GPGPU中的分歧

时间:2015-08-19 03:27:06

标签: cuda opencl gpgpu

我知道,如果发生分歧,if和else都会在GPU上为每个工作项执行,最后在掩码的帮助下我们选择一个。但我无法理解,如果两者都被执行,那么它如何增加执行单元的空闲性。

我在stackoverflow上经历了一些问题,但是它们并没有涉及它如何影响执行单元的空闲状态。

有人能清楚地向我解释这个概念吗?分歧如何增加执行单位的失速或闲置?

2 个答案:

答案 0 :(得分:2)

与@Mai Longdong讨论后几点: 执行单元的空闲时间:是执行单元没有做任何有用工作的时间。

在每个循环中,warp最多可以在一个指令上执行最多32个数据元素(或者任何经线宽度)。如果需要执行两个不同的指令(如warp divergent branches的情况),则需要在两个周期内发出这些指令。

当我们使用if和else时,为整个warp执行两个分支。但是如果第一个线程接受一个if然后它被禁用而其他的warp接受了else。在经线的其余部分完成其他操作之前,它不会做任何事情。这可以被视为浪费执行单元(与分支较少的代码相比)。当第一个线程将执行时,其他线程将被禁用。这导致有用工作量减少,因此执行单元的空闲时间增加。

如果warp中的所有32个项目仅在条件路径或条件路径中执行,则执行单元的空闲时间不会增加。您可以参考here

上的讨论

答案 1 :(得分:1)

在执行两个代码路径以选择一个结果后,不使用掩码,但在执行期间使用不同的掩码,以仅启用当前warp中当前执行的代码路径中处于活动状态的线程。

让我们看一个8宽SIMD单元的小例子(真正的GPU SIMD单元是32(NVidia)或64-ops(AMD GCN)宽):

if ((threadIdx.x % 2) == 0)   
{
   a = b+c;   // Even threads
} else
   a = b*c;   // Odd threads
}
d = a*2

执行如下:

  1. if ((threadIdx.x % 2) == 0) // MASK: 11111111 all threads enabled

  2. a = b+c; // MASK: 10101010, only even threads enabled, odd threads idle

  3. a = b*c; // MASK: 01010101, only odd threads enabled, even threads idle

  4. d = a*2 // MASK: 11111111, all threads are enabled again

  5. 第4行被称为"恢复点"因为在第1行拆分的控制流合并回这里。在第2行和第3行中,只使用了一半执行单元,其他执行单元保持空闲状态。因此,在执行这些线路期间,GPU的性能减半。