我看到很多问题散布在互联网上,关于分支差异,以及如何避免分歧.然而,即使在阅读了几篇关于CUDA如何工作的文章之后,我似乎也无法看到在大多数情况下如何避免分支差异.在有人用伸出的爪子抓住我之前,请允许我描述我认为是"大多数情况".
在我看来,大多数分支差异实例涉及许多真正不同的代码块.例如,我们有以下场景:
if (A):
foo(A)
else:
bar(B)
Run Code Online (Sandbox Code Playgroud)
如果我们有两个线程遇到这种分歧,线程1将首先执行,采用路径A.接下来,线程2将采用路径B.为了消除分歧,我们可能会将上面的块更改为如下所示:
foo(A)
bar(B)
Run Code Online (Sandbox Code Playgroud)
假设foo(A)在线程2和bar(B)线程1上调用是安全的,可能会期望性能得到改善.但是,这是我看到它的方式:
在第一种情况下,线程1和2串行执行.调用这两个时钟周期.
在第二种情况下,线程1和2 foo(A)并行执行,然后bar(B)并行执行.这仍然看起来像两个时钟周期,区别在于在前一种情况下,如果foo(A)涉及从内存中读取,我想线程2可以在该延迟期间开始执行,这导致延迟隐藏.如果是这种情况,分支发散代码更快.
如果您在波前执行工作项并且存在条件,例如:
if(x){
...
}
else{
....
}
Run Code Online (Sandbox Code Playgroud)
工作项执行什么?是这样的情况,波前的所有工作项都将执行第一个分支(即x == true).如果没有x为false的工作项,则跳过其余的条件?
如果一个工作项采用替代路径会发生什么.我是否告诉所有工作项也将执行备用路径(因此执行两个路径?).为什么会出现这种情况,以及如何解决程序执行问题
假设我正在尝试对数组大小n进行简单的缩减,比如保持在一个工作单元内...说添加所有元素.一般策略似乎是在每个GPU上生成许多工作项,这会减少树中的项目.天真地看起来似乎采取了log n步骤,但它并不像第一波线程所有这些线程一次性进行,是吗?它们被安排在经线中.
for(int offset = get_local_size(0) / 2;
offset > 0;
offset >>= 1) {
if (local_index < offset) {
float other = scratch[local_index + offset];
float mine = scratch[local_index];
scratch[local_index] = (mine < other) ? mine : other;
}
barrier(CLK_LOCAL_MEM_FENCE);
}
Run Code Online (Sandbox Code Playgroud)
因此,并行添加了32个项目,然后该线程在屏障处等待.另外32人去,我们在障碍物等待.另外32个,我们在屏障处等待,直到所有线程都完成了必要的n/2次添加以进入树的最顶层,然后我们绕过循环.凉.
这看起来不错,但也许很复杂?我理解指令级并行是一个大问题,所以为什么不产生一个线程并做类似的事情
while(i<array size){
scratch[0] += scratch[i+16]
scratch[1] += scratch[i+17]
scratch[2] += scratch[i+17]
...
i+=16
}
...
int accum = 0;
accum += scratch[0]
accum += scratch[1]
accum += scratch[2]
accum += scratch[3]
...
Run Code Online (Sandbox Code Playgroud)
这样所有的添加都发生在经线内.现在你有一个线程可以保持gpu的忙碌程度.
现在假设指令级并行性不是真的.如下所示,工作大小设置为32(warp数).
for(int i …Run Code Online (Sandbox Code Playgroud) 我正在阅读专业CUDA C编程,并在GPU架构概述部分:
CUDA采用单指令多线程(SIMT)架构来管理和执行32个被称为warp的组中的线程.warp中的所有线程同时执行相同的指令.每个线程都有自己的指令地址计数器和寄存器状态,并对自己的数据执行当前指令.每个SM将分配给它的线程块分区为32线程warp,然后调度它以便在可用的硬件资源上执行.
SIMT架构类似于SIMD(单指令,多数据)架构.SIMD和SIMT都通过向多个执行单元广播相同的指令来实现并行性.一个关键的区别是SIMD要求向量中的所有向量元素在一个统一的同步组中一起执行,而SIMT允许同一warp中的多个线程独立执行.即使warp中的所有线程在同一程序地址处一起启动,单个线程也可能具有不同的行为.SIMT使您能够为独立的标量线程编写线程级并行代码,以及为协调线程编写数据并行代码.SIMT模型包括SIMD不具备的三个关键功能:
➤每个线程都有自己的指令地址计数器.
➤每个线程都有自己的寄存器状态.
➤每个线程都可以有一个独立的执行路径.
第一段提到" All threads in a warp execute the same instruction at the same time.",而在第二段则提到" Even though all threads in a warp start together at the same program address, it is possible for individual threads to have different behavior.".这让我感到困惑,上述陈述似乎是矛盾的.任何人都可以解释一下吗?