从特征算法调用Lapack函数时的分段错误

时间:2014-08-09 08:09:25

标签: c++ segmentation-fault eigen lapack blas

我的程序是用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服务器上运行程序并且有足够的内存。

非常感谢!

1 个答案:

答案 0 :(得分:1)

以下讨论假定:

  • sizeof(double) == 8
  • MKL_INTintsizeof(int) == 4
  • sizeof(std::size_t) == 8
  • CHAR_BIT == 8

在典型的64位系统中应该如此。

这一行非常有趣:

s1 = (double *)malloc(q*q*sizeof(double));

如果q50000,则q*q2500000000。如果qint,则会导致有符号整数溢出,从而导致未定义的行为。在这种特殊情况下,编译器可能只是简单地回绕(有效地减去2 32 ),从而产生-1794967296

然而,当您将-1794967296sizeof(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的内存。