Skip to content

Roofline 模型与算力分析

本页速览 Roofline 是分析 GPU 算子性能的统一框架—— attainable FLOPS = min(peak FLOPS, bandwidth × arithmetic_intensity)。本文画一张 Roofline 图,讲清算术强度、拐点、memory-bound vs compute-bound 的判定,并用它诊断 LLM 推理的瓶颈。

Roofline 模型与算力分析

概念定义:一张图看穿算子性能

Roofline 模型(Williams et al., 2009)是分析处理器上算子性能的统一框架——一句话概括:

text
可达算力 ( attainable FLOPS ) = min( Peak 算力 , 带宽 × 算术强度 )

每个算子都能在 Roofline 图上画成一个点。它的位置告诉你:这个算子是被算力卡住还是被带宽卡住,从而决定优化方向。LLM 推理优化 90% 的判断都从画一张 Roofline 图开始——它把"为什么这么慢"从玄学变成定量。

理解 Roofline 的三个关键认知:

  1. 算术强度(Arithmetic Intensity, AI)= FLOPS / Bytes——每读 1 byte 数据能做几次运算。AI 高 → 计算密集;AI 低 → 访存密集;
  2. 每个硬件有一条"屋顶线"——左边斜线段(带宽限制)和右边水平段(算力限制),中间有个拐点(ridge point)
  3. 算子的位置决定瓶颈——AI 在拐点左侧 → memory-bound;右侧 → compute-bound。

一、算术强度:每个算子的"性价比"

算术强度(也叫运算访存比)是 Roofline 的核心量:

text
AI = 总运算量 (FLOPS) / 总数据搬运量 (Bytes)
  • 分子:算子做多少次浮点运算(matmul 是 2MNK、elementwise 是 N);
  • 分母:算子从 HBM 读了多少字节(输入 + 输出)。

LLM 推理中常见算子的 AI

算子运算量数据搬运量算术强度类型
Elementwise add/scaleN3N(2 输入 + 1 输出)~0.33memory-bound
ReLU/GELU~N2N(输入+输出)~0.5memory-bound
LayerNorm~5N2N~2.5memory-bound
Softmax(行向)~5N2N~2.5memory-bound
小 batch decode matmul2·M·N·K(M=1)2·N·K + 2·M·K~1-5memory-bound
大 batch prefill matmul2·M·N·K(M 大)2·N·K + 2·M·K数十-数百compute-bound
大 GEMM(M=N=K=8192, FP16)~10⁹~10⁷几百-几千compute-bound

为什么 decode matmul 是 memory-bound

decode 阶段每次只生成 1 个 token,matmul 的 M 维(batch × 1)= 1,相当于"向量 × 矩阵"。算力只算了一点点(M=1),但权重矩阵 N×K 整个都要从 HBM 读——算力闲置、带宽爆满。详见显存层次与带宽墙

二、Roofline 图:硬件的"性能天花板"

每个 GPU 都有一条专属的 Roofline 线。以 H100 SXM5 为例:

  • 峰值算力(BF16,Tensor Core)≈ 989 TFLOPS = 989 × 10¹² FLOPS/s
  • HBM 带宽 ≈ 3.35 TB/s = 3.35 × 10¹² Bytes/s
  • 拐点 AI = 989 / 3.35 ≈ 295 FLOPS/Byte

画成图:

text
可达算力 (TFLOPS)

1000┤                                  ╱─────────────────  ← 算力天花板(989 TFLOPS)
 900┤                              ╱──
 800┤                          ╱──
 700┤                      ╱──
 600┤                  ╱──
 500┤              ╱──
 400┤          ╱──
 300┤      ╱──  ← 拐点 AI ≈ 295 FLOPS/Byte
 200┤  ╱──
 100┤╱─
   0┼────────────────────────────────────────→ 算术强度 (FLOPS/Byte)
    0    50   100  150  200  300  500  1000
                  (log scale)

图中:

  • 左半段(AI < 295):可达算力 = 带宽 × AI,是斜线(带宽限制段)。算子 AI 越低,算力越跑不满;
  • 右半段(AI > 295):可达算力 = 峰值算力,是水平线(算力限制段)。算子算力被天花板卡住;
  • 拐点(AI = 295):斜线和水平线交汇处,是带宽限制转为算力限制的临界点。

怎么读 Roofline 图

  1. 算算子的 AI:FLOPS / Bytes;
  2. 在图上标出 AI 对应的位置(横坐标);
  3. 从这点向上读可达算力(纵坐标)——这就是这个算子在这块 GPU 上的理论上限;
  4. 实测算力 vs 理论上限:如果实测远低于理论值 → 优化空间在那;如果实测接近理论值 → 已经到顶,得换硬件或换算法。

三、各代 GPU 的 Roofline 参数

不同 GPU 的拐点位置不同——算力涨得快,带宽涨得慢,导致新一代 GPU 拐点右移,越来越多算子变成 memory-bound:

GPU算力(BF16)带宽拐点 AI
A100 80GB312 TF2.0 TB/s156
H100 SXM5989 TF3.35 TB/s295
H200 SXM989 TF4.8 TB/s206
B200 SXM2250 TF (FP4)8 TB/s281

算力涨得快,带宽涨得慢的后果

A100 → H100:算力涨 3 倍,带宽涨 1.7 倍。结果是 H100 上的 decode matmul 比 A100 还更 memory-bound——单纯升级 GPU 不会让 decode 加速 3 倍,可能只快 1.7 倍(带宽限制了)。 这就是为什么 H200 反而比 H100 更适合 LLM 推理——虽然算力没变(989 TF),但带宽从 3.35 涨到 4.8 TB/s,直接缓解了 decode 的带宽墙

四、用 Roofline 诊断 LLM 推理

1. decode 阶段

Llama-2-70B 在 H100 SXM5 上单请求 decode:

  • 每 token 算力消耗:~140 GFLOPS(70B 参数 × 2 FLOPS/参数);
  • 每 token 带宽消耗:140GB 权重 × 2 bytes = 280GB(FP16);
  • AI = 140 / 280 ≈ 0.5 FLOPS/Byte
  • Roofline 上 AI=0.5,对应可达算力 = 3.35TB/s × 0.5 = 1.675 TFLOPS
  • 实际算力(按 50ms/token 算)≈ 140GFLOPS / 50ms = 2.8 TFLOPS
  • 可达上限 1.675 TFLOPS,算力利用率 0.3%(989 TFLOPS 的天花板远未触达)。

诊断结论:强烈 memory-bound,加 GPU 算力没用,必须减带宽压力——上权重量化(W4A16,把 280GB → 70GB,AI 不变但带宽压力降 4 倍)、堆 batch(多个请求共享权重读,AI 随 batch 线性上升)。

2. prefill 阶段

Llama-2-70B 在 H100 SXM5 上单请求 prefill,prompt 长度 2048:

  • 算力消耗:~2 × 2048 × 70B FLOPS ≈ 286 TFLOPS;
  • 带宽消耗:~140GB(权重读一次,prompt 输入可忽略);
  • AI = 286 × 10¹² / 280 × 10⁹ ≈ 1020 FLOPS/Byte
  • Roofline 上 AI=1020,超过拐点 295 → compute-bound
  • 可达算力 = 989 TFLOPS(被算力天花板卡住)。

诊断结论:prefill 是 compute-bound,加算力(升级到 B200)确实有效。这也是为什么 vLLM 把 prefill 和 decode 分开调度——它们瓶颈不同,要分开优化。

3. elementwise 算子

LayerNorm 的 AI ≈ 2.5,远低于拐点 295:

  • 可达算力 = 3.35TB/s × 2.5 ≈ 8.4 TFLOPS(989 TFLOPS 的 0.8%);
  • 实测如果不融合,要多读几遍输入输出——把 3-4 个 elementwise 算子用 算子融合 合一个 kernel,AI 没变但读写次数从 4 倍降到 1 倍,等效带宽 × 4。

五、用 Roofline 选优化策略

Roofline 给的不只是诊断,还有优化路径的优先级:

算子位置AI瓶颈优化方向
左侧远端(AI ≈ 0.5)极低带宽量化减字节数、堆 batch、算子融合
左侧中段(AI ~50)中低带宽算子融合、调 loop order、tiling
拐点附近(AI ~295)临界临界两侧都可优化,看实测离 Roofline 多远
右侧近拐点(AI ~500)中高算力减少计算(蒸馏、剪枝)、用 Tensor Core
右侧远端(AI ~2000)算力换更高算力的硬件、用低精度(FP8/FP4)

通用优化口诀

  • memory-bound 算子:先减字节(量化),再减次数(融合),最后堆 batch(continuous batching);
  • compute-bound 算子:先减算力(蒸馏剪枝),再换更高算力的精度(FP8/FP4),最后升级硬件。

六、Roofline 的局限

Roofline 是简化模型,实际算子还受这些因素影响:

  1. 缓存命中:Roofline 假设所有数据从 HBM 读,但如果命中 L2 cache,实际带宽高得多(甚至接近 SRAM 带宽);
  2. 算子内在并行度:matmul 在 Tensor Core 上跑和纯 CUDA Core 上跑差几十倍,Roofline 不区分;
  3. 指令 mix:一个算子如果是加减乘除混合,可能算力利用率上不去(Tensor Core 只对密集 GEMM 友好);
  4. memory access pattern:coalesced vs random 的带宽差 5-10 倍,Roofline 只算总量没看模式;
  5. 延迟隐藏:GPU 通过多 warp 并发隐藏 HBM 延迟,但 warp 数量不够时也跑不满带宽。

Roofline 是上限不是实测

Roofline 给的是"理论上限"——如果你的算子实测只有 Roofline 上限的 30%,那 70% 是其他因素(cache、warp occupancy、bank conflict、指令 mix)。要追这部分,得上 Nsight Compute 做单算子 profiling。详见GPU 体系结构与优化benchmarking 实践

七、权衡与取舍

  • 理论 vs 实测:Roofline 是起点,告诉你"该优化算力还是带宽",但优化收益多大要看实测;
  • 算力 vs 带宽硬件选择:compute-bound 任务(训练)选高算力卡(B200),memory-bound 任务(LLM 推理)选高带宽卡(H200);
  • 量化 vs 蒸馏:根据算子位置决定——memory-bound 先量化(直接减字节),compute-bound 再考虑蒸馏减计算;
  • 预算分配:小团队先靠软件(vLLM + AWQ + 算子融合)摸到 Roofline 上限,再考虑硬件升级——很多情况下软件优化已经能拿 80% 收益。

延伸阅读

参考资料