Intel® oneAPI Math Kernel Library
Ask questions and share information with other developers who use Intel® Math Kernel Library.
6977 Discussions

Making use of MKL GMP in a C# environment - how to define classes / structs?

fritzfranz
Beginner
836 Views
Here is the next question regarding C# access:

When I want to use GMP functions, the names used in the documentation like "mpz_fdiv_qr" do not seem to work
looking at the mkl_core.dll, I see names likemkl_gmp___gmpz_fdiv_qr, and with these names I can build a custom library.

Now the next problem shows up: how to map data structures, like "mpz_t" to a C# environment?
There isa pretty large amount of GMP examples for C in the "examples" subdirectory, but this does not really help me to map the structures to C#.

The frequently mentioned article "Using Intel MKL in your C# program" does not explain that either.

Please provide some hints how to map the needed structs to C#

Thanks - Franz
0 Kudos
10 Replies
Vladimir_Koldakov__I
New Contributor III
836 Views

Hello, Franz,

You can find an example of the C# structure for the corresponding MKL VML C structure in the article. You can find this structure also in the vddiv.cs MKL C# example:

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]

public struct VmlErrorContext

{

public int iCode; /* Error status value */

public int iIndex; /* Index for bad array element,

* or bad array dimension,

* or bad array pointer */

public double dbA1; /* Error argument 1 */

public double dbA2; /* Error argument 2 */

public double dbR1; /* Error result 1 */

public double dbR2; /* Error result 2 */

[MarshalAs(UnmanagedType.ByValTStr,SizeConst=64)]

public String cFuncName; /* Function name */

int iFuncNameLen; /* Length of functionname*/

}

The structure mpz_t includes pointer and size_t fields. C# provides platform-independent types IntPtr and UIntPtr to map such kind of C types. See the dfti_d1.cs MKL C# example.

You can find the full table of data type correspondence in any PInvoke tutorial. See for instance MSDN documentation.

WBR,

Vladimir

0 Kudos
fritzfranz
Beginner
836 Views
In the meantime I was able to do some elementary tests with MKL GMP, like assigning values to big integers and doing elementary operations like divisions.

However I am stuck with 2 problems:
1. I can not make the function mpz_get_str work. Whatever I try to marshal the string parameters, the program terminates with error codes which I do not find anywhere (no matter whether i run the program in the command line or in a VS environment.)The first parametr char* str is the problem. Reading multiple PInvoke tutorials and the relevant chapter of Donis Marshal's book on C# did not help me to find a workable solution.

Here is the function in question and a piece of its documentation:

- Function: char * mpz_get_str (char *str, int base, mpz_t op)

Convert op to a string of digits in base base. The base argument may vary from 2 to 62 or from 2 to 36.

For base in the range 2..36, digits and lower-case letters are used; for 2..36, digits and upper-case letters are used; for 37..62, digits, upper-case letters, and lower-case letters (in that significance order) are used.

If str is NULL, the result string is allocated using the current allocation function (see Custom Allocation). The block will be strlen(str)+1 bytes, that being exactly enough for the string and null-terminator.

Among other things I tried a marhalling like

[DllImport("mkl.dll", CallingConvention = CallingConvention.Cdecl,

ExactSpelling = true, SetLastError = true)]

[return: MarshalAs(UnmanagedType.LPStr)]

internal static extern

string mkl_gmp___gmpz_get_str(

[MarshalAs(UnmanagedType.LPStr)]

[In, Out] ref StringBuilder s,

[In] int bas,

[In] ref mpz_t inp);

[DllImport("mkl.dll", CallingConvention = CallingConvention.Cdecl,

ExactSpelling = true, SetLastError = true)]

[return: MarshalAs(UnmanagedType.LPStr)]

internal static extern

string mkl_gmp___gmpz_get_str(

[MarshalAs(UnmanagedType.LPStr)]

[In, Out] ref StringBuilder s,

[In] int bas,

[In] ref mpz_t inp);

This problem is a show stopper for me, it prevents me from getting back meaningful output from MKL GMP.

2. Working with Int64 integers does not function as expected.
There are no compile-time or runtime errors, but I can see viaset/get roundtrips that only the low 32 bits are used.Signatures see below.

/** GMPI native mpz_init_set_si declaration */
[DllImport("mkl.dll", CallingConvention = CallingConvention.Cdecl,
ExactSpelling = true, SetLastError = false)]
internal static extern void mkl_gmp___gmpz_init_set_si(
[In, Out]ref mpz_t big,
[In]Int64 n);

/** GMPI native mpz_get_si declaration */
[DllImport("mkl.dll", CallingConvention = CallingConvention.Cdecl,
ExactSpelling = true, SetLastError = true)]
internal static extern Int64 mkl_gmp___gmpz_get_si(
[In] ref mpz_t big);

Please provide hints how to solve this.
Thanks - Franz

0 Kudos
Vladimir_Koldakov__I
New Contributor III
836 Views

Hello Franz,

We are working on the issue. Now I see one general mistake in your code. The names with the prefix mkl_gmp are internal MKL names. Therefore you should not use them. You can find correct names in the mkl_gmp.h file. For instance, use __gmpz_get_str instead of mpz_get_str:

#define mpz_get_str __gmpz_get_str

Regards,

Vladimir

0 Kudos
fritzfranz
Beginner
836 Views
I don't think that the names are the issue.
I did the dumpbin /exports command for mkl_core.dll, and all the names for the integer functions work correctly, also the results are ok with the exception of the ...get_str function (see above).
I will soon report another issue with the ...get_si function which does not seem to report the correct sign.
With the ...get_str issue, I could not make any progess and still need your help.
0 Kudos
Vladimir_Koldakov__I
New Contributor III
836 Views

Hello Franz,

Generally external and internal MKL functions have different set of arguments.

I know the problem and I'm trying to find a solution.

Thanks,

Vladimir

0 Kudos
Vladimir_Koldakov__I
New Contributor III
836 Views
Hello Franz,
The code belowworks:


using System;

using System.Security;

using System.Runtime.InteropServices;

using mkl;


public class test_str
{
private test_str() {}
public static void Main(string[] args) {
String str_in = "18446744073709551616";
String str_out = " ";
STR.mpz_t rop = new STR.mpz_t();
STR.mpz_init ( ref rop );

STR.mpz_set_str ( ref rop, str_in, 10);
String ss = STR.mpz_get_str ( str_out, 10, ref rop );
Console.WriteLine(ss);
}
}

namespace mkl

{

public sealed class STR

{

private STR() {}

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]

public struct mpz_t

{

public int _mp_alloc; /* number of limbs allocated by the library in a native way */

public UIntPtr _mp_size; /* sign of this field indicates the sign of the big number */

/* the absolute value is the number of limbs in the big number */

public IntPtr _mp_d; /* points to limbs allocated for the big number */

}

public static void mpz_init(ref mpz_t integer)

{

STRNative.__gmpz_init (ref integer);

}

public static void mpz_set_str(ref mpz_t rop, String str, int base_)

{

STRNative.__gmpz_set_str (ref rop, str, base_);

}

public static String mpz_get_str(String s, int bas, ref mpz_t inp)

{

return STRNative.__gmpz_get_str(s, bas, ref inp);

}

}

[SuppressUnmanagedCodeSecurity]

internal sealed class STRNative

{

private STRNative() {}

[DllImport("mkl.dll", CallingConvention = CallingConvention.Cdecl)]

internal static extern

void __gmpz_init ([In, Out] ref STR.mpz_t integer);

[DllImport("mkl.dll", CallingConvention = CallingConvention.Cdecl)]

internal static extern

int __gmpz_set_str (ref STR.mpz_t rop, [MarshalAs(UnmanagedType.LPStr)] [In] String str, int base_);

[DllImport("mkl.dll", CallingConvention = CallingConvention.Cdecl)]

[return: MarshalAs(UnmanagedType.LPStr)]

internal static extern

string __gmpz_get_str([MarshalAs(UnmanagedType.LPStr)] [In, Out] String s,

[In] int bas,

[In] ref STR.mpz_t inp);

}

}

Add three functions to build custom dll:

__gmpz_get_str
__gmpz_init
__gmpz_set_str

Regards,
Vladimir

0 Kudos
fritzfranz
Beginner
836 Views

Unfortunately this does NOT solve the problem on my side.
There must be a difference somewhere (maybe due to Windows 7 and the 64 bit environment ...)
Below I posted my summary, and I sent some more information via a separate channel.

With the Visual Studio debugger, I get the following additional information:

Das Programm "[6560] MKL_Cons2.vshost.exe: Verwaltet" wurde mit Code -1073740940 (0xc0000374) beendet.

Looking for information regarding the return code 0xc0000374, I found a huge number of forum entries most of which did not tell me anything.

I searched MSDN and found the following link:

http://blogs.msdn.com/b/jiangyue/archive/2010/03/16/windows-heap-overrun-monitoring.aspx

To me, this seems to get closer to the problem. There must be a problem with the string handling somewhere between C# and the native environment which leads to the heap corruption. But I do not have the means to really find the root cause of the problem.

I believe that somebody needs to have a detailed look at the implementation of the get_str function in MKL .

0 Kudos
Gennady_F_Intel
Moderator
836 Views
Franz,that's not good idea to use undocumented names of routines like "mkl_gmp___gmpz_get_str" you did.
We have never tested mkl's funtionality by this way. Please use all declaration from gmp.h.
0 Kudos
fritzfranz
Beginner
836 Views
I changed all the names to __gmpz_***, but this does NOT make a difference for the reported problem.
I still have the situation that the program terminates with0xc0000374 as soon as I call get_str with exactly the code as suggested in this thread. So there MUST be another problem.
0 Kudos
Vladimir_Koldakov__I
New Contributor III
836 Views

Hello Franz,

Please try to use the following idea:

public static String mpz_get_str(String s, int bas, ref mpz_t inp)

{

String m_str = "...........This is manged string................";

// convert managed string to ANSI and copy it into unmanaged memory

IntPtr u_str = Marshal.StringToHGlobalAnsi(m_str);

IntPtr u_ret = __gmpz_get_str(u_str, bas, ref inp);

// convert string back

String m_ret = Marshal.PtrToStringAnsi(u_ret);

// release unmanaged memory

Marshal.FreeHGlobal(u_str);

return m_ret;

}

[DllImport("mkl.dll", CallingConvention = CallingConvention.Cdecl)]

internal static extern IntPtr __gmpz_get_str(IntPtr s, [In] int bas, [In] ref STR.mpz_t inp);

It works directly with the unmanaged memory, so do not forgetto reserve enough room to keep the requested string and to free memory manually.

Regards,

Vladimir

0 Kudos
Reply