OpenMP的减少是否可以免于虚假共享?

时间:2018-04-03 12:45:06

标签: c++ openmp

我仍然感到困惑。如果我在OpenMP中使用reduce子句可以进行错误共享吗? (两个代码片段都给出了正确的结果。)

一个小例子,需要最大数组:

double max_red(double *A, int N){

double mx = std::numeric_limits<double>::min();
#pragma omp parallel for reduction(max:mx)
for(int i=0; i<N; ++i){
    if(A[i]>mx) mx = A[i];

}

return mx; 
}

此示例也可以使用额外填充

编写
double max_padd(double *A, int N){

omp_set_num_threads(NUM_THREADS);
double local_max[NUM_THREADS][8];
double res;

#pragma omp parallel
{

    int id = omp_get_thread_num();
    local_max[id][0] = std::numeric_limits<double>::min();

    #pragma omp for
        for(int i=0; i<N; ++i){
            if(A[i]>local_max[id][0])local_max[id][0]=A[i];
    }
    #pragma omp single
    {
        res = local_max[0][0];
        for(int i=0; i<NUM_THREADS; ++i){
            if(local_max[i][0]> res)res = local_max[i][0];
        }
    }
}

return res;

}

完全禁止虚假共享或减少条款是否足够安全所需的额外填充?

由于

1 个答案:

答案 0 :(得分:4)

填充不是必需的。

从技术上讲,这不是标准规定的。该标准没有说明每个线程私有副本在内存中的位置。请记住,错误共享不是正确性问题,而是(非常重要的)实际性能问题。

但是,如果任何OpenMP实现会造成这样的菜鸟错误并将私有副本放在同一个缓存行上,那将是非常令人惊讶的。

假设实现比程序员更好地理解平台及其性能特征。如果您通过测量证明惯用解决方案(例如您的第一个解决方案)具有无法通过调整修复的不良性能,则只编写手动“性能改进”,例如您的第二个解决方案。

实用注意事项:我非常确定实现通常会将私有副本放在执行线程的(私有)堆栈上,然后每个线程都会在关键部分更新共享变量,或者在支持时以原子方式更新。

理论上,基于对数时间树的减少是可能的。但是implementations don't seem to do that,至少在所有情况下都不是。