[英]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.