8

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

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

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

4

4 回答 4

17

供应商提供的 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。

从这个意义上说,

  • 你的数据集到底是什么?
  • 什么矩阵/向量大小?
  • 什么线性代数运算?

此外,关于“简单的 for 循环”:让编译器有机会为您进行矢量化。即类似的东西:

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);

将是更干净的代码并且可能更快。

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

于 2011-02-21T11:02:38.407 回答
7

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

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

于 2011-02-21T03:27:16.437 回答
4

数值分析很难。至少,您需要清楚地了解浮点运算的局限性,并知道如何对运算进行排序,以便在速度和数值稳定性之间取得平衡。这是不平凡的。

您实际上需要对您实际需要的速度和稳定性之间的平衡有所了解。在更一般的软件开发中,过早的优化是万恶之源。在数值分析中,它是游戏的名称。如果你第一次没有得到平衡,你将不得不或多或少地重新编写所有内容。

当您尝试将线性代数证明应用于算法时,它会变得更加困难。您需要真正了解代数,以便将其重构为稳定(或足够稳定)的算法。

如果我是你,我会以 LAPACK/BLAS API 为目标,并四处寻找适用于你的数据集的库。

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

于 2012-07-29T16:08:59.690 回答
0

我不太了解这个图书馆。但是您应该考虑到库通常会在参数中进行一些测试,它们对错误具有“通信系统”,甚至在您调用函数时会归因于新变量……如果计算很简单,也许您可​​以尝试自己做,适应你的需要......

于 2011-02-21T03:30:02.350 回答