title: 什么是延迟隐藏?

延迟隐藏是一种通过并发运行多个长延迟操作来掩盖长延迟操作的策略。

高性能 GPU 程序通过交错执行多个线程 (thread) 来隐藏延迟。这使得程序即使面对较长的指令延迟也能保持高吞吐量。当一个线程束 (warp) 因慢速内存操作而停顿 (stall) 时,GPU 会立即切换到执行另一个符合条件的线程束 (eligible warp) 的指令。

这使得所有执行单元都能保持并发忙碌状态。当一个线程束 (warp) 使用张量核心 (Tensor Core) 进行矩阵乘法时,另一个线程束可能在 CUDA 核心 (CUDA Core) 上执行算术运算(例如,对矩阵乘数进行量化或反量化),而第三个线程束可能正在通过加载/存储单元 (load/store unit) 获取数据。

具体来说,考虑以下流式汇编器 (Streaming Assembler) 中的简单指令序列。

LDG.E.SYS R1, [R0]        // 内存加载,400 个周期
IMUL R2, R1, 0xBEEF       // 整数乘法,6 个周期
IADD R4, R2, 0xAFFE       // 整数加法,4 个周期
IMUL R6, R4, 0x1337       // 整数乘法,6 个周期

如果顺序执行,这将需要 416 个周期才能完成。我们可以通过并发操作来隐藏这种延迟。如果我们假设每个周期可以发射一条指令,那么根据利特尔定律 (Little's Law),如果我们运行 416 个并发线程 (thread),我们仍然可以平均每个周期完成一次该序列,从而对使用 R6 中数据的消费者隐藏了内存延迟。

请注意,指令发射的单位不是线程 (thread),而是线程束 (warp)。每个线程束 (warp) 包含 32 个线程 (thread),因此我们的代码片段需要 416 ÷ 32 = 13 个线程束 (warp)。当成功隐藏延迟时,GPU 的调度系统会维持这么多线程束 (warp) 在执行中,每当一个线程束停顿时就在它们之间切换,确保执行单元在等待慢速操作完成时永远不会空闲。

要深入了解张量核心 (Tensor Core) 出现之前的 GPU 上的延迟隐藏,请参阅 Vasily Volkov 的博士论文