【问题标题】:Basic ways to speed up a simple Eigen program加速简单 Eigen 程序的基本方法
【发布时间】:2019-10-26 02:29:09
【问题描述】:

我正在寻找使用 Eigen 进行简单操作的最快方法。有这么多可用的数据结构,很难说哪个是最快的。

我尝试过预定义我的数据结构,但即便如此,我的代码仍被类似的 Fortran 代码所超越。我猜 Eigen::Vector3d 是满足我需求的最快的,(因为它是预定义的),但我很容易出错。在编译期间使用 -O3 优化给了我很大的提升,但我的运行速度仍然比相同代码的 Fortran 实现慢 4 倍。

我使用“原子”结构,然后将其存储在由以下定义的“原子”向量中:

struct Atom {
    std::string element;
    //double x, y, z;
    Eigen::Vector3d coordinate;
};
std::vector<Atom> atoms;

我的代码中最慢的部分如下:

distance = atoms[i].coordinate - atoms[j].coordinate;
distance_norm = distance.norm();

我可以使用更快的数据结构吗?或者有没有更快的方法来执行这些基本操作?

【问题讨论】:

  • 您可以尝试使用-ffast-math 进行编译(如果您使用的是 gcc 或 clang)。您可以从#include &lt;unsupported/Eigen/AlignedVector3&gt; 尝试Eigen::AlignedVector3&lt;double&gt;。还要确保使用-DNDEBUG 进行编译(一旦您验证您的代码工作正常)。但是要回答“最快”是什么,需要更多的上下文。
  • -ffast-math 让我的速度比 -O3 快 40 倍!
  • 有趣的是,我单独使用 -fno-math-errno 选项(只是 --fast-math 启用的几个选项之一)获得了 40 倍的加速。
  • 对于像我这样的其他 c++ 新手。通过删除对“pow”的调用,我得到了数量级的加速。例如pow(x,2) --> x_2 = x*x, pow(x,6) = x_2*x_2*x_2

标签: c++ eigen


【解决方案1】:

正如您在评论中指出的那样,添加 -fno-math-errno 编译器标志可以显着提高速度。至于为什么会发生这种情况,您的代码被截断表明您正在通过distance_norm = distance.norm(); 执行sqrt

这使得编译器不会在每个sqrt 之后设置ERRNO(这是对线程局部变量的保存写入),这样更快并且可以实现向量化任何重复执行此操作的循环。唯一的缺点是失去了对 IEEE 的遵守。见gcc man

您可能想尝试的另一件事是添加-march=native 并添加-mfma 如果-march=native 没有为您打开它(我似乎记得在某些情况下它不是由@987654332 打开的@ 并且必须手动打开 - check here for details)。与 Eigen 一样,您可以使用 -DNDEBUG 禁用边界检查。

SoA 而不是 AoS!!!如果性能实际上是一个真正的问题,请考虑使用单个 4xN 矩阵来存储位置(并让Atom 保留列索引而不是Eigen::Vector3d)。在您展示的小代码 sn-p 中应该没有太大关系,但根据您的其余代码,可能会给您带来另一个巨大的性能提升。

【讨论】:

【解决方案2】:

考虑到您有大约 4 倍的折扣,可能值得检查您是否在编译时启用了 AVX 或 AVX2 等矢量化。处理双打时当然还有 SSE2 (~2x) 和 AVX512 (~8x)。

【讨论】:

    【解决方案3】:

    要么尝试其他编译器,例如英特尔 C++ 编译器(免费供学术和非营利用途使用),要么使用其他库,例如英特尔 MKL(比您自己的代码快得多),甚至使用其他 BLAS/LAPACK 实现密集矩阵或 PARDISO 或 SuperLU (不确定是否仍然存在)用于稀疏矩阵。

    【讨论】:

      猜你喜欢
      • 2012-01-25
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 2014-01-27
      • 2012-06-10
      • 2011-03-04
      • 1970-01-01
      • 2011-08-11
      相关资源
      最近更新 更多