Cuda __activemask()与选票同步()的比较

Cuda __activemask()与选票同步()的比较,cuda,gpu-warp,Cuda,Gpu Warp,读了CUDA开发者博客上的文章后,我很难理解何时使用\uuuu activemask()代替\uuu ballow\u sync()是安全的\正确的 在“活动掩码查询”一节中,作者写道: 这是不正确的,因为它将导致部分和而不是 总数 之后,在第节“机会主义扭曲级编程”中,他们使用函数\uu activemask(),因为: 如果要在内部使用扭曲级别编程,这可能会很困难 库函数,但不能更改函数接口 CUDA中没有\u活动\u掩码()。这是一个打字错误(在博客文章中)。它应该是\uuu active

读了CUDA开发者博客上的文章后,我很难理解何时使用
\uuuu activemask()
代替
\uuu ballow\u sync()
是安全的\正确的

在“活动掩码查询”一节中,作者写道:

这是不正确的,因为它将导致部分和而不是 总数

之后,在第节“机会主义扭曲级编程”中,他们使用函数
\uu activemask()
,因为:

如果要在内部使用扭曲级别编程,这可能会很困难 库函数,但不能更改函数接口


CUDA中没有
\u活动\u掩码()
。这是一个打字错误(在博客文章中)。它应该是
\uuu activemask()

\uuu activemask()
是。它会问“在这个循环中,扭曲中的哪些线程当前正在执行此指令?”这相当于问“扭曲中的哪些线程当前在这一点上聚合?”

它对收敛没有影响。它不会导致线程聚合。它没有扭曲同步行为

另一方面,
\uu ballow\u sync()
具有收敛行为(根据提供的
掩码

这里的主要区别应该根据Volta warp执行模型来考虑。由于warp执行引擎中的硬件更改,Volta和beyond可以支持warp中的线程在更多的场景中分散,并且比以前的架构支持的时间更长

我们这里所指的分歧是由于先前的条件执行而产生的偶然分歧。由于显式编码而产生的强制发散在Volta之前或之后是相同的

让我们考虑一个例子:

if (threadIdx.x < 1){
   statement_A();}
statement_B();

因此,在伏尔塔之前的情况下,当我们通常不希望在
语句_B()
处出现分歧时,实际上这两个表达式返回相同的值

在Volta执行模型中,我们可以在
语句B()
处偶然出现分歧。因此,这两个表达式可能不会返回相同的结果。为什么?

\uuu\u sync()
指令与所有其他具有掩码参数的CUDA 9+扭曲级内部函数一样,具有同步效果。如果我们有代码强制的分歧,如果掩码参数指示的同步“请求”无法实现(就像上面我们请求完全收敛的情况一样),那么这将表示非法代码

但是,如果我们有偶然的分歧(仅在本例中),则
\u ballot\u sync()
语义首先将扭曲重新聚合到掩码参数请求的程度,然后执行请求的投票操作

\uuu activemask()
操作没有这种重新聚合行为。它只报告当前聚合的线程。如果某些线程因任何原因发散,它们将不会在返回值中报告

如果您随后创建了执行某些扭曲级别操作(如博客文章中建议的扭曲级别总和减少)的代码,并根据
\uuuu activemask()
\uuuu ballow\u sync(0xFFFFFFFF,1)
选择要参与的线程,您可能会得到不同的结果,在偶然出现分歧的情况下。
\uuu activemask()
实现在存在偶然分歧的情况下,将计算不包括所有线程的结果(即,它将计算“部分”和)。另一方面,
选票同步(0xFFFFFFFF,1)
实现,因为它将首先消除偶然的分歧,将强制所有线程参与(计算“总”和)

博客文章中的清单10给出了一个类似的示例和描述

关于“机会主义扭曲级别编程”的博客文章中给出了使用
\uu activemask
的正确示例,如下所示:

此语句表示“告诉我哪些线程聚合”(即
\uu activemask()
请求),然后是“使用(至少)执行
\uuuu match\u all
操作的线程。这是完全合法的,并且将使用在该点上发生聚合的任何线程。如清单9示例所示,在上述步骤中计算的
掩码
将用于唯一的其他warp cooperative原语:

res = __shfl_sync(mask, res, leader); 
(恰好在一段条件代码之后)。这将确定哪些线程可用,然后强制使用这些线程,不管可能存在什么附带的分歧,以产生可预测的结果

作为对
mask
参数用法的补充说明,请注意。特别是,
mask
参数并不打算用作排除方法。如果希望将线程排除在洗牌操作之外,则必须使用条件代码来执行此操作。鉴于m PTX指南:

如果执行线程不在membermask中,则shfl.sync的行为未定义


谢谢你如此详细地回答这个问题,@robercrovella。这里有非常有用的背景资料。
int mask = __ballot_sync(0xFFFFFFFF, 1);
int mask = __match_all_sync(__activemask(), ptr, &pred);
res = __shfl_sync(mask, res, leader);