我正在使用新开普勒的 shuffle 指令在 CUDA 上实现并行缩减,类似于: http ://devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/
我正在搜索给定矩阵中的行的最小值,在内核的末尾我有以下代码:
my_register = min(my_register, __shfl_down(my_register,8,16));
my_register = min(my_register, __shfl_down(my_register,4,16));
my_register = min(my_register, __shfl_down(my_register,2,16));
my_register = min(my_register, __shfl_down(my_register,1,16));
我的块是 16*16,所以一切正常,使用该代码,我在同一个内核的两个子行中得到了最小值。
现在我还需要返回矩阵每一行中最小元素的索引,所以我打算用“if”语句替换“min”并以类似的方式处理这些索引,我被困在这段代码中:
if (my_reg > __shfl_down(my_reg,8,16)){my_reg = __shfl_down(my_reg,8,16);};
if (my_reg > __shfl_down(my_reg,4,16)){my_reg = __shfl_down(my_reg,4,16);};
if (my_reg > __shfl_down(my_reg,2,16)){my_reg = __shfl_down(my_reg,2,16);};
if (my_reg > __shfl_down(my_reg,1,16)){my_reg = __shfl_down(my_reg,1,16);};
没有任何 cudaErrors,但内核现在返回垃圾。尽管如此,我已经解决了这个问题:
myreg_tmp = __shfl_down(myreg,8,16);
if (myreg > myreg_tmp){myreg = myreg_tmp;};
myreg_tmp = __shfl_down(myreg,4,16);
if (myreg > myreg_tmp){myreg = myreg_tmp;};
myreg_tmp = __shfl_down(myreg,2,16);
if (myreg > myreg_tmp){myreg = myreg_tmp;};
myreg_tmp = __shfl_down(myreg,1,16);
if (myreg > myreg_tmp){myreg = myreg_tmp;};
因此,分配新的 tmp 变量以潜入相邻的寄存器为我节省了一切。现在的问题是:开普勒洗牌指令是否具有破坏性?从某种意义上说,两次调用相同的指令不会发出相同的结果。我没有为那些说“my_reg > __shfl_down(my_reg,8,16)”的寄存器分配任何东西——这增加了我的困惑。谁能解释我两次调用 shuffle 有什么问题?我几乎是CUDA的新手,所以欢迎对傻瓜进行详细解释