优化循环以获得更好的性能

时间:2021-02-06 13:54:26

标签: c++ c multithreading parallel-processing openmp

我像这样并行化了我的代码:

    for (int i=0; i<size; ++i) {
    
        #pragma omp parallel for
        for (int j=i; j<size; ++j) {
            int l = j+1;
            float sum = a[i*size+j];
            float sum2 = a[l*size+i];
            for (int k=0; k<i; ++k) {
                sum -= a[i*size+k] * a[k*size+j];
                sum2 -= a[l*size+k] * a[k*size+i];
            }
            a[i*size+j]=sum;
            a[l*size+i]=sum2;
        }
        
        #pragma omp parallel for
        for (int j=i+1; j<size; ++j) {
            a[j*size+i]/=a[i*size+i];
        }
    }

但我希望它是这样的:

    for (int i=0; i<size; ++i) {
    
        #pragma omp parallel for
        for (int j=i; j<size; ++j) {
            int l = j+1;
            float sum = a[i*size+j];
            float sum2 = a[l*size+i];
            for (int k=0; k<i; ++k) {
                sum -= a[i*size+k] * a[k*size+j];
                sum2 -= a[l*size+k] * a[k*size+i];
            }
            a[i*size+j]=sum;
            a[l*size+i]=sum2;
            a[l*size+i]/=a[i*size+i];
        }
    }

所以我可以获得更好的表现。但是,如果我将 a[l*size+i]/=a[i*size+i]; 放入与其他内容相同的循环中,则会得到与应有的结果不同的结果。我想这是因为 OpenMP 指令,因为如果没有它们,两者的结果相同。

如果有人能给我一些关于如何使这成为可能或如何提高总体性能的提示,我会很高兴。

1 个答案:

答案 0 :(得分:1)

无需重新设计代码,您可以尝试以下操作:

    #pragma omp parallel
    {
        for (int i=0; i<size; ++i)
        {
            #pragma omp for
            for (int j=i; j<size; ++j) {
                 int l = j+1;
                 float sum = a[i*size+j];
                 float sum2 = a[l*size+i];
                 for (int k=0; k<i; ++k) {
                     sum -= a[i*size+k] * a[k*size+j];
                     sum2 -= a[l*size+k] * a[k*size+i];
                 }
                a[i*size+j]=sum;
                a[l*size+i]=sum2;
            }
            #pragma omp for
            for (int j=i+1; j<size; ++j)
                a[j*size+i]/=a[i*size+i];
      }
   }

不是创建 2x 次 per 循环 i 迭代(总共 2 * 大小的并行区域),您可以创建一个。尽管如此,在 OpenMP 标准的有效实现中,新的并行区域不会引入人们想象的那么多开销,因为通常线程将在第一次创建并在下一个并行区域上重用。

尽管如此,拥有多个并行区域的开销之一是在它们的末尾调用隐式屏障。不幸的是,这种开销仍然存在于我所展示的版本中。为避免这种情况,您需要重新设计算法。