.NET Memory Usage
For all developers that
use MKL under .NET
As every
.NET developer knows memory usage is managed from Garbage Collector. This layer determines
when memory is released and how to reorganize it. It allocates spaces for each
thread separately and avoid conflicts.
For this, we
programmers often don’t know exactly what really happen at this level, the
details.
In general,
this is enough, because GC has been built in order to permit developer to
concentrate at higher levels.
IntPtr x = new IntPtr(0);
double[] x_init = null;
x = mkl_malloc(sizeof(double) * n, 64);
Marshal.Copy(x_init, 0, x, n);
//use x pointer …
mkl_free(ref x);
This set of
instructions define a memory space for an array of double and assign a memory
pointer to x. This pointer x is then passed to a function like this:
[DllImport("mkl_rt.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true,
SetLastError = false)]
internal static extern int dtrnlspbc_init(
ref IntPtr handle,
ref int n,
ref int m,
IntPtr x,
IntPtr LW,
IntPtr UP,
double[] eps,
ref int iter1,
ref int iter2,
ref double rs
);
Everything
seems to work, but this is a very subtle felling!
Yes,
because memory is in the heap area managed by GC and can be moved, reorganized.
This means that your pointer x is not reliable.
We spend a
lot of time to fight against strange results, sometimes good, sometimes not.
Where was the trick? Was Intel fault of our fault? I don’t like this word “fault”,
but the question was where the issue?
At the end,
we got the solution!
This was: Pin
the pointer with the correct syntax and methods.
GCHandle x_handle = GCHandle.Alloc(x_init, GCHandleType.Pinned);
x = x_handle.AddrOfPinnedObject();
//use x pointer …
x_handle.Free();
Now GC can’t
move the pointer and the array used by API function is always located.
I hope these
notes useful for poor developer always alone in the ocean of troubles.
Part 1 | Part 2 | Part 3 | Part 4
Thank you for this example. It has been very useful. Using it I have been able to call DFTi and confirmed correct output for the 1-D case.
ReplyDeleteUnfortunately I have been unable to understand how to do so for the 2-D and N-D cases.
Do you have examples for the 2-D case?
I think I need something like this:
status = DftiCreateDescriptor(ref des_handle, (int)DFTI_CONFIG_VALUE.DFTI_DOUBLE, (int)DFTI_CONFIG_VALUE.DFTI_COMPLEX, 2, in_matrix.Length);
but i don't know how to pass the multiple dimension lengths of the in_matrix for the 2-D case.
Any comments or suggestions that you have would be appreciated!
Thanks again for this article.