我正在寻找使用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();
我可以使用更快的数据结构吗?还是有更快的方法来执行这些基本操作?
答案 0 :(得分:2)
正如您在评论中指出的那样,添加-fno-math-errno
编译器标志可以大大提高速度。至于发生这种情况的原因,您的代码片段显示您正在通过sqrt
执行distance_norm = distance.norm();
。
这使得编译器不会在每个ERRNO
之后设置sqrt
(这是对线程局部变量的保存写入),这更快 和 启用重复执行此操作的任何循环的矢量化。唯一的缺点是失去了IEEE遵循性。参见gcc man。
您可能想尝试的另一件事是添加-march=native
并添加-mfma
,如果-march=native
不能为您打开它(我似乎记得在某些情况下不是) t由native
打开,必须手动打开-check here for details)。与Eigen一样,您可以使用-DNDEBUG
禁用边界检查。
SoA而不是AoS !!!如果性能实际上是一个真正的问题,请考虑使用单个4xN矩阵存储位置(并让Atom
保留列索引而不是Eigen::Vector3d
)。在您显示的小代码片段中,这没什么大不了的,但是取决于您其余的代码,可能会给您带来另一个性能上的巨大提高。
答案 1 :(得分:0)
鉴于您的速度是4倍,可能值得检查一下在编译时是否启用了矢量化功能,例如AVX或AVX2。处理双打时,当然也有SSE2(〜2x)和AVX512(〜8x)。
答案 2 :(得分:0)
要么尝试使用其他编译器,例如Intel C ++编译器(免费用于学术和非营利性活动),要么使用其他库(例如Intel MKL)(比您自己的代码快得多),甚至使用其他BLAS / LAPACK实现来处理密集矩阵或PARDISO或SuperLU (不确定是否仍然存在)用于稀疏矩阵。