【问题标题】:opencl synchronizationopencl 同步
【发布时间】:2012-04-14 16:58:54
【问题描述】:

我是 opencl 的新手,我似乎不了解屏障功能。这是我的内核的代码。这是一个标准矩阵向量计算,输出为 *w。有1个工作组,64个工作单元,与向量的维数相同

#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);

感谢您的帮助。这对我来说很好,但可能不是很感兴趣 给别人。

【问题讨论】:

  • 重要的是,OpenCL 内核中的barrier 函数只会作为工作组的屏障,而不是整个设备。 GPU 上的设备范围同步是一个积极研究的主题。

标签: opencl


【解决方案1】:

您能否详细说明一下,为什么您的内核中需要 global_id 和 local_id?

如果你只有一个工作组,那么 local_id 就足够了。

还有,为什么要把g中的数据复制到w中呢?

您是否试图实现的不仅仅是简单的:w=h*g,其中 h 是矩阵,g 是向量?

最后,如果您不是简单地多次重新启动您的应用程序,而是您只是在一个应用程序中多次启动内核,似乎最可能的解释是您在某处损坏了内存,即。您正在覆盖输入数据。

能否检查在同一次运行中传递给内核的输入数据是否一致?

【讨论】:

  • 我将 local_id 传递回调用例程,只是为了查看只有一个工作组。这不是矩阵乘法。
  • 看到您对原始问题的编辑,我知道根本原因是您有多个工作组,因此 barrier() 无法同步属于不同工作组的工作项(正如 KLee1 建议的那样)。您拥有 1 个工作项的 64 个(非同步)工作组,而不是 1 个(障碍同步的)工作组(包含 64 个工作项)。对吗?
【解决方案2】:

首先,在您的情况下,您不需要使用 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

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
}

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-21
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    • 2011-08-19
    • 2020-01-04
    • 1970-01-01
    • 2015-07-24
    相关资源
    最近更新 更多