计算受限与内存受限
说明:本文翻译自 CisMine Ng 在 Level Up Coding 发表的博客 Compute Bound & Memory Bound,版权归原作者所有。
在任何一个程序中,我们都需要做两件事:
- 从内存中取出数据。
- 对数据执行计算。
或者说:当讨论一段代码的性能时,我们主要考虑两个概念:内存和计算。
什么是内存和计算?为什么它们如此重要?
内存 — 计算
- 计算(Computation):指计算能力,通常用一个流行的指标来衡量,即 FLOPS 率(floating point operations per second,每秒浮点运算次数)。它量化了计算机在一秒内执行浮点运算的性能:
图:FLOPS(计算能力)示意图
- 内存(Memory):这里指的不是总内存容量,而是 内存带宽(GB/s),即数据在内存与处理单元之间加载或存储的速率:
图:内存带宽示意图
如何确定一个良好的 FLOPS 率或内存带宽?
期望的计算与内存比率(OP/B)
这是一个关键指标,用于平衡计算机的处理能力与其内存的加载/存储能力。
图:OP/B 比率示意图
为什么要平衡它们?——平衡能确保硬件资源得到高效利用,避免性能瓶颈。
- 如果 OP/B 偏低:系统在处理繁重的计算任务,但计算能力有限,这会导致计算受限(compute-bound)的情形。
- 如果 OP/B 偏高:系统无法提供足够的数据供处理,导致数据饥饿(data starvation),即内存受限(memory-bound)的情形。
什么是计算/内存受限?如何识别并解决它们?
- 计算受限(Compute-bound):当计算机的性能受限于其计算能力时发生,在执行复杂计算时很常见。
- 内存受限(Memory-bound):当性能受限于从内存访问数据的能力时发生,通常在处理大量数据的加载/存储操作时出现。
在代码中识别计算/内存受限
光速吞吐量(Speed Of Light Throughput, SoL)
图:Nsight Compute 中的 SoL 示例
Nsight Compute 可以利用 SoL 帮助我们识别代码是计算受限还是内存受限。
SoL:实际利用率相对于理论上限的百分比,它反映的是计算机硬件的活跃程度,而不是代码本身的性能。
我们的目标是确保计算和内存资源得到均衡利用,避免显著失衡。
- 均衡利用可以防止瓶颈,即避免某一资源(计算或内存)成为整体性能的限制因素。
- 均衡利用还能最大限度地提高硬件效率,使实际性能更接近理论峰值性能。
图:SoL 的四种典型情况
延迟(Latency)(M 与 SM 均 < 60%): 如上所述,SoL 反映的是计算机的活跃程度。但在这种情况下,我们可以看到 M(内存)和 SM(计算)都没有得到充分利用。这表明系统没有充分利用可用资源,可能意味着工作负载不够重,不足以压满硬件。
计算受限(Compute Bound)(SM > 60% 或 M < 60%): 这种情况表明,系统虽然拥有足够的计算能力来处理数据,但计算单元被复杂的运算过度占用,导致计算受限。
内存受限(Memory Bound)(SM < 60% 或 M > 60%): 这会导致数据饥饿,即系统无法及时为计算资源提供足够的数据,尽管计算本身可能很简单。
计算/内存同时受限(Compute/Memory Bound)(SM 与 M 均 > 60%): 在这种情况下,系统的计算和内存都处于高负载运行,需要仔细监控性能,以避免潜在的瓶颈。
图:Nsight Compute 中的资源利用率汇总界面
总之,上述每种情况都反映了不同类型的资源失衡:
- 延迟(Latency):两种资源利用率都很低。
- 计算受限(Compute Bound):计算过度使用,而内存利用不足。
- 内存受限(Memory Bound):内存利用率高,而计算利用不足。
- 均衡利用(Balanced Usage):计算和内存都得到优化利用,或两者同时达到性能上限。
在 Nsight Compute 中,可以通过以下两个指标来判断瓶颈类型:
- SM: Inst Executed Pipe Lsu(%)(SM 执行的 LSU 指令流水线利用率):如果这个百分比很高(出现在 SM 侧而非计算侧),说明加载/存储单元耗时较大。
- SM: Pipe Fma/Alu Cycles Active (%)(SM 的 FMA/ALU 流水线活跃周期):SM 计算活跃度百分比。
Roofline 模型(Roofline chart)
图:Nsight Compute 中的 Roofline 图
Nsight Compute 可以利用 Roofline 图帮助我们识别代码是计算受限还是内存受限。
在深入讲解 Roofline 图之前,先介绍你需要了解的定义。
- 算术强度(Arithmetic Intensity):一个衡量计算资源(FLOP,浮点运算次数)与内存带宽(传输的数据字节数)利用效率的指标:
图:算术强度定义示意图
我们知道,数学运算比内存访问快得多,因此需要合理平衡这一比率,以避免内存/计算受限的情况。每台计算机的这一比率都不同,要确定它,可以点击图中所示的方块。
图:如何查看本机的计算与内存比率
我们详细分析一下这张图:
图:Roofline 图(来源:NERSC Roofline 文档)
- 峰值 FLOP/s(Peak FLOP/s):计算机所能达到的最大计算速度。
- 带宽 GB/s(Bandwidth GB/s):计算机加载/存储内存的速率,在红线与蓝线相交处达到峰值。该点称为关键点(key point)或拐点(knee point)。
关键点(拐点):两个阶段之间发生转变的点:
- 内存受限阶段。
- 计算受限阶段。
理论上:如果我们达到关键点比率(如图所示,AI = 0.55),意味着我们的代码近乎完美(在计算与内存之间取得了平衡)。
实践中:达到图中对角线上的某一点就已经是非常好的结果。
瓶颈情形:
(FLOP/s):表示执行一个任务的速度。 (峰值):计算机理论上能达到的最大计算速度。 (FLOP/byte × byte/s):运行特定代码所需的实际速度。
图:求取
的公式
当我们用 min 函数判断系统是计算受限还是内存受限时:
- 如果
是 min中的较小项 → 计算受限:这意味着运行代码所需的实际速度更高,但计算机受限于峰值计算速度,无法超越它。解决方案:使用更大的单元尺寸(unit size)。 - 如果
是 min中的较小项 → 内存受限:这表明我们尚未充分利用计算机的能力。解决方案:使用粗化(coarsening)策略。
因此,通过这两个方面,我们可以判断代码是存在计算问题,还是加载/存储数据的问题。在接下来的文章中,我将指导你如何针对每种情况具体解决。
参考
- NERSC — Introduction to the Roofline Model
- ANU — Performance Analysis with the Roofline Model (CPU & GPU)
- NHR@FAU — Introduction to Performance Analysis for NVIDIA GPUs