代码之家  ›  专栏  ›  技术社区  ›  Jacob Chang

关于树约简中共享内存的问题

  •  0
  • Jacob Chang  · 技术社区  · 2 年前

    NVIDIA第22页 Optimizing Parallel Reduction in CUDA ,

    __device__ void warpReduce(volatile int* sdata, int tid) {
    sdata[tid] += sdata[tid + 32];
    sdata[tid] += sdata[tid + 16];
    sdata[tid] += sdata[tid + 8];
    sdata[tid] += sdata[tid + 4];
    sdata[tid] += sdata[tid + 2];
    sdata[tid] += sdata[tid + 1];
    }
    
    // later…
    for (unsigned int s=blockDim.x/2; s>32; s>>=1) {
    if (tid < s)
        sdata[tid] += sdata[tid + s];
    __syncthreads();
    }
    if (tid < 32) warpReduce(sdata, tid);
    

    我不确定CUDA如何处理函数最后一行中的操作 warpReduce(...) : sdata[tid] += sdata[tid + 1]; . 如果扭曲具有线程ID tid 从0到31,是否 每日三次 此时0和1发生冲突?我的意思是,CUDA将如何选择 sdata[0] += sdata[0 + 1]; sdata[1] += sdata[1 + 1]; ? 如果它运行 sdata[0]+=sdata[0+1]; 首先,结果是正确的。或者,CUDA采取措施防止这种混淆/冲突?

    1 回复  |  直到 2 年前
        1
  •  0
  •   Homer512    2 年前

    那些幻灯片太过时了。自从CUDA-3.0(IIRC)发明了warp shuffle指令以来,在单个warp中使用共享内存进行缩减还不是最先进的。甚至在这一点上,这些都已经过时了。

    这些天你会使用 warp reduce functions 例如 __reduce_add_sync .

    至于为什么上面的模式会起作用:在Volta架构之前,warp中的线程是以锁步方式运行的。他们都会先加载值,然后存储它。因此,不需要同步。这已经改变了。请注意Nvidia的 Volta Tuning Guide

    假设读写对同一个扭曲中的其他线程隐式可见的应用程序需要在通过全局或共享内存在线程之间交换数据的步骤之间插入新的_syncwarp()扭曲宽屏障同步指令。假设代码是在lockstep中执行的,或者从不同线程进行的读/写在一个warp中是可见的,而没有同步,这是无效的。

    您可以在Github存储库中找到更新的示例代码: https://github.com/NVIDIA/cuda-samples

    可能还有更新版本的幻灯片,但我不知道在哪里。