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