CUDA:避免在分支发散时串行执行

CUDA: Avoiding serial execution on branch divergence

假设由单个 warp(为简单起见)执行的 CUDA 内核达到 if-else 语句,其中 warp 中的 20 个线程满足 condition 和 32 - 20 = 12 个线程不:

if (condition){
    statement1;     // executed by 20 threads
else{
    statement2;     // executed by 12 threads
}

根据 CUDA C Programming Guide

A warp executes one common instruction at a time [...] if threads of a warp diverge via a data-dependent conditional branch, the warp serially executes each branch path taken, disabling threads that are not on that path, and when all paths complete, the threads converge back to the same execution path.

因此这两个语句将在不同的周期中顺序执行。

Kepler 架构的每个 warp 调度程序包含 2 个指令调度单元,因此能够在每个周期为每个 warp 发出 2 条独立指令。

我的问题是:在这个只有两个分支的设置中,为什么statement1statement2不能由两个指令调度单元发出以供warp内的32个线程同时执行,即 20 个线程执行 statement1 而其他 12 个线程同时执行 statement2?如果指令调度程序不是 warp 一次执行一条公共指令的原因,那是什么?是只提供32线程宽指令的指令集吗?还是硬件相关的原因?

每条内核指令始终针对 warp 中的所有线程执行。因此,逻辑上不可能同时在同一 warp 内的不同线程上执行不同的指令。这将违反构建 GPU 的 SIMT execution model。对于您的问题:

The Kepler architecture contains 2 instruction dispatch units per warp scheduler, and therefore has the ability to issue 2 independent instructions per warp to be at each cycle.

...

why could statement1 and statement2 not be issued by the two instruction dispatch units for simultaneous execution by the 32 threads within the warp, i.e. 20 threads execute statement1 while the 12 others simultaneously execute statement2?

不知道你是否意识到这一点,但是如果statement1statement2在计算上是独立的,那么它们可以在一个周期内执行:

  1. 来自statement1的指令将在所有线程上执行,
  2. 由于第二个调度单元,来自 statement2 的指令将在同一周期内在所有线程上执行,因为它也被调度了。

这就是分支发散在 GPU 中的一般工作方式,可以找到一些进一步的阅读,例如here。因此,我相信您已经免费获得了您所要求的 - 两个语句都在同一周期内执行(或者 can be)。

编辑:

正如 talonmies 在评论中所述,可能值得一提的是条件执行,因为它有时有助于防止分支发散带来的惩罚。可以找到有关此主题的更多信息,例如在 this SO thread 中引用:

For simpler conditionals, NVIDIA GPUs support conditional evaluation at the ALU, which causes no divergence, and for conditionals where the whole warp follows the same path, there is also obviously no penalty.