【问题标题】:Cuda thread scheduling - latency hidingCuda 线程调度 - 延迟隐藏
【发布时间】:2016-02-25 13:26:44
【问题描述】:

从全局内存读取的 cuda 线程(或整个 warp)何时被调度程序置于睡眠状态?假设我在读取内存后立即在内核中进行一些计算,这些计算不依赖于读取的数据。这些可以在全局读取的数据还没有的时候执行吗?

【问题讨论】:

    标签: cuda


    【解决方案1】:

    内存读取本身不会导致停顿(除非 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 可能很有趣。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-16
      • 1970-01-01
      • 2015-10-31
      • 2012-02-22
      • 1970-01-01
      • 2018-09-06
      • 2012-05-26
      • 2013-05-27
      相关资源
      最近更新 更多