在OpenCL中执行扫描

在OpenCL中执行扫描,opencl,Opencl,很长一段时间以来,我一直在尝试进行一次简单的扫描。对于小问题,输出是正确的,但是对于大输出,我只是有时得到正确的结果。我已经检查过了,我基本上也在做同样的事情(除了银行冲突,我忽略了atm)。这是第一阶段的代码: __kernel void scan_init(__global int * input, __global int * sums) { int gid = get_global_id(0); int lid = get_local_id(0); int

很长一段时间以来,我一直在尝试进行一次简单的扫描。对于小问题,输出是正确的,但是对于大输出,我只是有时得到正确的结果。我已经检查过了,我基本上也在做同样的事情(除了银行冲突,我忽略了atm)。这是第一阶段的代码:

__kernel void
scan_init(__global int * input,
          __global int * sums)
{
  int gid = get_global_id(0);
  int lid = get_local_id(0);
  int chunk_size = get_local_size(0)*2;

  int chunk = gid/chunk_size;
  int offset = chunk*chunk_size;

  reduction(input, offset);

  // store sums
  if(lid==0)
  {
    sums[chunk] = input[(chunk+1)*chunk_size-1];
  }

  downsweep(input, offset);
}
以及还原函数本身:

void reduction(__global int * input,
      int offset)
{
 int stride = 1;
 int grp_size = get_local_size(0);
 int lid = get_local_id(0);

 for(int d = grp_size; d > 0; d>>=1)
 {
   barrier(CLK_GLOBAL_MEM_FENCE);

   if(lid < d)
   {
     int ai = stride*(2*lid+1)-1+offset;
     int bi = stride*(2*lid+2)-1+offset;
     input[bi] += input[ai];
   }

   stride *= 2;
  }
}
然而,预期的结果将是

0:1024  1:1024  2:1024  3:928 
如果我再次运行代码,我会得到:

0:1056  1:5376  2:1024  3:928 
0:1024  1:1088  2:1280  3:992 
0:5944  1:11156 2:3662  3:1900  
0:7872  1:1056  2:2111  3:1248  
对内核的调用如下所示:

clEnqueueNDRangeKernel(cl_ctx->queue, scan_init, 1, NULL, &scan_global_size, &local_work_size, 0, NULL, NULL);
其中全局大小为4096,局部大小为512。如果将本地工作组大小限制为64,则输出如下所示:

0:128  1:128  2:128  3:288  4:128  5:128  6:192  7:192  
8:192  9:254  10:128  11:256  12:128  13:360  14:128  15:128  
16:128  17:128  18:128  19:288  20:128  21:128  22:128  23:128  
24:192  25:128  26:128  27:192  28:128  29:128  30:128  31:32 
如果我将输入大小更改为512和任何块大小,一切都会很好

最后,当使用输入大小513和组大小256(即,我有两个块,每个块有512个元素,第二个块只有第一个元素设置为1)时,第一阶段的结果是:

0:1  1:2  2:1  3:6  4:1  5:2  6:1  7:14  
8:1  9:2  10:1  11:6  12:1  13:2  14:1  15:28  
16:1  17:2  18:1  19:6  20:1  21:2  22:1  23:14  
24:1  25:2  26:1  27:6  28:1  29:2  30:1  31:56  
32:1  33:2  34:1  35:6  36:1  37:2  38:1  39:14  
40:1  41:2  42:1  43:6  44:1  45:2  46:1  47:28  
48:1  49:2  50:1  51:6  52:1  53:2  54:1  55:14  
56:1  57:2  58:1  59:6  60:1  61:2  62:1  63:148   
应在哪里:

0:1  1:2  2:1  3:4  4:1  5:2  6:1  7:8  
8:1  9:2  10:1  11:4  12:1  13:2  14:1  15:16  
16:1  17:2  18:1  19:4  20:1  21:2  22:1  23:8  
24:1  25:2  26:1  27:4  28:1  29:2  30:1  31:32  
32:1  33:2  34:1  35:4  36:1  37:2  38:1  39:8  
40:1  41:2  42:1  43:4  44:1  45:2  46:1  47:16  
48:1  49:2  50:1  51:4  52:1  53:2  54:1  55:8  
56:1  57:2  58:1  59:4  60:1  61:2  62:1  63:64 

我的猜测是,不同线程并发访问相同的数据是一个问题,然而,情况不应该是这样,因为每个工作组都在处理不同的输入数据块。在此问题上的任何帮助都将不胜感激

我怀疑问题与barrier()不是工作组间同步有关。每个工作组都有自己的障碍,您无法保证工作组本身的顺序。当您将输入集大小更改为512时,您可能会使所有工作组在同一个多处理器上运行,因此顺便同步

您的chunk变量是get_group_id(0)/2,这意味着您已将两个完整的工作组分配给同一个chunk。你可能想反过来。如果它们碰巧在lockstep中运行,它们将简单地覆盖彼此的工作,因为它们的负载存储依赖项将匹配。否则,它们可能会干扰,也可能不会干扰,总是在多次求和值的方向上

在这个问题上,你的问题本身就暗示了一点:“每个工作组可以扫描两倍大小的块。”这意味着总工作大小为数组大小的一半就足够了


downsweep()中的循环也有一个奇怪之处;lid+1>=1,d从1开始。这可能是一个无关紧要的多余迭代,但在计划中是一个一个的过程。

我怀疑问题与barrier()不是工作组间同步有关。每个工作组都有自己的障碍,您无法保证工作组本身的顺序。当您将输入集大小更改为512时,您可能会使所有工作组在同一个多处理器上运行,因此顺便同步

您的chunk变量是get_group_id(0)/2,这意味着您已将两个完整的工作组分配给同一个chunk。你可能想反过来。如果它们碰巧在lockstep中运行,它们将简单地覆盖彼此的工作,因为它们的负载存储依赖项将匹配。否则,它们可能会干扰,也可能不会干扰,总是在多次求和值的方向上

在这个问题上,你的问题本身就暗示了一点:“每个工作组可以扫描两倍大小的块。”这意味着总工作大小为数组大小的一半就足够了


downsweep()中的循环也有一个奇怪之处;lid+1>=1,d从1开始。这可能是一个无关紧要的多余迭代,但在计划中却是一次又一次的失败。

好吧,既然你已经指出了这一点,这是非常明显的!在计算全局工作大小和块时,我有点忘记了这个细节。我已经重新做了,现在它的工作非常好!非常感谢你发现了这一点。关于downsweep循环中的“奇怪之处”:是的,我知道了void循环运行,现在其他一切都正常了,我将修复它。好吧,现在你已经指出了,这是非常明显的!在计算全局工作大小和块时,我有点忘记了这个细节。我已经重新做了,现在它的工作非常好!非常感谢你发现了这一点。至于downsweep循环中的“奇怪之处”:是的,我知道了void循环运行,现在所有其他操作都在运行,我将修复它。
0:1  1:2  2:1  3:6  4:1  5:2  6:1  7:14  
8:1  9:2  10:1  11:6  12:1  13:2  14:1  15:28  
16:1  17:2  18:1  19:6  20:1  21:2  22:1  23:14  
24:1  25:2  26:1  27:6  28:1  29:2  30:1  31:56  
32:1  33:2  34:1  35:6  36:1  37:2  38:1  39:14  
40:1  41:2  42:1  43:6  44:1  45:2  46:1  47:28  
48:1  49:2  50:1  51:6  52:1  53:2  54:1  55:14  
56:1  57:2  58:1  59:6  60:1  61:2  62:1  63:148   
0:1  1:2  2:1  3:4  4:1  5:2  6:1  7:8  
8:1  9:2  10:1  11:4  12:1  13:2  14:1  15:16  
16:1  17:2  18:1  19:4  20:1  21:2  22:1  23:8  
24:1  25:2  26:1  27:4  28:1  29:2  30:1  31:32  
32:1  33:2  34:1  35:4  36:1  37:2  38:1  39:8  
40:1  41:2  42:1  43:4  44:1  45:2  46:1  47:16  
48:1  49:2  50:1  51:4  52:1  53:2  54:1  55:8  
56:1  57:2  58:1  59:4  60:1  61:2  62:1  63:64