nvidia kepler洗牌是"破坏性的"吗?

ser*_*lly 1 cuda nvidia kepler

我正在使用新的kepler的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));
Run Code Online (Sandbox Code Playgroud)

我的块是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);};
Run Code Online (Sandbox Code Playgroud)

没有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;};
Run Code Online (Sandbox Code Playgroud)

因此,分配新的tmp变量以潜入相邻寄存器可以为我保存所有内容.现在的问题是:kepler shuffle指令是否具有破坏性?在某种意义上,两次调用相同的指令不会发出相同的结果.我没有给那些说"my_reg> __shfl_down(my_reg,8,16)"的寄存器分配任何东西 - 这加起来让我感到困惑.任何人都可以解释一下两次调用shuffle的问题是什么?我几乎是CUDA的新手,所以欢迎详细解释傻瓜

Rob*_*lla 5

warp shuffle不具有破坏性.如果在完全相同的条件下重复操作,则每次都会返回相同的结果.该var值(myreg在你的例子)没有得到由经随机播放功能本身进行修改.

您遇到的问题是由于__shfl_down() 第一种方法中第二次调用的参与线程数与其他方法中的其他调用次数不同.

首先,让我们提醒自己文档中的一个关键点:

线程只能从另一个主动参与__shfl()命令的线程中读取数据.如果目标线程处于非活动状态,则检索到的值未定义.

现在让我们来看看你的第一个"破碎"方法:

if (my_reg > __shfl_down(my_reg,8,16)){my_reg = __shfl_down(my_reg,8,16);};
Run Code Online (Sandbox Code Playgroud)

第一次调用__shfl_down()上面(在if子句中),所有线程都参与其中.因此,返回的所有值__shfl_down()都将是您所期望的.但是,一旦if子句完成,只有满足if子句的线程才会参与if语句的主体.因此,在__shfl_down()if语句体内的第二次调用中,只有其my_reg值大于my_reg它们上面的线程8通道值的线程才会参与.这意味着其中一些赋值语句可能不会返回您期望的值,因为另一个线程可能没有参与.(上面的8个线程的参与将取决于该线程进行的if比较的结果,这可能是也可能不是.)

您提出的第二种方法没有这样的问题,并根据您的陈述正确工作.所有线程都参与每次调用__shfl_down().