网站建设报价表下载百度灰色关键词代发
__shfl_down_sync__后各个线程的返回值不同解决
问题描述:
__shfl_down_sync__命令出现warp内各个线程的返回值不同,改成__shfl_xor_sync__解决
原因说明:
在CUDA编程中,__shfl_down_sync
函数在处理越界索引时的行为是有明确规范的,不会自动执行取余操作。根据NVIDIA的官方文档,当目标线程的索引超出warp范围(0-31)时,返回的值是源操作数的值,而不是取余后从其他线程获取的值。
对于您提供的代码:
for (int offset = kWarpSize / 2; offset > 0; offset /= 2) {val = ReductionOp<T>()(val, __shfl_down_sync(0xFFFFFFFF, val, offset));
}
当lane_id=16
且offset=16
时,目标线程索引为16+16=32
,此时__shfl_down_sync
会返回val
的原值(即源操作数),而不是从lane_id=0
获取数据。这确保了在warp边界处不会发生错误或未定义行为。
关键点说明:
- 越界行为:如果
srcLane + delta >= warpSize
,则返回var
的原值。 - 代码正确性:您的代码在这种情况下是安全的,因为越界时操作等价于
val = ReductionOp<T>()(val, val)
,不会引入错误。 - 同步掩码:使用
0xFFFFFFFF
表示所有线程都参与操作,确保warp内所有线程同步。
这种设计使得归约操作可以简洁地处理warp内的所有线程,无需额外的边界检查。
解决方案
广播lane_id=0的值
template<template<typename T> class ReductionOp, typename T>
__device__ __forceinline__ T WarpReduce(T val) {for (int offset = kWarpSize / 2; offset > 0; offset /= 2) {val = ReductionOp<T>()(val, __shfl_down_sync(0xFFFFFFFF, val, offset));}return __shfl_sync(0xFFFFFFFF, val, 0);
}
使用__shfl_xor_sync__
template<template<typename T> class ReductionOp, typename T>
__device__ __forceinline__ T WarpReduce(T val) {for (int offset = kWarpSize / 2; offset > 0; offset /= 2) {val = ReductionOp<T>()(val, __shfl_xor_sync(0xFFFFFFFF, val, offset));}return val;
}