[英]OpenMP: Huge performance differences between Visual C++ 2008 and 2010
我正在运行一个摄像头采集程序,对采集的图像进行处理,我正在使用简单的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。
太谢谢了
正如DeadMG所建议的那样,使用新的并发框架会导致40%的CPU。 分析它显示时间花在处理上,因此它没有显示我在OpenMP中看到的错误,但在我的情况下性能比OpenMP差。
我已经安装了最新英特尔C ++的评估版。 它显示完全相同的性能问题!!
我交叉发布到MSDN论坛
在Windows 7 64位和XP 32位上测试,结果完全相同(在相同的机器上)
在2010 OpenMP中,每个工作线程在任务完成后执行大约200 ms的旋转等待。 在我的I / O等待和重复的OpenMP任务的情况下,它正在大量加载CPU。
解决方案是改变这种行为; 英特尔C ++有一个扩展例程 ,即kmp_set_blocktime()
。 但是Visual 2010没有这种可能性。
在这篇Autodesk笔记中,他们讨论了英特尔C ++的问题。 此编译器首先引入了该行为,但允许更改它(参见上文)。 Visual 2010切换到它,但......没有像英特尔这样的解决方法。
总而言之,切换到英特尔C ++并使用kmp_set_blocktime(0)
解决了它。
感谢DataLever公司的 John Lilley在另一个MSDN线程上
问题已提交给MS Connect ,并收到“无法修复”的反馈。
使用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的修补程序,VC2013等更高版本可直接支持。
您可以尝试使用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; });
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.