开放mp方法的基准测试结果奇怪

时间:2018-12-30 20:40:24

标签: c++11 openmp benchmarking

我的基准测试结果非常奇怪。一方面,我具有用于计算二次形式的串行函数。另一方面,我编写了两个并行版本。对于一个线程,所有功能应或多或少地需要相同的运行时间。但是一个并行功能只需要一半的时间。有“隐藏”优化吗?

序列号:

double quadratic_form_serial(const std::vector<double> & A,const std::vector<double> & v, const std::vector<double> & w){
    int N= v.size();
    volatile double q=0.0;

    for(int i=0; i<N; ++i)
        for(int j=0; j<N; ++j)
            q +=v[i]*A[i*N+j]*w[j];

return q;
}

并行版本1:

double quadratic_form_parallel(const std::vector<double> & A,const std::vector<double> & v, const std::vector<double> & w, const int threadnum){
int N= v.size();

omp_set_num_threads(threadnum);
volatile double q[threadnum];
volatile double val = 0.0; 

#pragma omp parallel
{
    int me = omp_get_thread_num(); 
    q[me] = 0.0;
    #pragma omp for collapse(2)
    for(int i=0; i<N; ++i)
        for(int j=0; j<N; ++j)
            q[me]+=v[i]*A[i*N+j]*w[j];
    #pragma omp atomic
    val+=q[me];
}
return val;
}

平行版本2:

double quadratic_form_parallel2(const std::vector<double> & A,const std::vector<double> & v, const std::vector<double> & w, const int threadnum){
    int N= v.size();
    volatile double result =0.0;
    omp_set_num_threads(threadnum);

    #pragma omp parallel for reduction(+: result)
    for (int i=0; i<N; ++i)
        for (int j=0; j<N; ++j)
            result += v[i] * A[i*N + j] * w[j];
    return result;
}

我为N = 10000运行代码,并在调用函数之前刷新了缓存。函数quadratic_form_parallel2需要的一个线程少于其他两个函数所需时间的一半:

threads    serial       Parallel1       Parallel2
1          0.0882503    0.0875649       0.0313441   

1 个答案:

答案 0 :(得分:4)

这很可能是result是第二个OpenMP版本中的reduction变量的结果。这意味着,每个线程都获得result的私有副本,该副本在并行区域之后合并。此私有副本可能不考虑易失性限制,因此可以进行更多优化。我假设volatileprivate之间的详细交互未指定。

这表明,将变量标记为volatile(大概是为了避免优化整个代码)是一个坏主意。而是只输出结果。