【发布时间】:2016-02-25 13:26:44
【问题描述】:
从全局内存读取的 cuda 线程(或整个 warp)何时被调度程序置于睡眠状态?假设我在读取内存后立即在内核中进行一些计算,这些计算不依赖于读取的数据。这些可以在全局读取的数据还没有的时候执行吗?
【问题讨论】:
标签: cuda
从全局内存读取的 cuda 线程(或整个 warp)何时被调度程序置于睡眠状态?假设我在读取内存后立即在内核中进行一些计算,这些计算不依赖于读取的数据。这些可以在全局读取的数据还没有的时候执行吗?
【问题讨论】:
标签: cuda
内存读取本身不会导致停顿(除非 LD/ST 单元不可用)。
当该内存读取操作的结果需要被另一个操作使用时,就会发生线程停顿。
编译器会意识到这一点,并会尝试对独立 (SASS) 指令重新排序,以便在读取后跟随独立指令。
但是,一旦代码被编译,指令序列就不会改变(CUDA GPU 目前不执行推测执行或乱序执行)。因此,一旦在(SASS)指令流中发生依赖于读取的操作,该线程将停止,直到读取操作完成。 (1)
因此,如果你做了这样的事情:
float a = global_data[idx];
float b = c*d;
a = a*b;
那么上面代码的第一行就不会造成线程停顿了。假设 c 和 d 已准备好/可用,第 2 行不会导致停顿。如果在遇到该行时尚未从全局内存中检索到 a 的值,则第 3 行将导致停顿。 (因为它也依赖于b,所以可能会有一些算术延迟——可能是一个停顿——而b 正在通过乘法管道,但是这个算术延迟可能比全局内存延迟要短得多。)
如前所述,即使您不以这种方式编写代码,编译器通常也会尝试重新排序独立操作,以使情况更有利。例如,如果您这样编写代码:
float b = c*d;
float a = global_data[idx];
a = a*b;
很可能底层的 SASS 代码可能没有显着不同。即使你这样做:
float b = c*d;
float a = global_data[idx]*b;
编译器会将第二行代码分解为(至少)两个独立的操作:将global_data[idx] 加载到寄存器中,然后是乘法操作。同样,任何这些实现中的底层 SASS 代码可能没有本质上的不同。
(1) Fermi cc2.1 和 cc3.x 及更高版本的 SM 通常具有多个问题的能力,即。超标量运算。这意味着来自同一个指令流的多个(独立 SASS)指令,对于同一个 warp,可以在受资源限制和限制的同一个周期内调度。我不认为这样的多问题案例与关于投机或 OOO 执行的陈述相矛盾,我不认为这会对上述讨论产生重大影响。一旦线程停止,即在指令调度机制的范围内发出指令的机会已经“枯竭”,那么在停止停止之前不能/将调度更多的指令。多问题机制的功能和限制的低级细节未发布 AFAIK。
幻灯片 14 here 可能很有趣。
【讨论】: