Nic*_*las 5 c parallel-processing openmp
我有一个C代码来计算两组节点之间的距离(每个节点三个坐标),即使我的代码已经足够快,我想用并行计算来增加它.我已经找到了一些关于openMP的信息,我现在正试图使用它,但是有点奇怪.没有omp,代码cpu时间是20s,添加两个pragma行需要160s!怎么会发生?
我在这里附上我的代码
float computedist(float **vG1, float **vG2, int ncft, int ntri2, int jump, float *dist){
int k = 0, i, j;
float min = 0;
float max = 0;
float avg = 0;
float *d = malloc(3*sizeof(float));
float diff;
#pragma omp parallel
for(i=0;i<ncft;i+=jump){
#pragma omp parallel
for(j=0;j<ntri2;j++){
d[0] = vG1[i][0] - vG2[j][0];
d[1] = vG1[i][1] - vG2[j][1];
d[2] = vG1[i][2] - vG2[j][2];
diff = sqrt(pow(d[0],2) + pow(d[1],2) + pow(d[2],2));
if(j==0)
dist[k] = diff;
else
if(diff<dist[k])
dist[k] = diff;
}
avg += dist[k];
if(dist[k]>max)
max = dist[k];
k++;
}
printf("max distance: %f\n",max);
printf("average distance: %f\n",avg/(int)(ncft/jump));
free(d);
return max;
}
Run Code Online (Sandbox Code Playgroud)
非常感谢你的帮助
(下面的答案是指问题中的初始代码,从那时起应用这些建议得到了改进)
您需要阅读有关如何使用OpenMP的更多信息.该规范可从http://www.openmp.org获得 ; 并且有指向教程和其他资源的链接.
我将在您的代码中指出一些问题并提供如何解决这些问题的建议.
float *d = malloc(3*sizeof(float));
float diff;
Run Code Online (Sandbox Code Playgroud)
d
被用作临时变量,所以应该被标记为private
在#pragma omp parallel for
(见下文),以避免数据争用.同时,我只使用3个独立的浮点数而不是动态分配.diff
也有暂时的价值,所以也应该private
.
#pragma omp parallel
for(i=0;i<ncft;i+=jump){
#pragma omp parallel
for(j=0;j<ntri2;j++){
Run Code Online (Sandbox Code Playgroud)
您创建了一个并行区域,其中每个线程执行整个循环(因为该区域不包含任何工作共享构造),并且在其中您创建了一个嵌套区域,其中包含一组新的(!)线程,每个线程也执行整个内部循环.它为您的程序增加了大量开销和不必要的计算.你需要的是#pragma omp parallel for
,只适用于外循环.
d[0] = vG1[i][0] - vG2[j][0];
d[1] = vG1[i][1] - vG2[j][1];
d[2] = vG1[i][2] - vG2[j][2];
diff = sqrt(pow(d[0],2) + pow(d[1],2) + pow(d[2],2));
Run Code Online (Sandbox Code Playgroud)
与并行性无关,但为什么要调用pow
计算方块呢?一个好的旧乘法可能更容易阅读和更快.
if(j==0)
dist[k] = diff;
else
if(diff<dist[k])
dist[k] = diff;
Run Code Online (Sandbox Code Playgroud)
由于动作相同(dist[k]=diff;
),因此可以通过将两个条件与||
(逻辑或)组合来简化代码.
}
avg += dist[k];
if(dist[k]>max)
max = dist[k];
Run Code Online (Sandbox Code Playgroud)
在这里,您可以计算外部循环中的聚合值.在OpenMP中,这是通过reduction
子句来完成的#pragma omp for
.
k++;
}
Run Code Online (Sandbox Code Playgroud)
目前,您k
在每次迭代时递增,从而在迭代之间创建不必要的依赖关系,从而导致并行代码中的数据竞争.根据你的代码,k
它只是一个方便的"别名" i/jump
- 所以只需在迭代开始时分配它,然后make private
.