在OpenCL中使用本地内存的奇怪行为

时间:2010-01-30 15:04:35

标签: opencl

我目前正致力于在NVIDIA Tesla C1060(驱动程序版本195.17)上起诉OpenCL的项目。但是我得到了一些我无法解释的奇怪行为。这是令我困惑的代码(为了清晰度和测试目的而减少):

kernel void TestKernel(global const int* groupOffsets, global       float* result,     
                       local        int* tmpData,             const int    itemcount)
{
   unsigned int groupid    = get_group_id(0);
   unsigned int globalsize = get_global_size(0);
   unsigned int groupcount = get_num_groups(0);

   for(unsigned int id = get_global_id(0); id < itemcount; id += globalsize, groupid += groupcount)
   {
      barrier(CLK_LOCAL_MEM_FENCE);
      if(get_local_id(0) == 0)
         tmpData[0] = groupOffsets[groupid]; 
      barrier(CLK_LOCAL_MEM_FENCE);
      int offset = tmpData[0];
      result[id]   = (float) offset;
   }
}

此代码应将每个工作组的偏移量加载到本地内存中,然后将其读回并将其写入相应的outputvector条目。对于大多数工作项,这是有效的,但对于每个工作组,具有本地ID 1到31的工作项读取的值不正确。 我的输出向量(对于workgroupsize = 128)如下:

index       0: 0
index   1- 31: 470400
index  32-127: 0
index     128: 640
index 129-159: 471040
index 160-255: 640
index     256: 1280
index 257-287: 471680
index 288-511: 1280
...

我预期的输出是

index   0-127: 0
index 128-255: 640
index 256-511: 1280
...

奇怪的是:问题只发生在我使用少于itemcount工作项时(因此当globalsize&gt; = itemcount时它会按预期工作,这意味着每个工作项只处理一个条目)。所以我猜它与循环有关。 有谁知道我做错了什么以及如何解决它?

更新: 我发现如果我改变

它似乎有效
if(get_local_id(0) == 0)
     tmpData[0] = groupOffsets[groupid]; 

if(get_local_id(0) < 32)
     tmpData[0] = groupOffsets[groupid]; 

这让我更加惊讶,所以虽然它可以解决这个问题,但我觉得用这种方式修复它感觉很舒服(因为它可能会破坏其他时间)。 此外,我宁愿避免在运行Geforce 8xxx类硬件时失去性能,因为额外的(据我所知,硬件没有合并)内存访问。 所以问题仍然存在。

1 个答案:

答案 0 :(得分:0)

首先,重要的是,您需要注意itemcount是本地工作大小的倍数,以避免在执行障碍时出现分歧。

  

在处理器上执行内核的工作组中的所有工作项必须先执行此功能,然后才允许继续执行超出障碍的执行。执行内核的工作组中的所有工作项都必须遇到此函数。

您可以按如下方式实现:

unsigned int itemcountrounded = get_local_size(0) * ((itemcount + get_local_size(0) - 1) / get_local_size(0));
for(unsigned int id = get_global_id(0); id < itemcountrounded; id += globalsize, groupid += groupcount)
{
    // ...
    if (id < itemcount)
        result[id]   = (float) offset;
}

你说代码是为了简单而减少了,如果你运行你发布的内容会发生什么?只是想知道你是否也需要把障碍放在全球记忆上。