我有一个c代码(Open MP并行化),在英特尔至强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是一个struct数组。 acc是pdata [i]的成员,并且有成员x,y和z。 struct pdata也有许多其他数据成员。数据参数的成员涉及像pow这样的数学函数。 上面发布的代码是我的探查器中显示的占用最长时间的部分之一。
我在两台机器上使用的编译器都是gcc。
谢谢。感谢您的耐心
答案 0 :(得分:1)
示例代码似乎使用了一组结构,这是N体仿真的经典表现不佳的主题,等等。你应该阅读AoS-to-SoA转换,其中SoA是数组结构,几乎总是计算我认为你想要计算的东西的正确方法。
除了使用AoS主题之外,你的循环还充满了大量间接的代码。您应该查看(&pdata[a].acc.x)[i]
的程序集,并确切地查看分配给此数量所需的指令数。
如果存在循环不变量,则应将它们从循环中拉出来,并可能使用单个指针替换这些高度间接访问,然后使用该指针迭代数据。我不知道这样做有多容易,也不知道它有多好,但如果我是你,那就是我开始的地方。
“AoS-to-SoA转换”中有许多谷歌点击率;其中有https://software.intel.com/en-us/articles/memory-layout-transformations,这似乎与你的情况特别相关。