在展开的链表上运行大约需要40%的代码运行时间——有什么明显的方法可以优化它吗
Running over an unrolled linked list takes around 40% of the code runtime - are there any obvious ways to optimise it?
我是一个名为吸血鬼(http://github.com/richard-evans/vampire),而计算密集型意味着代码性能的任何改进都可以显著增加可以进行的研究数量。此代码的典型运行时间可能长达数百个核心小时,因此我一直在寻找改进代码中性能关键部分的方法。然而,我有点拘泥于以下看起来相对无害的代码,它大约占运行时的40%:
for (int atom = start_index; atom < end_index; atom++){
register double Hx = 0.0;
register double Hy = 0.0;
register double Hz = 0.0;
const int start = atoms::neighbour_list_start_index[atom];
const int end = atoms::neighbour_list_end_index[atom] + 1;
for (int nn = start; nn < end; nn++){
const int natom = atoms::neighbour_list_array[nn];
const double Jij = atoms::i_exchange_list[atoms::neighbour_interaction_type_array[nn]].Jij;
Hx -= Jij * atoms::x_spin_array[natom];
Hy -= Jij * atoms::y_spin_array[natom];
Hz -= Jij * atoms::z_spin_array[natom];
}
atoms::x_total_spin_field_array[atom] += Hx;
atoms::y_total_spin_field_array[atom] += Hy;
atoms::z_total_spin_field_array[atom] += Hz;
}
该代码的函数和变量的高级概述如下:有一个称为"spin"的物理向量的1D阵列(为了内存缓存目的,为每个分量x、y、z、atoms::x_spin_array
等划分为三个1D阵列)。这些自旋中的每一个与一些其他自旋相互作用,并且所有的相互作用被存储为1D邻居列表(atoms::neighbour_list_array
)。每个原子的相关交互列表由两个单独阵列中的邻居listarray
的开始和结束索引确定。在计算结束时,每个原子自旋都有一个有效场,它是相互作用的矢量和。
考虑到代码量很小,占用的运行时间相当大,我已经尽了最大努力,但我觉得必须有一种方法来进一步优化它,但作为一名物理学家而不是计算机科学家,也许我错过了什么?
在连续数据上有一个恒定的乘法、减法和加法流。这似乎是SSE的理想用途。如果内存带宽有限,请改用OpenCL/CUDA。
如果您不熟悉所有的低级指令,请尝试使用此库。
然后,这种内部循环可能会被大幅重组,可能会加快速度。
如果x
、y
、z
组件确实是链表,那么执行x[i]
、y[i]
和z[i]
将导致列表被多次遍历,从而给出(n^2)/2
迭代。使用矢量将使其成为O(1)
操作。
您提到,出于内存缓存的目的,三个坐标是分开的,但当您访问内存中的三个不同区域时,这将影响级别1和级别2的缓存位置。链表也会影响您的缓存位置。
使用类似的东西
struct vector3d {
double x;
double y;
double z;
};
std::vector<vector3d> spin;
std::vector<vector3d> total_spin;
这应该会提高缓存的局部性,因为x、y和z值在内存中是相邻的,并且旋转占用了内存的线性块。
我觉得以下建议可以帮助您优化代码,即使不是完全优化:
- 尽可能使用初始化而不是分配
- 为了获得更好的速度,更喜欢提前增量而不是后增量。(相信我,它确实改变了)
除此之外,我认为代码还不错。每个DS都有一些优点和缺点……你必须接受它。
快乐编码!
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在 c++ 中拥有一组结构的正确方法是什么?
- 通过JNI传递数据数组的最快方法是什么
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 在另一个类视图中添加最多2个图表的正确方法是什么
- 在C++中样板"冷/never_inline"错误处理技术的最佳方法是什么?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 在C++中包含原型文件的正确方法是什么?
- 在 OpenCV C++ 中估计基本矩阵之前对相应点进行归一化的正确方法是什么?
- 在PostgreSQL中根据它们的ID选择大量行的最快方法是什么?
- 在OSX上使用CMake将Adobe的XMP工具包构建为共享库的最简单方法是什么?