OpenMP:Visual C ++ 2008和2010之间的巨大性能差异

时间:2011-01-19 16:44:30

标签: c++ performance visual-studio-2010 openmp

我正在运行相机采集程序,对获取的图像执行处理,我正在使用简单的OpenMP指令进行此处理。所以基本上我等待来自相机的图像,然后处理它。

迁移到VC2010时,我看到非常奇怪的性能问题:在VC2010下,我的应用程序占用了近100%的CPU,而在VC2008下只占用了10%。

如果我仅对处理代码进行基准测试,那么VC2010和VC2008之间没有区别,使用采集功能会产生差异。

我已将重现问题所需的代码缩减为执行以下操作的简单循环:

  for (int i=0; i<1000; ++i)
  {
    GetImage(buffer);//wait for image
    Copy2Array(buffer, my_array);

    long long sum = 0;//do some simple OpenMP parallel loop
    #pragma omp parallel for reduction(+:sum)
    for (int j=0; j<size; ++j)
      sum += my_array[j];
  }

此循环在2008年占据CPU的5%,在2010年占70%。

我做了一些分析,这表明在2010年大部分时间花在了OpenMP的vcomp100.dll!_vcomp::PartialBarrierN::Block

我还做了一些并发性分析:

2008年,处理工作分布在3个工作线程上,由于处理时间远远低于图像等待时间,因此工作线程非常活跃

相同的主题出现在2010年,但它们都被PartialBarrierN::Block函数100%占用。由于我有四个核心,他们正在吃掉75%的工作,这大概就是我在CPU职业中所看到的。

所以看起来OpenMP和Matrox采集库(专有)之间存在冲突。但它是VS2010或Matrox的错误吗? 有什么我能做的吗?使用VC ++ 2010对我来说是必须的,所以我不能坚持使用2008。

非常感谢

STATUS UPDATE

使用新的并发框架,如DeadMG所示,可以产生40%的CPU。分析它显示时间花在处理上,因此它没有显示我在OpenMP中看到的错误,但在我的情况下性能比OpenMP差。

STATUS UPDATE 2

我已经安装了最新英特尔C ++的评估版。它显示完全相同的性能问题!!

我交叉发布到MSDN forum

STATUS UPDATE 3

在Windows 7 64位和XP 32位上测试,结果完全相同(在相同的机器上)

4 个答案:

答案 0 :(得分:18)

在2010 OpenMP中,每个工作线程在任务完成后执行大约200 ms的旋转等待。在我的I / O等待和重复的OpenMP任务的情况下,它正在大量加载CPU。

解决方案是改变这种行为;英特尔C ++有extension routinekmp_set_blocktime()。但是Visual 2010没有这种可能性。

this Autodesk note中,他们讨论了英特尔C ++的问题。此编译器首先引入了该行为,但允许更改它(参见上文)。 Visual 2010切换到它,但是......没有像英特尔那样的解决方法。

总而言之,切换到英特尔C ++并使用kmp_set_blocktime(0)解决了它。

感谢来自DataLever Corporation

other MSDN thread的John Lilley

问题已提交至MS Connect,并收到“无法修复”反馈。

答案 1 :(得分:5)

使用OpenMP 3.0,可以通过OMP_WAIT_POLICY停用spinwait:

_putenv_s( "OMP_WAIT_POLICY", "PASSIVE" );

效果与kmp_set_blocktime(0)基本相同,但是当我们在运行时设置环境变量OMP_WAIT_POLICY时,它只会影响当前进程和子进程。

当然,OMP_WAIT_POLICY也可以由启动器应用程序设置,例如, Blender以这种方式处理它。

VC2010的修补程序可用here,VC2013等更高版本可直接支持。

答案 2 :(得分:4)

您可以尝试使用VS2010附带的新并发运行时 - 只需从测试示例开始。

即,

for (int i=0; i<1000; ++i)
  {
    GetImage(buffer);//wait for image
    Copy2Array(buffer, my_array);

    long long sum = 0;//do some simple OpenMP parallel loop
    #pragma omp parallel for reduction(+:sum)
    for (int j=0; j<size; ++j)
      sum += my_array[j];
  }

会变成

for (int i=0; i<1000; ++i)
  {
    GetImage(buffer);//wait for image
    Copy2Array(buffer, my_array);

    Concurrency::combinable<int> combint;
    Concurrency::parallel_for(0, size / 1000, [&](int j) {
      for(int i = 0; i < 1000; i++)
          combint.local() += my_array[(j * 1000) + i];
    });
    combint.combine([](int a, int b) { return a + b; });
  }

答案 3 :(得分:1)

我测试了另一个采集板,问题是相同的,所以罪魁祸首是VC ++ 2010。正如thread on MSDN forums所示,微软进行了OpenMP实施更改,搞砸了我的程序。