Intel MKL Error: Parameter 9 was incorrect on entry to cblas_zgemm (C# Linux)
Intel MKL Error: Parameter 9 was incorrect on entry to cblas_zgemm (C# Linux)
我使用以下命令构建了一个 custom MKL library (2019 Update 2) for Windows (10) and 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 上失败(进入 cblas_zgemm 时参数 9 不正确)。
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(单声道)上失败,参数 9 在进入 cblas_zgemm 或空引用时不正确。
- 如果我用
cblas_dgemm
和 double
重复实验,它在 Windows 和 Linux 上有效。
仔细看看 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);
表明参数 alpha
和 beta
必须通过引用传递。所以 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);
参数 alpha
和 beta
是按值传递的。
[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 上工作一样。我仍然不明白为什么它在 Windows 上使用 ref
?
我使用以下命令构建了一个 custom MKL library (2019 Update 2) for Windows (10) and 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 上失败(进入 cblas_zgemm 时参数 9 不正确)。
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(单声道)上失败,参数 9 在进入 cblas_zgemm 或空引用时不正确。
- 如果我用
cblas_dgemm
和double
重复实验,它在 Windows 和 Linux 上有效。
仔细看看 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);
表明参数 alpha
和 beta
必须通过引用传递。所以 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);
参数 alpha
和 beta
是按值传递的。
[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 上工作一样。我仍然不明白为什么它在 Windows 上使用 ref
?