我知道,如果发生分歧,if和else都会在GPU上为每个工作项执行,最后在掩码的帮助下我们选择一个。但我无法理解,如果两者都被执行,那么它如何增加执行单元的空闲性。
我在stackoverflow上经历了一些问题,但是它们并没有涉及它如何影响执行单元的空闲状态。
有人能清楚地向我解释这个概念吗?分歧如何增加执行单位的失速或闲置?
答案 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
执行如下:
if ((threadIdx.x % 2) == 0) // MASK: 11111111 all threads enabled
a = b+c; // MASK: 10101010, only even threads enabled, odd threads idle
a = b*c; // MASK: 01010101, only odd threads enabled, even threads idle
d = a*2 // MASK: 11111111, all threads are enabled again
第4行被称为"恢复点"因为在第1行拆分的控制流合并回这里。在第2行和第3行中,只使用了一半执行单元,其他执行单元保持空闲状态。因此,在执行这些线路期间,GPU的性能减半。