LAPACK / BLAS与简单的“for”循环

时间:2011-02-21 03:14:09

标签: c++ c lapack blas performance

我想将一段涉及大量向量和矩阵计算的代码迁移到C或C ++,目的是尽可能地加速代码。

C代码中的for循环的线性代数计算与使用LAPACK / BLAS的计算一样快,或者使用这些库有一些独特的加速?

换句话说,简单的C代码(使用for循环等)可以像使用LAPACK / BLAS的代码一样快地执行线性代数计算吗?

4 个答案:

答案 0 :(得分:16)

供应商提供的LAPACK / BLAS库(英特尔的IPP / MKL已被提及,但也有AMD的ACML,其他CPU供应商,如IBM / Power或Oracle / SPARC也提供等价物)通常针对特定的CPU能力进行了高度优化这将大大提高大型数据集的性能。

但是,通常情况下,您可以使用非常特定的小数据进行操作(例如,4x4矩阵或4D点积,即3D几何处理中使用的操作)以及这类事物, BLAS / LAPACK是过度的,因为这些子程序的初始测试选择了代码路径,具体取决于数据集的属性。在这些情况下,简单的C / C ++源代码,可能使用SSE2 ... 4内在函数和/或编译器生成的矢量化,可能会击败BLAS / LAPACK。
这就是为什么,例如,英特尔有两个库 - 用于大型线性代数数据集的MKL,以及用于小型(图形向量)数据集的IPP。

从这个意义上说,

  • 您的数据集究竟是什么?
  • 什么矩阵/矢量大小?
  • 什么是线性代数运算?

另外,关于“simple for loops”:给编译器提供向量化的机会。即类似的东西:

for (i = 0; i < DIM_OF_MY_VECTOR; i += 4) {
    vecmul[i] = src1[i] * src2[i];
    vecmul[i+1] = src1[i+1] * src2[i+1];
    vecmul[i+2] = src1[i+2] * src2[i+2];
    vecmul[i+3] = src1[i+3] * src2[i+3];
}
for (i = 0; i < DIM_OF_MY_VECTOR; i += 4)
    dotprod += vecmul[i] + vecmul[i+1] + vecmul[i+2] + vecmul[i+3];
对于矢量化编译器,

可能比普通的

更好
for (i = 0; i < DIM_OF_MY_VECTOR; i++) dotprod += src1[i]*src2[i];

表达。在某些方面,使用for循环计算的意思将产生重大影响 如果您的矢量尺寸足够大,那么BLAS版本

dotprod = CBLAS.ddot(DIM_OF_MY_VECTOR, src1, 1, src2, 1);

将是更清晰的代码,可能更快。

在参考方面,这些可能是有意义的:

答案 1 :(得分:7)

可能不是。人们在确保lapack / BLAS例程得到优化和数值稳定方面做了大量工作。虽然代码通常有点复杂,但通常这种方式是有原因的。

根据您的预期目标,您可能需要查看英特尔Math Kernel Library。至少如果您的目标是英特尔处理器,它可能是您要找到的最快的。

答案 2 :(得分:4)

数值分析很难。至少,您需要非常了解浮点运算的局限性,并知道如何对运算进行排序,以便平衡速度和数值稳定性。这不重要。

你需要对你实际需要的速度和稳定性之间的平衡有一些线索。在更一般的软件开发中,过早优化是万恶之源。在数值分析中,它是游戏的名称。如果你第一次没有得到正确的平衡,你将不得不重新写下所有的余额。

当你尝试将线性代数证明适应算法时,它会变得更难。你需要真正理解代数,这样你才能将它重构成一个稳定的(或足够稳定的)算法。

如果我是你,我会定位LAPACK / BLAS API并四处寻找适合您数据集的库。

您有很多选择:LAPACK / BLAS,GSL和其他自我优化库,供应商库。

答案 3 :(得分:0)

我不太满足这个库。但你应该考虑到库通常会在参数中进行一些测试,它们对错误有一个“通信系统”,甚至在调用函数时归因于新变量...如果计算是微不足道的,也许你可以尝试自己做,适应你的必需品......