opencl同步

opencl同步,opencl,Opencl,我是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) { //

我是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中的值最终都不正确。如有任何建议,将不胜感激

对于这是否是一个简单的矩阵乘法,存在一些混淆。事实并非如此。这就是代码试图实现的,我只包括了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);
谢谢你的帮助。这对我来说很好,但可能不太感兴趣
给其他人。

请详细说明,为什么内核中同时需要全局id和本地id

如果您只有一个工作组,那么本地id就足够了

另外,为什么要将数据从g复制到w

你是不是想得到的不仅仅是:w=h*g,其中h是矩阵,g是向量

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


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

首先,您不需要在本例中使用CLK\U LOCAL\U MEM\U FENCE

不过,我建议复制

全局->本地 使用本地数据 复制本地->全局 在这种情况下,您需要CLK_LOCAL_MEM_围栏

现在回到你的问题上来。 据我所见,若工作组中的不同项目执行此行,则可能会出现问题:

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
}

希望这有帮助

我将本地id传递回调用例程,只是为了查看只有一个工作组。这不是矩阵乘法。看到您对原始问题的编辑,我了解到根本原因是您有多个工作组,因此barrier无法按照KLee1的建议同步属于不同工作组的工作项。您有64个工作项的64个未同步工作组,而不是1个工作项的1个已同步工作组。这是正确的吗?重要的是,OpenCL内核中的barrier函数将只作为工作组的屏障,而不是整个设备的屏障。GPU上的设备范围同步是一个活跃的研究主题。
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
}