使用 OpenMP 进行归约以计算矩阵元素的最终求和值

Make a reduction with OpenMP to compute the final summed value of an element of matrix

我有以下双循环,我在其中计算矩阵 Fisher_M[FX][FY] 的元素。

我尝试通过放一个OMP pragma来优化它#pragma omp parallel for schedule(dynamic, num_threads),但是增益没有预期的那么好。

有没有一种方法可以使用 OpenMP(总和)进行归约以快速计算元素 Fisher_M[FX][FY]?或者也许这对 MAGMA 或 CUDA 可行?

#define num_threads 8

#pragma omp parallel for schedule(dynamic, num_threads)
for(int i=0; i<CO_CL_WL.size(); i++){
    for(int j=0; j<CO_CL_WL.size(); j++){
        if( CO_CL_WL[i][j] != 0 || CO_CL_WL_D[i][j] != 0){
          Fisher_M[FX][FY] += CO_CL_WL[i][j]*CO_CL_WL_D[i][j];
        }
    }
}

您的代码在第 Fisher_M[FX][FY] += ... 行存在竞争条件。可以用reduce来解决:

double sum=0;  //change the type as needed
#pragma omp parallel for reduction(+:sum) 
for(int i=0; i<CO_CL_WL.size(); i++){
    for(int j=0; j<CO_CL_WL.size(); j++){
        if( CO_CL_WL[i][j] != 0 || CO_CL_WL_D[i][j] != 0){
          sum += CO_CL_WL[i][j]*CO_CL_WL_D[i][j];
        }
    }
}
Fisher_M[FX][FY] += sum;

请注意,此代码受内存限制,计算量不大,因此并行化带来的性能增益可能小于预期(并且取决于您的硬件)。

Ps:为什么需要这个条件if( CO_CL_WL[i][j] != 0 || CO_CL_WL_D[i][j] != 0)?如果其中任何一个为零,则总和不会改变。如果删除它,编译器可以生成更好的矢量化代码。

Ps2:在schedule(dynamic, num_threads) 子句中,第二个参数是块大小而不是使用的线程数。我建议根据您的情况将其删除。如果您想指定使用的线程数,请添加 num_threads 子句或使用 omp_set_num_threads 函数。