Using Intel® MKL in your C# program

Introduction 

Some users have asked how to call and link the Intel® Math Kernel Library (Intel® MKL) functions from their C# programs. While the standard way of interfacing with third party software libraries from C# is well documented, some of the steps in interfacing with Intel MKL specifically may still be confusing. The attached source code package is intended to show how to navigate the whole process for Intel MKL users. These examples show how to create a custom DLL from Intel MKL libraries, call those functions from their C# source, and interface with that custom DLL.

Examples are provided for calling mkl from 5 intel MKL domains 
1. dgemm.cs - BLAS (CBLAS)
2. dgeev.cs - LAPACK
3. pardiso.cs - PARDISO direct sparse solver
4. dfti_d1.cs - DFTI (the FFT interface)
5. vddiv.cs - VML vector math library

Let's take the function "dgeev" as example, The function is a typical routine in the Linear Algebra PACKage (LAPACK). It computes the eigenvalues and left and reight eigenvectors of a general matrix. As LAPACK are Fortran interface, that means scalars are passed as references, and only Fortranstyle (column-major) matrices are allowed. Many LAPACK routines use work arrays. Some array arguments may be not referenced for certain condition.   The interface in C# is like below 

[SuppressUnmanagedCodeSecurity]
[DllImport("mkl.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void dgeev(ref char jobvl, ref char jobvr,
ref int n, [In, Out] double[] a, ref int lda,
[Out] double[] wr, [Out] double[] wi,
[Out] double[] vl, ref int ldvl, [Out] double[] vr, ref int ldvr,
[In, Out] double[] work, ref int lwork, ref int info);

In this LAPACK routine vr is not referenced if jobvr = 'N', and vl is not referenced if jobvl = 'N'. The 
user  can  pass  a "null"  value  in  the  case  unreferenced  arguments.  It  does  not  matter  for  automatic 
pinning but it may require additional efforts to check null values in case of passing arrays as pointers 
with fixed keyword within unsafe block. 

Building the Examples

Follow these steps to build the example programs:

  • unzip the contents of the attached zip file
  • Open a Microsoft Visual Studio command prompt or add the Microsoft.NET Framework to the PATH environment variable in another command prompt
  • Run the build script (makefile) using nmake
    Example:

          >"C:\Program Files (x86)\Intel_sw_development_tools\compilers_and_libraries\windows\mkl\bin\mklvars.bat" ia32
          >nmake ia32 

  • The makefile provides further explanation of the parameters in comments

This will create custom DLL mkl.dll, which include the used functions and several executables for each of the example programs.

Example files: Intel_MKL_C#_Examples.zip

Building the Examples with  Intel® MKL Single Dynamic Library

Dynamic interface libraries have been added since Intel MKL 10.3 for improving linkage from C#. It is not required to build a custom DLL. The Intel MKL library named mkl_rt.dll can be called directly from C# code. Below is an updated version of the examples. Follow the same steps and run the nmake command.

Example:  
>"
C:\Program Files (x86)\Intel_sw_development_tools\compilers_and_libraries\windows\mkl\bin\mklvars.bat" ia32
>n
make ia32 

Example files: Intel_MKL_C#_Examples_02.zip

Examples with Complex Data Types

The below examples are provided for calling complex data types  from 3 intel MKL domains 
1. cscal.cs - BLAS (CBLAS)
2. cgemm.cs - LAPACK
3. LAPACKE_zgesv.cs - C interface LAPACK function

There is an informative discussion in MKL Forum, please read the thread. It includes several issues:

1) System.Numerics Complex type

If you use System.Numerics Complex type, it corresponds to Z  type in MKL function : complex, double precision(64bit, 8 bytes)

for example, LAPACKE_zgesv, not LAPACKE_cgesv

2) Use the large Array >2G

2.1) .NET allow allocate large array since .NET 4.5, by set the gcAllowVeryLargeObjects = true into the config file.

2.2) when passing large array to native space, the default marshaling doesn't allow large array > 2Bb.  One workaround is to pin the array and pass a pointer to its first element to the native function with the fixed keyword:

using System.Numerics;
using System.Runtime.InteropServices;

[SuppressUnmanagedCodeSecurity]
 internal sealed unsafe class CNative
 {
  private CNative() {}

 /**  native LAPACKE_zgesv declaration */
    [DllImport("mkl_rt.dll", CallingConvention=CallingConvention.Cdecl,
      ExactSpelling=true, SetLastError=false)]
    internal static extern int LAPACKE_zgesv(
    int matrix_layout, 
    int n,
    int nrhs,
    Complex* A,
    int lda,
    int[] ipiv,
    Complex* B,
    int ldb
    );
   }

public unsafe sealed class LAPACK
 {
/** LAPACKE_zgesv wrapper */
  public static int zgesv(int matrix_layout, int n, int nrhs,
   Complex[] A, int lda, int[] ipiv,
   Complex[] B, int ldb)
  {
      fixed (Complex* pA = &A[0])
      fixed (Complex* pB = &B[0])
      // fixed (int* pipiv = &ipiv[0])
   return CNative.LAPACKE_zgesv(matrix_layout, n, nrhs, pA, lda,
      ipiv, pB, ldb);
  }
For more complete information about compiler optimizations, see our Optimization Notice.

26 comments

Top
anonymous's picture

Hi,
I am using eigen values/vectors decomposition DSYEV in mkl for a university project and I need results to be reproductible.
I wrote a little wrapper (according to examples) to call DSYEV from C# :

[code=c-sharp]
namespace Front_toolbox_v2
{
class Solve
{
public double[,] decompo(double[,] A)
{
int lwork = -1;
int n = A.GetLength(0);
int lda = n;

double[] A_bis = new double[n * n];
double[] w = new double[n];
for (int i = 0; i < n; i++)
{
int cte = i * n;
for (int j = 0; j < n; j++)
{
A_bis[cte + j] = A[j, i];
}
}

lwork = -1;
double[] work_1 = new double[1];
int info = LAPACK_mkl.dsyev('V', 'U', n, A_bis, lda, w, work_1, lwork);
lwork = (int)work_1[0];
double[] work = new double[lwork];
info = LAPACK_mkl.dsyev('V', 'U', n, A_bis, lda, w, work, lwork);

double[,] res2 = new double[n, n + 1];
for (int i = 0; i < n; i++)
{
res2[i, 0] = w[i];
for (int j = 0; j < n; j++)
{
res2[i, j + 1] = A_bis[i + j * n];
}
}
GC.Collect(0);
return res2;
}
}
}

namespace mkl
{
public sealed class LAPACK_mkl
{
private LAPACK_mkl() { }

public static int dsyev(char jobz, char uplo, int N, double[] A, int LDA, double[] w, double[] work, int lwork)
{
LAPACKNative.kmp_set_warnings_off();
int num = Environment.ProcessorCount;
LAPACKNative.omp_set_num_threads(ref num);

int info = -1;
LAPACKNative.dsyev(ref jobz, ref uplo, ref N, A, ref LDA, w, work, ref lwork, ref info);
return info;
}
}

/** LAPACK native declarations */
[SuppressUnmanagedCodeSecurity]
internal sealed class LAPACKNative
{

[DllImport("libiomp5md", EntryPoint = "omp_set_num_threads")]
internal static extern void omp_set_num_threads(ref int num);

[DllImport("libiomp5md", EntryPoint = "kmp_set_warnings_off")]
internal static extern void kmp_set_warnings_off();

[DllImport("mkl", EntryPoint = "DSYEV", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
internal static extern void dsyev(ref char jobz, ref char uplo, ref int n, double[] A, ref int lda, double[] w, double[] work, ref int lwork, ref int info);

private LAPACKNative()
{
kmp_set_warnings_off();
int num = Environment.ProcessorCount;
omp_set_num_threads(ref num);
}
}
}
[/code]

I red something about memory alignment and 16-byte boundaries... does this apply here ?
Thank you for any answer or comment on my code

Janene Pappas-mccrillis's picture

I'm attempting to run the examples on my machine, Windows-7 VS 2010. I need to eventually integrate a good FFT library into my product and this one was recommended, but I can't get the examples to run. I've set up nmake, added paths of the MKL redistributable to my main path environment variable, etc.

The makefile execution fails:

C:projectsMKL Examples>nmake ia32 mklredist="C:Program Files (x86)IntelComposerXE-2011redist"

Microsoft (R) Program Maintenance Utility Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.

Add path of the MKL redistributable to the path environment variable
set path=%MKLREDIST%ia32mkl;%MKLREDIST%ia32compiler;%path%
Build and run examples
nmake /a dgemm.exe dgeev.exe dfti_d1.exe pardiso.exe vddiv.exe

Microsoft (R) Program Maintenance Utility Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.

Compile dgemm.cs
csc .dgemm.cs
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.

Run dgemm example
dgemm.exe
MKL cblas_dgemm example

alpha=1
beta=-1
Matrix A
1 2 3
4 5 6
Matrix B
0 1 0 1
1 0 0 1
1 0 1 0
Initial C
5 1 3 3
11 4 6 9
MKL FATAL ERROR: Cannot load mkl_intel_thread.dll
NMAKE : fatal error U1077: '.dgemm.exe' : return code '0x1'
Stop.
NMAKE : fatal error U1077: '"C:Program Files (x86)Microsoft Visual Studio 10.0VCBINnmake.EXE"' : return code '0x2'
Stop.

I am totally unable to add references to the MKL DLL's in VS2010. The standard "Add Reference" simply ignores my attempt.

How does one use this library with a C# project?

Janene

fritzfranz's picture

I downloaded MKL for evaluation, and I also downloaded the examples above.
The source code is pretty clear - but I do NOT manage to properly set up the links from the C# project to the MKL DLLs

Using the Visual studio command for project links, I can find the DLLs, but setting up links is not accepted.

What is the nature of the DLLs? COM or .NET?
Is there anything else I have to do to set up the links ??

The makefile was not helpful at all, I have a Windows 7 64-bit computer, and I can not find nmake on my machine ....

shachris23's picture

Just a feedback that as Mono platform grows, it would be real nice if MKL supports that platform. Thanks!!

anonymous's picture

only for this version:
nmake ia32 MKLROOT="C:ProgramFileIntelCompile11.1.51mkl"
and i need to coy libiomp5md.dll & libiomp5md.lib to de folder IntelCompiler11.151mklia32lib

Vladimir Koldakov (Intel)'s picture

Hi,
We do not support Mono at the moment.
I believe it will work if you build custom dynamic library (<mkl_root>/tools/builder) and call it via P/Invoke.
Thanks,
Vladimir

shachris23's picture

I have a C# program running on Mono/Linux platform. Does Intel MKL Linux version allow me to integrate the MKL into the Mono implementation as well? If so, is the instruction pretty similar?

Thanks.

anonymous's picture

If I had a C# program running on mono/linux, can I use the MKL Linux version with my program since this solution is relying on a DLL?

Vladimir Koldakov (Intel)'s picture

Hi, Jo.
I've checked on an 8 core Xeon - it is ok with MKL_NUM_THREADS=2 or 4 or (default) 8.
I used the makefile attached to the examples to build custom dll and run example with N=9000, K=8000, M=6000.
Could you please provide more details how do you build dll? And a small test if it is possible.
Thanks,
Vladimir

Jo Cotterell's picture

Hi MKL gurus,

We have successfully linked a C# program to MKL thanks to your examples, but a problem remain: It seems that MKL can't span multiple threads when being called from our managed environment. When calling cblas_dgemm from a freshly built DLL, the linkage is successfully done (pinning, ...) and the Matrix-Matrix multiplication is processed, but on an Intel Xeon 5130, we attained only 25% of CPU Usage, even after setting some environment variables (MKL_DYNAMIC=FALSE, MKL_NUM_THREADS=x) which seemed to have no impact on this issue...

Of course we were expecting some overhead coming from the C#->C transition, but such a behavior seems strange. Is it expected or have we gone wrong on something? Does C# constrain the use of unmanaged code to only one thread?

Best Regards.

Pages

Add a Comment

Have a technical question? Visit our forums. Have site or software product issues? Contact support.