CUDA:避免在分支差异上执行串行执行

lod*_*dhb 2 c++ cuda simd

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

if (condition){
    statement1;     // executed by 20 threads
else{
    statement2;     // executed by 12 threads
}
Run Code Online (Sandbox Code Playgroud)

根据CUDA C编程指南:

如果warp的线程经由数据相关的条件分支发散,则warp一次执行一条公共指令,warp串行执行所采用的每个分支路径,禁用不在该路径上的线程,以及所有路径完成后,线程会聚回同一个执行路径.

因此,这两个语句将在不同的循环中顺序执行.

Kepler体系结构每个warp调度程序包含2个指令调度单元,因此能够在每个周期发出每个warp 2个独立指令.

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

Mic*_*ala 6

始终对warp中的所有线程执行每个内核指令.因此,逻辑上不可能同时在同一个warp中的不同线程上执行不同的指令.这将违背构建 GPU 的SIMT执行模型.对于你的问题:

Kepler体系结构每个warp调度程序包含2个指令调度单元,因此能够在每个周期发出每个warp 2个独立指令.

...

为什么statement1和statement2不能由两个指令调度单元发出,以便由warp中的32个线程同时执行,即20个线程执行statement1而另外12个线程同时执行statement2?

我不确定你是否意识到这一点,但如果statement1并且statement2在计算上是独立的,那么它们可以在一个循环中执行:

  1. statement1将在所有线程上执行指令,
  2. statement2由于第二个调度单元,将在与调度相同的周期内的所有线程上执行指令.

这就是分支发散在GPU中的工作原理,一些进一步的读取可以在这里找到.因此,我相信您已经获得了免费的要求 - 两个语句都在同一个周期内执行(或者可以).

编辑:

正如评论中所说的talonmies,值得一提的是条件执行,因为它有时有助于防止分支分歧的惩罚.有关此主题的更多信息可以在例如此SO线程中找到,引用:

对于更简单的条件,NVIDIA GPU支持ALU的条件评估,这不会引起分歧,对于整个warp遵循相同路径的条件,显然也没有惩罚.

  • 可能值得一提的是硬件支持有条件预测的指令,并且编译器通常更喜欢条件执行而不是分支发散以用于短代码段. (4认同)