英特尔MKL错误:在输入cblas_zgemm(C#Linux)时参数9不正确

时间:2019-03-06 14:12:25

标签: c# linux cross-platform dllimport intel-mkl

我已经使用以下命令构建了custom MKL library (2019 Update 2) for Windows(10)和Linux(Ubuntu 18.04):

nmake libintel64 MKLROOT="C:\Program Files (x86)\IntelSWTools\compilers_and_libraries\windows\mkl" name=win\intel64\custom_mkl interface="lp64"

make libintel64 MKLROOT="opt/intel/mkl" name=linux/intel64/custom_mkl interface=lp64

我正在使用C#中的DllImport来呼叫cblas_zgemm

[DllImport(DLLName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, SetLastError = false)]
internal static extern void cblas_zgemm(
    int Order, int TransA, int TransB, int M, int N, int K,
    ComplexDouble alpha, [In] ComplexDouble[,] A, int lda, [In] ComplexDouble[,] B, int ldb,
    ComplexDouble beta, [In, Out] ComplexDouble[,] C, int ldc);

请参阅https://software.intel.com/en-us/mkl-developer-reference-c-cblas-gemm

其中ComplexDouble定义为:

public struct ComplexDouble
{
    public double real;
    public double imag;

    public static implicit operator ComplexDouble(double d)
    {
        return new ComplexDouble() { real = d };
    }
}

我为矩阵乘法定义了以下静态方法:

public static ComplexDouble[,] Dot(ComplexDouble[,] a, ComplexDouble[,] b)
{
    int n1 = a.GetLength(0);
    int n2 = a.GetLength(1);
    int n3 = b.GetLength(0);
    int n4 = b.GetLength(1);
    if (n2 != n3) throw new System.Exception("Inner matrix dimensions must agree");
    int Order = 101; // row-major arrays
    int TransA = 111; // trans='N'
    int TransB = 111; // trans='N'
    int M = n1, N = n4, K = n2;
    int lda = K, ldb = N, ldc = N;
    ComplexDouble alpha = 1, beta = 0;
    ComplexDouble[,] c = new ComplexDouble[n1, n4];
    _mkl.cblas_zgemm(Order, TransA, TransB, M, N, K, alpha, a, lda, b, ldb, beta, c, ldc);
    return c;
}

最后,我得到了以下测试代码,这些代码在Windows下可以正常运行,但在Linux上则失败(参数9输入cblas_zgemm时不正确)。

ComplexDouble[,] A = new ComplexDouble[,] { { 1, 2, 3 }, { 4, 5, 6 } };
ComplexDouble[,] B = new ComplexDouble[,] { { 0, 1, 0, 1 }, { 1, 0, 0, 1 }, { 1, 0, 1, 0 } };
ComplexDouble[,] C = MKL.Dot(A, B);

我做了以下观察:

  • 它在Windows上可以使用
  • 在Linux(Mono)上失败,其参数9输入cblas_zgemm或Null引用时不正确。
  • 如果我重复使用cblas_dgemmdouble进行实验,那么它可以在Windows和Linux上运行。

1 个答案:

答案 0 :(得分:0)

仔细研究cblas_zgemm

void cblas_zgemm (
    const CBLAS_LAYOUT Layout, const CBLAS_TRANSPOSE transa, const CBLAS_TRANSPOSE transb, const MKL_INT m, const MKL_INT n, const MKL_INT k, 
    const void *alpha, const void *a, const MKL_INT lda, const void *b, const MKL_INT ldb, 
    const void *beta, void *c, const MKL_INT ldc);

显示参数alphabeta必须通过引用传递。因此DllImport必须看起来像这样:

[DllImport(DLLName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, SetLastError = false)]
internal static extern void cblas_zgemm(
    int Order, int TransA, int TransB, int M, int N, int K,
    ref ComplexDouble alpha, [In] ComplexDouble[,] A, int lda, [In] ComplexDouble[,] B, int ldb,
    ref ComplexDouble beta, [In, Out] ComplexDouble[,] C, int ldc);

我不知所措,因为cblas_dgemm

void cblas_dgemm (
    const CBLAS_LAYOUT Layout, const CBLAS_TRANSPOSE transa, const CBLAS_TRANSPOSE transb, const MKL_INT m, const MKL_INT n, const MKL_INT k, 
    const double alpha, const double *a, const MKL_INT lda, const double *b, const MKL_INT ldb, 
    const double beta, double *c, const MKL_INT ldc);

参数alphabeta通过值传递。

[DllImport(DLLName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, SetLastError = false)]
internal static extern void cblas_dgemm(
    int Order, int TransA, int TransB, int M, int N, int K,
    double alpha, [In] double[,] A, int lda, [In] double[,] B, int ldb,
    double beta, [In, Out] double[,] C, int ldc);

就像cblas_zgemm在Windows和Linux上一样。我仍然不明白为什么它可以在ref的Windows上运行?