VS2010發表時很強調他的平行處理函式的功能,因此我也嘗試看看是不是真如廣告說的那麼神奇。測試使用一張8MB(32bit)的影像進行500次的平滑化處理。
平滑化處理公式為
I'(x) = (I(x) - dc) * W(x)
首先,必載入平行處理函式的檔頭,由於這是2010才支援的功能,我會先判斷_MSC_VER是否為1600以上的版本,以確認編譯器有支援
#if _MSC_VER >= 1600
#include "ppl.h"
using namespace Concurrency;
using namespace std;
#endif // _MSC_VER
接著將原有的
unsigned long dwPos = 0;
long value = 0;
for(unsigned long i=0 ; i<dwSize ; i++)
{
value = (((pIData[dwPos] - DC[0]) * pWeight[dwPos]) >> 8);
if(value < 0) pOData[dwPos] = 0;
else if(value > 255) pOData[dwPos] = 255;
else pOData[dwPos] = (unsigned char)value;
dwPos++;
value = (((pIData[dwPos] - DC[1]) * pWeight[dwPos]) >> 8);
if(value < 0) pOData[dwPos] = 0;
else if(value > 255) pOData[dwPos] = 255;
else pOData[dwPos] = (unsigned char)value;
dwPos++;
value = (((pIData[dwPos] - DC[2]) * pWeight[dwPos]) >> 8);
if(value < 0) pOData[dwPos] = 0;
else if(value > 255) pOData[dwPos] = 255;
else pOData[dwPos] = (unsigned char)value;
dwPos+=2;
}
改寫為
unsigned long dwPos = 0;
long value = 0;
parallel_for(unsigned long(0),dwSize,[&](unsigned long i)
{
dwPos = (i << 2);
value = (((pIData[dwPos] - DC[0]) * pWeight[dwPos]) >> 8);
if(value < 0) pOData[dwPos] = 0;
else if(value > 255) pOData[dwPos] = 255;
else pOData[dwPos] = (unsigned char)value;
dwPos++;
value = (((pIData[dwPos] - DC[1]) * pWeight[dwPos]) >> 8);
if(value < 0) pOData[dwPos] = 0;
else if(value > 255) pOData[dwPos] = 255;
else pOData[dwPos] = (unsigned char)value;
dwPos++;
value = (((pIData[dwPos] - DC[2]) * pWeight[dwPos]) >> 8);
if(value < 0) pOData[dwPos] = 0;
else if(value > 255) pOData[dwPos] = 255;
else pOData[dwPos] = (unsigned char)value;
dwPos+=2;
});
這裡我犯了一個明顯的錯誤,在做並行化處理時必注意資料必需保持獨立性,共享資料則必需唯讀或同步化,上述的程式執行後,影像上會有明顯的雜點,主要原因是共享資料dwPos與value並未保持唯讀的特性,使得資料混亂。
解決方案為將dwPos與value變為local的變數不共享,程式修改如下:
parallel_for(unsigned long(0),dwSize,unsigned long(1),[&](unsigned long i)
{
for(int c=0 ; c<3 ; c++)
{
unsigned long dwPos = (i << 2) + c;
long value = (((pIData[dwPos] - DC[c]) * pWeight[dwPos]) >> 8);
if(value < 0) pOData[dwPos] = 0;
else if(value > 255) pOData[dwPos] = 255;
else pOData[dwPos] = (unsigned char)value;
}
});
先在Core dual 2.2G + XP系統上執行,比較serial / parallel上執行的效能
serial: 0.01639851 sec / frame
paralle: 0.03472216 sec / frame
在雙核主機上serial的效能比parallel佳
換成 Coro i7 920 2.7G + XP64再次比較
serial: 0.01312059
parallel: 0.01394287
平行處理的效能與使用單處理器相當,也就是說,單純使用平行處理函式的速度並未有提升而且可能降低原有的效能。看來事實並不如Microsoft廣告說的如此簡單,要發揮出真正的效能仍有不少最佳化的動作要做。