CUDA归约操作中warp shuffle寄存器方案比共享内存慢,是否代码存在问题?
问题解答
代码正确性说明
你的代码功能逻辑没有错误,两个内核输出结果一致即可验证。仅存在一处不影响当前测试结果的冗余操作:reduceShfl 中完成smem[tid] += smem[tid + 32]操作后,多了一次不必要的__syncthreads()调用,该同步对1024线程块的配置无功能影响,但会引入额外开销。
性能差异的核心原因
- 多余同步开销:
reduceShfl比reduceShmUnroll多了一次块级同步操作,而reduceShmUnroll进入最后warp分支后,直接用volatile修饰符保证warp内内存操作可见性,无需额外块级同步,省掉了同步开销。 - 额外数据搬运开销:
reduceShfl在执行shfl指令前,需要将共享内存中的值读取到寄存器变量tmpsum中;而reduceShmUnroll直接在共享内存上完成累加,warp内连续地址的共享内存访问完全无bank冲突,吞吐量和寄存器操作差距极小,反而shfl的跨线程寄存器通信延迟在短路径操作下没有优势。 - 计时方式的放大效应:当前的计时逻辑包含了
cudaMemcpy和CPU端累加的开销,内核本身执行时间占比不高,微小的内核性能差异被放大。如果用nvprof/nsys单独统计内核执行时间,两者的差距会比你当前测试的数值更小。
优化方案
你可以删除reduceShfl中多余的__syncthreads(),同时将最后32个线程的操作合并,省去不必要的共享内存读写:
// 优化后reduceShfl的末尾部分代码 if (tid < 32) { // 直接在寄存器中完成32偏移的累加,不需要额外写回共享内存 int tmpsum = smem[tid] + smem[tid + 32]; tmpsum += __shfl_xor_sync(0xffffffff, tmpsum, 16); tmpsum += __shfl_xor_sync(0xffffffff, tmpsum, 8); tmpsum += __shfl_xor_sync(0xffffffff, tmpsum, 4); tmpsum += __shfl_xor_sync(0xffffffff, tmpsum, 2); tmpsum += __shfl_xor_sync(0xffffffff, tmpsum, 1); if (tid == 0) out[blockIdx.x] = tmpsum; }
优化后reduceShfl的性能会反超reduceShmUnroll。
内容的提问来源于stack exchange,提问作者jake y
相关产品推荐
相关产品推荐

