NVIDIA 架构通过为一组称为扭曲的线程发出指令来优化内存吞吐量。如果每个线程访问连续的数据元素或相同的元素,则可以非常有效地执行访问。然而,如果每个线程访问不同缓存行中的数据或同一存储体中不同地址的数据,则存在冲突并且必须重放指令。
inst_executed 是退役指令的计数。inst_issued 是发出的指令数。在向量内存访问、内存地址冲突、内存组冲突等情况下,一条指令可能会被多次发出。每次发出时,都会减少线程掩码,直到所有线程完成为止。
做出这种区别有两个原因: 1. 指令的退出表示数据依赖性的完成。尽管可能重播,但数据依赖性仅解决了 1 次。2. 已发布和已执行之间的比率是显示节省 warp 调度程序发布周期的机会的简单方法。
在 Fermi 和 Kepler SM 中,如果遇到内存冲突,则会重放(重新发出)指令,直到所有线程完成。这是由 warp 调度程序执行的。这些重放会消耗问题周期,从而降低 SM 向数学管道发出指令的能力。在此 SM 中,发出 > 执行表示优化的机会,特别是在发出的 IPC 较高时。
在 Maxwell-Turing SM 中,向量访问的重播、地址冲突和内存冲突由内存单元(共享内存、L1 等)重播,并且不会窃取 warp 调度程序发出周期。在这个SM中,发出的执行很少超过百分之几。
示例:内核加载 32 位值。warp 中的所有 32 个线程均处于活动状态,每个线程访问唯一的缓存行(步长 = 128 字节)。
在 Kepler (CC3.*) SM 上,指令发出 1 次,然后再重播 31 次,因为 Kepler L1 每个请求只能执行 1 次标签查找。
inst_executed = 1 inst_issued = 32
在 Kepler 上,对于 L1 中丢失的每个请求,必须再次重放指令。如果所有线程都未命中 L1 缓存,则
inst_execulated = 1 inst_issued >= 64 = 32 个请求 + 32 个未命中重播
在 Maxwell - Turing 架构上,重放由 SM 内存系统执行。重播可以限制内存吞吐量,但不会阻止 warp 调度程序向数学管道发出指令。
inst_executed = 1 inst_issued = 1
在 Maxwell-Turing Nsight Compute/Perfworks 上,公开每个内存管道的吞吐量计数器,包括由于内存库冲突、原子序列化、地址分歧等导致的周期数。