C++ 为什么OpenMP版本较慢?

C++ 为什么OpenMP版本较慢?,c++,openmp,C++,Openmp,我正在试验OpenMP。我写了一些代码来检查它的性能。在采用Kubuntu 11.04的4核单英特尔CPU上,以下使用OpenMP编译的程序比不使用OpenMP编译的程序慢20倍左右。为什么? 我用g++-g-O2-funroll循环-fomit帧指针-march=native-fopenmp编译了它 #include <math.h> #include <iostream> using namespace std; int main () { long doub

我正在试验OpenMP。我写了一些代码来检查它的性能。在采用Kubuntu 11.04的4核单英特尔CPU上,以下使用OpenMP编译的程序比不使用OpenMP编译的程序慢20倍左右。为什么?

我用g++-g-O2-funroll循环-fomit帧指针-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;
}
#包括
#包括
使用名称空间std;
int main()
{
长双i=0;
长双k=0.7;
#pragma omp并行还原(+:i)

对于(int t=1;t而言,问题在于变量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;
}
#包括
#包括
使用名称空间std;
int main()
{
长双i=0;
#pragma omp并行还原(+:i)
对于(int t=1;t最快代码:

for (int i = 0; i < 100000000; i ++) {;}
for(inti=0;i<100000000;i++){;}
稍微慢一点的代码:

#pragma omp parallel for num_threads(1)
for (int i = 0; i < 100000000; i ++) {;}
#pragma omp parallel for
for (int i = 0; i < 100000000; i ++) {;}
用于num_线程的pragma omp parallel(1) 对于(int i=0;i<100000000;i++){;}
速度慢2-3倍的代码:

#pragma omp parallel for num_threads(1)
for (int i = 0; i < 100000000; i ++) {;}
#pragma omp parallel for
for (int i = 0; i < 100000000; i ++) {;}
#pragma omp parallel for
对于(int i=0;i<100000000;i++){;}
无论是在{和}之间。一个简单的;或更复杂的计算,结果都是一样的。我在Ubuntu 13.10 64位下编译,使用gcc和g++,尝试不同的参数-ansi-pedantic errors-Wall-Wextra-O3,并在英特尔四核3.5GHz上运行


我猜线程管理开销是错误的?OMP在每次需要线程时创建一个线程并在之后销毁它似乎并不明智。我以为会有四个(或八个)线程要么在需要时运行,要么处于休眠状态。

我在GCC上观察到类似的行为。但我想知道,在我的例子中,它是否与模板或内联函数有关。您的代码是否也在模板或内联函数中?请查看

但是,对于非常短的for循环,您可能会观察到一些与线程切换相关的小开销,如您的情况:

#pragma omp parallel for
for (int i = 0; i < 100000000; i ++) {;}
#pragma omp parallel for
对于(int i=0;i<100000000;i++){;}

如果您的循环执行时间很长,只有几毫秒甚至几秒钟,那么在使用OpenMP时,您应该观察到性能提升。但只有当您有多个CPU时,您的内核越多,OpenMP的性能就越高。

我从未使用过OpenMP,但在我看来,创建多线程和syn的开销越大对这些线程之间的共享数据访问进行计时(很多)在4个不同的内核之间分配处理的好处。但是20倍似乎有点太极端了。如果你想检查OpenMP性能,那么使用设计更好的并行代码将是一个好主意。我刚刚把你的程序带到一个有2个处理器的Ubuntu 11.04系统上运行。我做了一个简单的编译(g++4.5.2,没有选项)使用OpenMP(g++-fopenmp)编译并运行。串行程序的运行时间为6:45.41,OpenMP程序(在两个处理器上运行)的运行时间为3:36.61(使用时间测量).考虑到您的计划,这是我所期望的。我将尝试您的选项,看看会发生什么。同意ejd。我看到OpenMP的加速约为4倍(使用问题中提到的选项)在4核机器上使用GCC4.8,开销非常小,如果编译器通过调用
pow()完全优化了整个内部循环,我也不会感到惊讶
在非OMP的情况下,因为它可以证明k是常数,并且具有16次迭代的循环在默认展开深度范围内。最新版本的gcc在编译时对
double
s进行长时间计算时没有任何精度损失。感谢olenz。将k的声明移到循环内部解决了sp问题eed问题。但是,它需要在循环中重新声明k 30000000次。我尝试了另一种解决方案,将k声明保留在循环之前(与原始代码一样),并将OpenMP代码更改为“#pragma omp parallel for firstprivate(k)reducement(+:I)”,因此k不再共享。但是,它不起作用。即使k是firstprivate,程序仍然慢20倍。为什么?将“k”设为private对我的运行没有影响(这是有意义的,因为它从未更改)。查看生成的代码,串行案例的优化方式与OpenMP版本完全不同。这就是造成性能差异的原因。OpenMP版本仍在运行时执行所有计算,而串行版本在编译时执行大量工作。优化串行代码的工作比OpenMP版本多并行代码(因此,在有些情况下,串行代码的运行速度比并行代码快,即使没有理由不能更好地优化并行代码)。当k在循环之前声明时,即使k设置为私有,看起来-funroll循环优化选项在OpenMP上也不起作用。也许这是g++的一个限制?我想知道Intel的icc编译器是否可以对其进行优化。如果可能,也值得声明所有常量-然后OMP同步器知道它不必做任何事情。另请参阅C++程序员的32个OMP陷阱