2012-01-06 73 views
7

這是我想要轉換爲openCL的循環。openCL減少,並傳遞2d數組

for(n=0; n < LargeNumber; ++n) {  
    for (n2=0; n2< SmallNumber; ++n2) { 
     A[n]+=B[n2][n]; 
    }               
    Re+=A[n];  
} 

這就是我到目前爲止,雖然,我知道這是不正確的,缺少一些東西。

__kernel void openCL_Kernel(__global int *A, 
         __global int **B, 
         __global int *C, 
         __global _int64 Re, 
            int D) 
{ 

int i=get_global_id(0); 
int ii=get_global_id(1); 

A[i]+=B[ii][i]; 

//barrier(..); ? 

Re+=A[i]; 

} 

我是這種類型的東西的完整初學者。首先我知道我不能將全局雙指針傳遞給openCL內核。如果可以的話,在發佈解決方案之前請等待幾天左右,我想爲自己弄清楚這一點,但如果您能幫助我指出正確的方向,我將不勝感激。

+1

「我無法將全局雙指針傳遞給openCL內核」您選擇的單詞讓我困惑。您可以傳遞一個雙指針(例如「__global double * A」)。您無法傳遞2D指針(例如「__global int ** B」)。 – vocaro 2012-01-06 19:56:22

+0

你有沒有考慮將程序分成兩個獨立的內核(順序執行),一個用於內部循環,另一個用於外部循環? – vocaro 2012-01-06 19:59:06

回答

11

關於你傳遞兩個指針的問題:通常通過將整個矩陣(或你正在處理的任何東西)拷貝到一個連續的內存塊中來解決這類問題,如果這些塊有不同的長度傳遞另一個數組,包含各行的偏移量(因此您的訪問權限看起來像B[index[ii]+i])。

現在爲了減少到Re:因爲你沒有提到你正在做什麼類型的設備,我將假設它的GPU。在這種情況下,我會避免在同一個內核中進行縮減,因爲它會像發佈它一樣緩慢(您將不得不將序列化訪問數千個線程的Re(以及訪問A[i]))。 相反,我會寫想內核,總結所有B[*][i]A[i],並把從A還原成Re在另一個內核,並做到在幾個步驟,這是您使用它進行操作n元素,並將它們降低到類似的減少內核(或者任何其他數字),然後你反覆調用這個內核,直到你下降到一個元素,這是你的結果(我把這個描述刻意模糊,因爲你說你想知道自己的想法)

作爲旁註:您意識到原始代碼並不完全具有良好的內存訪問模式?假設B比較大(並且由於第二維而比A大得多),讓內部循環遍歷外部索引會產生大量的cachemisses。這是更糟糕移植到GPU,這大約是一致內存訪問非常敏感,當

所以重新排序像這樣可以大量提高性能:

for (n2=0; n2< SmallNumber; ++n2) 
    for(n=0; n < LargeNumber; ++n)  
    A[n]+=B[n2][n]; 
for(n=0; n < LargeNumber; ++n)             
    Re+=A[n];  

這是格外真實,如果你有一個編譯器是擅長自動矢量化,因爲它可能能夠矢量化該構造,但是對於原始代碼來說這是不太可能的(並且如果它不能證明AB[n2]不能引用相同的存儲器,它可以將原始代碼轉換成這個)。

+0

謝謝!這讓我有很多想法。 – MVTC 2012-01-07 19:33:06