为什么OpenMP版本更慢?

Dun*_*can 11 c++ openmp

我正在试验OpenMP.我写了一些代码来检查它的性能.在使用Kubuntu 11.04的4核单Intel CPU上,使用OpenMP编译的以下程序比没有OpenMP编译的程序慢大约20倍.为什么?

我用g ++编译了它-g -O2 -funroll-loops -fomit-frame-pointer -march = native -fopenmp

#include <math.h>
#include <iostream>

using namespace std;

int main ()
{
  long double i=0;
  long double k=0.7;

  #pragma omp parallel for reduction(+:i)
  for(int t=1; t<300000000; t++){       
    for(int n=1; n<16; n++){
      i=i+pow(k,n);
    }
  }

  cout << i<<"\t";
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

ole*_*enz 15

问题是变量k被认为是共享变量,因此必须在线程之间同步.避免这种情况的可能解决方案是:

#include <math.h>
#include <iostream>

using namespace std;

int main ()
{
  long double i=0;

#pragma omp parallel for reduction(+:i)
  for(int t=1; t<30000000; t++){       
    long double k=0.7;
    for(int n=1; n<16; n++){
      i=i+pow(k,n);
    }
  }

  cout << i<<"\t";
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

在下面的注释中跟随Martin Beckett的提示,不是在循环中声明k,而是在循环外声明k const.

否则,ejd是正确的 - 这里的问题似乎并不是很糟糕的并行化,而是代码并行化时的错误优化.请记住,gcc的OpenMP实现非常年轻,远非最佳.

  • 在可能的情况下声明所有const也是值得的 - 然后OMP同步器知道它不需要做任何事情.另请参阅32个用于c ++程序员的OMP陷阱(http://www.viva64.com/en/a/0054/) (3认同)
  • 如果编译器在非OMP情况下完全优化了所有对`pow()`的调用,那么我就不会感到惊讶,因为它可以证明k是常量并且有16次迭代的循环在默认展开深度.最新版本的gcc在编译时对`double`s'的长计算没有任何精度损失没有任何麻烦. (2认同)