2012-04-14 87 views
0

我是opencl的新手,似乎有一些關於屏障功能的東西我不明白。這是我的內核的代碼。這是用* w輸出的標準矩陣向量計算。有1個工作組有64個工作單位,與矢量的維數相同opencl同步

#pragma OPENCL EXTENSION cl_khr_fp64 : enable 
__kernel void fmin_stuff(__global double *h, __global double *g, __global double 
    *w,int n,__global int * gid) { 

// Get the index of the current element 
int i = get_global_id(0); 
int j; 
gid[i]=get_local_id(0); 

w[i]=-g[i]; 
barrier(CLK_GLOBAL_MEM_FENCE | CLK_LOCAL_MEM_FENCE); 
for (j=0;j<n;j++) 
{ 
    if (j<i) 
    w[i]-=h[i+j*n]*w[j]; 
    barrier(CLK_GLOBAL_MEM_FENCE | CLK_LOCAL_MEM_FENCE); 
} 
} 

問題是代碼隨機失敗。輸出是正確的一段時間。這裏是每次運行的w的初始值。

-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.34999 2.51524 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.10141 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.72261 2.80155 
-0.148351 -0.309007 0.133204 -1.39589 2.88335 -2.68636 2.77369 

程序報告內核在每種情況下都成功執行。對於所有運行,向量w中的值最終都是不正確的。任何建議將不勝感激。

這是否是一個簡單的矩陣乘法存在一些混淆。不是這樣。這是代碼試圖完成的地方,其中我只包括w的前5項。

w(1)=-g(1); 
w(2)=-g(2); 
w(3)=-g(3); 
w(4)=-g(4); 
w(5)=-g(5); 

w(2)-=h(2)*w(1); 
w(3)-=h(3)*w(1); 
w(4)-=h(4)*w(1); 
w(5)-=h(5)*w(1); 

w(3)-=h(3+N)*w(2); 
w(4)-=h(4+N)*w(2); 
w(5)-=h(5+N)*w(2); 

w(4)-=h(4+2*N)*w(3); 
w(5)-=h(5+2*N)*w(3); 

w(5)-=h(5+3*N)*w(4); 

此外,內核僅在每次程序運行時調用一次。隨機行爲是由多次運行程序產生的。

該評論讓我看到我做錯了什麼。我將工作組和項目配置爲

size_t global_item_size[3] = {N, 1, 1}; // Process the entire lists 
size_t local_item_size[3] = {1,1,1}; // Process in groups of 64 
ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, 
     global_item_size, local_item_size, 0, NULL, NULL); 

它應該是什麼時候。

size_t global_item_size[3] = {N, 1, 1}; // Process the entire lists 
size_t local_item_size[3] = {N,1,1}; // Process in groups of 64 
ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, 
     global_item_size, local_item_size, 0, NULL, NULL); 

感謝您的幫助。這對我來說很好,但可能對其他人不太感興趣。

+0

採取遠離這一切最重要的是,在OpenCL內核的'barrier'功能只會充當工作組,而不是整個設備的屏障。 GPU上的設備範圍同步是一個積極研究的話題。 – KLee1 2012-04-15 07:56:44

回答

0

請問您爲什麼需要內核中的global_id和local_id?

如果您只有一個工作組,那麼local_id應該足夠了。

另外,你爲什麼要將數據從g複製到w?

您是否試圖實現更多的簡單:w = h * g,其中h是矩陣,g是向量?最後,如果您不是簡單地多次重新啓動應用程序,而只是在單個應用程序中多次啓動內核,似乎最可能的解釋是您在某處損壞了內存,即。您正在覆蓋輸入數據。

您可以檢查傳遞給內核的輸入數據是否在相同的運行時保持一致?

+0

我將local_id傳遞迴調用例程,以查看只有一個工作組。這不是一個矩陣乘法。 – 2012-04-14 18:34:33

+0

看到您對原始問題的編輯,我知道其根本原因是您有多個工作組,因此barrier()無法同步屬於不同工作組的工作項目(如KLee1建議的)。您不必擁有1個(屏障同步)64個工作項目的工作組,您有64個(非同步)工作項目的1個工作項目。那是對的嗎? – user1284631 2012-04-20 01:49:07

0

首先你不需要在你的情況下使用CLK_LOCAL_MEM_FENCE。

但是我會推薦給複製

  1. 全局 - 局部數據
  2. 複製本地>本地
  3. 工作 - >全球

在這種情況下,你需要CLK_LOCAL_MEM_FENCE

現在回到你的問題。不能同時

w[i]-=h[i+j*n]*w[j]; 

: 從我所看到的,如果在工作組不同的項目,執行這條線可能會出現問題。設想一個工作項目已經爲w [i]計算了值,然後其他工作項目訪問了w [j]。然後,如果第二個工作項目的「j」與第一個工作項目的「i」相同,則其他工作項目將在其第一個迭代值上使用,該第一個迭代值已由第一個工作項目更新。

你應該做的是下一個(如果你仍然想使用全局內存):

我也採取N個< N(您的工作組大小),否則不同步可能的,因爲你跨越雖然幾個工作組

for (j=0;j<n;j++) 
{ 
    double wj; 
    if (j<i) 
     wj = w[j]; 
    barrier(CLK_GLOBAL_MEM_FENCE); // read_mem_fence(CLK_GLOBAL_MEM_FENCE) is enough 
    if(j<i) 
     w[i]-=h[i+j*n]*wj; 
    barrier(CLK_GLOBAL_MEM_FENCE); // write_mem_fence(CLK_GLOBAL_MEM_FENCE) is enough 
} 

希望這有助於