用于距离计算的并行C代码

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)

非常感谢你的帮助

Ale*_*nov 5

(下面的答案是指问题中的初始代码,从那时起应用这些建议得到了改进)


您需要阅读有关如何使用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.