2012-04-14 59 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 
} 

希望这有助于