【问题标题】:Issued load/store instructions for replay发布了重放的加载/存储指令
【发布时间】:2019-08-14 09:56:13
【问题描述】:

关于加载/存储指令有两个nvprof 指标,它们是ldst_executedldst_issued。我们知道executed<=issued。我希望那些发出但未执行的加载/存储与分支预测和其他不正确的预测有关。但是,从this (slide 9) 文档和this 主题来看,已发出但未执行的指令与序列化和重放有关。

我不知道这个原因是否适用于加载/存储指令。此外,我想知道为什么这样的术语用于已发出但未执行的指令?如果出于某种原因存在序列化,则会多次执行指令。那么,为什么不计入executed呢?

对此有何解释?

【问题讨论】:

    标签: cuda nvidia nvprof


    【解决方案1】:

    NVIDIA 架构通过为一组称为 warp 的线程发出指令来优化内存吞吐量。如果每个线程访问一个连续的数据元素或相同的元素,那么访问可以非常有效地执行。但是,如果每个线程访问不同高速缓存行中的数据或同一存储区中不同地址的数据,则会发生冲突,并且必须重播指令。

    inst_executed 是退役指令的计数。 inst_issued 是发出的指令计数。在向量内存访问、内存地址冲突、内存库冲突等情况下,一条指令可能会被多次发出。在每次发出时,线程掩码都会减少,直到所有线程都完成。

    区分有两个原因: 1. 指令的退出表示数据依赖的完成。尽管可能重播,但数据依赖性仅解决了 1 次。 2.发出和执行之间的比率是显示节省warp调度程序发出周期机会的简单方法。

    在 Fermi 和 Kepler SM 中,如果遇到内存冲突,则重播(重新发出)指令,直到所有线程完成。这是由 warp 调度程序执行的。这些回放消耗了发布周期,降低了 SM 向数学管道发布指令的能力。在此 SM 中,已发布 > 已执行表示优化的机会,尤其是在已发布 IPC 较高的情况下。

    在向量访问的 Maxwell-Turing SM 重放中,地址冲突和内存冲突由内存单元(共享内存、L1 等)重放,并且不会窃取 warp 调度程序发出周期。在这个 SM 中发布的很少超过执行的几个 %。

    示例:内核加载 32 位值。 warp 中的所有 32 个线程都处于活动状态,每个线程都访问一个唯一的缓存行(stride = 128 字节)。

    在 Kepler (CC3.*) SM 上,指令发出 1 次,然后再重放 31 次,因为 Kepler L1 每个请求只能执行 1 个标签查找。

    inst_executed = 1 inst_issued = 32

    在 Kepler 上,必须为 L1 中丢失的每个请求再次重播该指令。如果所有线程都在 L1 缓存中丢失,那么

    inst_executed = 1 inst_issued >= 64 = 32 次请求 + 32 次未命中重播

    在 Maxwell - Turing 架构上,回放由 SM 内存系统执行。回放可以限制内存吞吐量,但不会阻止 warp 调度程序向数学管道发出指令。

    inst_executed = 1 inst_issued = 1

    在 Maxwell-Turing Nsight Compute/Perfworks 上公开每个内存管道的吞吐量计数器,包括由于内存库冲突、原子序列化、地址分歧等导致的周期数。

    【讨论】:

    • 除了银行冲突之外,由于 MSHR 中用于提供即时缓存未命中的条目数量有限,是否可以重播?我的意思是内存冲突以外的原因。
    • 在 CC 32 位)、地址分歧、完整的写入缓冲区、完整的未决未命中表,将原子/归约序列化到同一地址,安排重播以在完成时读取 l1 未命中,...
    • 谢谢。似乎 CC>7 的 nsight 缺少这样的指标 (docs.nvidia.com/nsight-compute/NsightComputeCli/…),其中发出和执行的 ldst 指令都是不适用的。我们要等到将来的版本发布吗?还是有别的?
    【解决方案2】:

    GPU 架构基于最大化吞吐量而不是最小化延迟。因此,GPU(当前)并没有真正进行乱序执行或分支预测。 GPU 不是构建几个充满复杂控制逻辑的内核来使一个线程运行得非常快(就像你在 CPU 上那样),而是使用这些晶体管来构建更多的内核来并行运行尽可能多的线程。

    正如您链接的演示文稿的幻灯片 9 中所解释的,已执行指令是控制流在您的程序中传递的指令(基本上是运行的汇编代码行数)。例如,当您执行全局加载指令并且无法立即处理内存请求(错过缓存)时,GPU 将切换到另一个线程。一旦值在缓存中准备好并且 GPU 切换回您的线程,则必须再次发出加载指令以完成获取值(另请参见 this answerthis thread)。例如,当您访问共享内存并且存在银行冲突时,共享内存访问将不得不为 warp 中的不同线程重播多次......

    区分已执行指令和已发出指令的主要原因似乎是,两者的比率可以用来衡量由于指令在执行时无法立即完成而产生的代码开销量…

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-03
      • 2018-11-28
      • 1970-01-01
      • 2016-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多