我的程序是用C ++编写的,我使用Eigen库进行矩阵运算。里面有一个巨大的矩阵产品,尺寸为50000 * 1000和1000 * 50000。所以我试图从MKL库中调用BLAS函数来提高性能。然后在调用dgemm函数时出现分段错误。
这是代码
double alpha = 1, beta = 0;
double *s1;
MKL_INT mm1 = q, nn1 = q, kk1 = ncol1;
s1 = (double *)malloc(q*q*sizeof(double));
cout << 14 << endl;
cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans,mm1, nn1, kk1, alpha, V.data(), mm1, A01.data(), kk1, beta, s1, mm1);
代码适用于小维度。我用以下代码编译代码:
icpc lapack.cpp generators.cpp SimpleRNG.cpp example.cpp -lmkl_intel_ilp64 -lmkl_sequential -lmkl_core -lpthread -lm -DMKL_ILP64 -o new_example.o
或
icpc lapack.cpp generators.cpp SimpleRNG.cpp example.cpp -lmkl_intel_lp64 -lmkl_sequential -lmkl_core -lpthread -lm -o new_example.o
即:我尝试了LP64接口和ILP64接口,但它们都不起作用,有人可以帮助我吗?我在Linux服务器上运行程序并且有足够的内存。
非常感谢!
答案 0 :(得分:1)
以下讨论假定:
sizeof(double) == 8
MKL_INT
为int
,sizeof(int) == 4
sizeof(std::size_t) == 8
CHAR_BIT == 8
在典型的64位系统中应该如此。
这一行非常有趣:
s1 = (double *)malloc(q*q*sizeof(double));
如果q
为50000
,则q*q
为2500000000
。如果q
为int
,则会导致有符号整数溢出,从而导致未定义的行为。在这种特殊情况下,编译器可能只是简单地回绕(有效地减去2 32 ),从而产生-1794967296
。
然而,当您将-1794967296
与sizeof(double)
(类型为std::size_t
,即无符号整数类型)相乘时,会发生有趣的事情。如果size_t
是64位,那么编译器需要将-1794967296
转换为无符号的64位数,并且这种转换在概念上通过向数字添加2 64 来实现,给你18446744071914584320
。当你将它乘以sizeof(double)
时,它会再次溢出,但是无符号溢出是明确定义的,并且为64位操作数返回模2 64 的结果,因此最终结果是{{ 1}}。 (有关计算,请参阅此处demo。)
因此,您的原始代码最终会尝试分配18446744059349813248
字节的内存(这几乎是16 exabytes )。哎哟。显然,分配将失败并返回空指针。由于您没有检查返回值,因此稍后会出现分段错误。
当您将其重写为
时18446744059349813248
然后首先评估s1 = (double *)malloc(sizeof(double) * q * q);
。此乘法会将sizeof(double) * q
转换为q
,但由于std::size_t
为正,转换不会影响其值。因此,结果是明确定义的,并且是q
,其值为std::size_t
。第二次乘法同样定义明确 - 400000
再次转换为q
,结果乘法产生std::size_t
,不会溢出20000000000
,所以你的{ {1}}调用实际上要求20GB的内存。