外观
Roofline 模型与算力分析
概念定义:一张图看穿算子性能
Roofline 模型(Williams et al., 2009)是分析处理器上算子性能的统一框架——一句话概括:
text
可达算力 ( attainable FLOPS ) = min( Peak 算力 , 带宽 × 算术强度 )每个算子都能在 Roofline 图上画成一个点。它的位置告诉你:这个算子是被算力卡住还是被带宽卡住,从而决定优化方向。LLM 推理优化 90% 的判断都从画一张 Roofline 图开始——它把"为什么这么慢"从玄学变成定量。
理解 Roofline 的三个关键认知:
- 算术强度(Arithmetic Intensity, AI)= FLOPS / Bytes——每读 1 byte 数据能做几次运算。AI 高 → 计算密集;AI 低 → 访存密集;
- 每个硬件有一条"屋顶线"——左边斜线段(带宽限制)和右边水平段(算力限制),中间有个拐点(ridge point);
- 算子的位置决定瓶颈——AI 在拐点左侧 → memory-bound;右侧 → compute-bound。
一、算术强度:每个算子的"性价比"
算术强度(也叫运算访存比)是 Roofline 的核心量:
text
AI = 总运算量 (FLOPS) / 总数据搬运量 (Bytes)- 分子:算子做多少次浮点运算(matmul 是 2MNK、elementwise 是 N);
- 分母:算子从 HBM 读了多少字节(输入 + 输出)。
LLM 推理中常见算子的 AI
| 算子 | 运算量 | 数据搬运量 | 算术强度 | 类型 |
|---|---|---|---|---|
| Elementwise add/scale | N | 3N(2 输入 + 1 输出) | ~0.33 | memory-bound |
| ReLU/GELU | ~N | 2N(输入+输出) | ~0.5 | memory-bound |
| LayerNorm | ~5N | 2N | ~2.5 | memory-bound |
| Softmax(行向) | ~5N | 2N | ~2.5 | memory-bound |
| 小 batch decode matmul | 2·M·N·K(M=1) | 2·N·K + 2·M·K | ~1-5 | memory-bound |
| 大 batch prefill matmul | 2·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 图
- 算算子的 AI:FLOPS / Bytes;
- 在图上标出 AI 对应的位置(横坐标);
- 从这点向上读可达算力(纵坐标)——这就是这个算子在这块 GPU 上的理论上限;
- 实测算力 vs 理论上限:如果实测远低于理论值 → 优化空间在那;如果实测接近理论值 → 已经到顶,得换硬件或换算法。
三、各代 GPU 的 Roofline 参数
不同 GPU 的拐点位置不同——算力涨得快,带宽涨得慢,导致新一代 GPU 拐点右移,越来越多算子变成 memory-bound:
| GPU | 算力(BF16) | 带宽 | 拐点 AI |
|---|---|---|---|
| A100 80GB | 312 TF | 2.0 TB/s | 156 |
| H100 SXM5 | 989 TF | 3.35 TB/s | 295 |
| H200 SXM | 989 TF | 4.8 TB/s | 206 |
| B200 SXM | 2250 TF (FP4) | 8 TB/s | 281 |
算力涨得快,带宽涨得慢的后果
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 是简化模型,实际算子还受这些因素影响:
- 缓存命中:Roofline 假设所有数据从 HBM 读,但如果命中 L2 cache,实际带宽高得多(甚至接近 SRAM 带宽);
- 算子内在并行度:matmul 在 Tensor Core 上跑和纯 CUDA Core 上跑差几十倍,Roofline 不区分;
- 指令 mix:一个算子如果是加减乘除混合,可能算力利用率上不去(Tensor Core 只对密集 GEMM 友好);
- memory access pattern:coalesced vs random 的带宽差 5-10 倍,Roofline 只算总量没看模式;
- 延迟隐藏: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% 收益。
延伸阅读
- 显存层次与带宽墙——带宽墙的成因与硬件数据
- 权重量化与混合精度——直接减字节突破带宽墙
- 算子融合与自定义核——减少 HBM 读写次数
- GPU 体系结构与优化——cache/occupancy/bank conflict 的底层视角
- 批处理与请求调度——堆 batch 提升 matmul 的 AI
- vLLM 案例研究——Roofline 优化的工业实现
- benchmarking 实践——把 Roofline 模型落到实测
参考资料
- Williams, Waterman, Patterson. Roofline: An Insightful Visual Performance Model for Multicore Architectures(CACM 2009) —— Roofline 模型原始论文
- Ofenbeck et al. Roofline Model for GPUs(2017) —— Roofline 扩展到 GPU
- NVIDIA Nsight Compute Documentation —— 单算子级 profiling 工具
- Ivanov et al. Data Movement Is All You Need(NeurIPS 2021) —— 用 Roofline 分析神经网络算子的带宽瓶颈
- Pope et al. Efficiently Scaling Transformer Inference(MLSys 2023) —— LLM 推理 Roofline 的系统化应用