我有一个 C 代码(Open MP 并行化),在 Intel Xeon E5-2650 节点(全部 16 个内核)上运行所需的时间是在配备 Intel i 7 处理器的桌面上运行的时间的两倍多。通过标准基准测试案例,我的计算节点提供了令人满意的性能。我意识到这与我的代码在现代处理器上运行的效率有关。有人可以指导我了解代码中可以改进的方面吗?我遇到过矢量化等问题,但是我无法找到有关此类问题的清晰的分步教程或文档。 关于代码:
该代码是模拟粒子相互作用。在识别出社区后,它们进行交互、计算和存储数据。粒子是结构体数组。交互函数示例如下所示。
static void interact(particleData *pdata, int a, int b, interactParams params)
{
int i;
double rdotdwdx = 0.0, vdotr =0.0;
for(i=0;i<dim;i++){
rdotdwdx += (¶ms.xr.x)[i]*(¶ms.dwdx.x)[i];
vdotr += (¶ms.vr.x)[i]*(¶ms.xr.x)[i];
}
double Fab = vdotr/(params.rdotr + 0.0001*params.h*params.h);
double acc;
for(i = 0; i < dim; i++){
acc = 8.*(((pdata[a].eta/pdata[a].rho)+(pdata[b].eta/pdata[b].rho)) /(pdata[a].rho+pdata[b].rho))*Fab*(¶ms.dwdx.x)[i];
(&pdata[a].acc.x)[i] += acc*pdata[b].mass;
(&pdata[b].acc.x)[i] += -acc*pdata[a].mass;
}
}
}
这里的pdata是一个结构体数组。 acc 是 pdata[i] 的成员,并且具有成员 x、y 和 z。 struct pdata 还有许多其他数据成员。 data param 的成员涉及 pow 等数学函数。 上面发布的代码是我的分析器中显示为消耗最多时间的部分之一。
我在两台机器上使用的编译器都是gcc。
谢谢。感谢您的耐心
最佳答案
示例代码似乎使用了结构数组,这是 N 体模拟等方面表现不佳的经典主题。您应该阅读 AoS 到 SoA 的转换,其中 SoA 是数组结构,并且几乎总是计算我认为您正在尝试计算的内容的正确方法。
除了使用 AoS 主题之外,您的循环还充满了大量间接代码。您应该查找 (&pdata[a].acc.x)[i]
的程序集,并准确查看分配给该数量需要多少条指令。
如果存在循环不变量,您应该将它们从循环中取出,并可能将这些高度间接的访问替换为使用单个指针的访问,然后使用该指针迭代数据。我不知道这有多容易做到,也不知道效果如何,但如果我是你,我就会从这里开始。
“AoS 到 SoA 转换”在 Google 上有很多点击;其中有https://software.intel.com/en-us/articles/memory-layout-transformations ,这似乎与您的案例特别相关。
关于C 代码在 Intel Xeon E5-2650 上的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27820959/