Cuda 在共享内存中暂存长度不合适的数组

Cuda 在共享内存中暂存长度不合适的数组,cuda,opencl,Cuda,Opencl,x是全局内存中长度为N的数组,由cuda/opencl内核操作,每个线程有k个块(因此k=ceil(N/w))。内核中的每个块都有一个长度为w的本地共享数组xlocal。任务是让每个块将其x块加载到xlocal中 如果w正好除以N,那么我们可以这样做: int lid = threadIdx.x; int gid = threadIdx.x + (blockIdx.x * blockDim.x); xlocal[lid] = x[gid]; 如果没有,则在最后一个块中有(N%w)个冗余线程。我

x是全局内存中长度为N的数组,由cuda/opencl内核操作,每个线程有k个块(因此k=ceil(N/w))。内核中的每个块都有一个长度为w的本地共享数组xlocal。任务是让每个块将其x块加载到xlocal中

如果w正好除以N,那么我们可以这样做:

int lid = threadIdx.x;
int gid = threadIdx.x + (blockIdx.x * blockDim.x);
xlocal[lid] = x[gid];
如果没有,则在最后一个块中有(N%w)个冗余线程。我们应该如何处理它们?我可以想到以下几种选择:

  • Malloc是x的较大长度。也就是说,分配k*w个元素而不是N个。这很有用,因为上面的代码可以正常工作。不幸的是,我不认为cuda或opencl中有realloc等价物

  • 装载前进行范围检查。这是很好的,因为我们不需要乱弄x的分配。但是,仅仅因为边缘条件而向大多数线程添加工作是很烦人的

    if (gid < N) xlocal[lid] = x[gid];
    
  • 关于解决这个问题还有其他想法吗


    一些基准测试 下面是一些比较选项(2)rangecheck(蓝色)和选项(3)加载模N(红色)的结果

    我们将块大小固定为32个线程,并将N从45.6k更改为45.6k+32,以分别在最后一个块中提供0到32个冗余线程。该测试运行一个简单的内核,该内核从全局内存预加载一个共享数组。左侧(/右侧)的图形为每个线程加载一个(/三个)元素。我使用cuda 3.2.16 flags-O2编译,并在特斯拉M2070卡上运行

  • 您可以从主机分配较大的x。然后,您应该考虑额外的复制时间(可能会被引入而没有使用),再加上内存空间。这也会使代码失去意义和结构

  • :

  • 使用此选项,您将向每个线程添加计算gid%N的额外工作(这正是您试图避免的),再加上来自全局内存的额外副本(这可能不会造成太大的伤害,因为副本可能会合并,但仍然如此)

  • 在我看来,2(或者3)是你最好的选择 您只需要向每个线程添加几个指令。考虑到您的代码将保持清晰和自解释性,不必担心太多


    您应该避免选择1。

    谢谢您的想法。我认为您对(2)的直觉是明智的,尽管我可能需要一些时间来对(2)和(3)进行基准测试。我认为仅仅为了每个线程保存几个指令而弄乱代码是不值得的。更重要的是要有一个清晰、易于维护和调试且可重用的代码。令人惊讶的我更关心代码的结构。但这似乎也是每个人都应该关注的。很高兴了解未来。我想你选择了选项2:)。谢谢你。
    xlocal[lid] = x[gid%N];