1

我正在使用新开普勒的 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的新手,所以欢迎对傻瓜进行详细解释

4

1 回答 1

5

warp shuffle 没有破坏性。如果在完全相同的条件下重复该操作,则每次都将返回相同的结果。var值(在您的myreg示例中)不会被 warp shuffle 函数本身修改。

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

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

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

现在让我们看一下您的第一个“破碎”方法:

if (my_reg > __shfl_down(my_reg,8,16)){my_reg = __shfl_down(my_reg,8,16);};

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

您提出的第二种方法没有这样的问题,并且根据您的陈述可以正常工作。所有线程都参与__shfl_down().

于 2014-03-10T15:38:14.560 回答