跳转到主要内容

Compute-bound vs Memory-bound:推理的两大瓶颈

用算术强度和 Roofline 判断 LLM 推理的算力、显存带宽与数据搬运瓶颈

· 约 5 分钟阅读

判断推理性能时,先别急着看 GPU utilization。一个算子跑得慢,可能是计算单元不够,也可能是权重、激活或 KV Cache 搬不动;两者需要不同的优化。

这篇只负责一件事:用算术强度Roofline 建立瓶颈判断。Prefill、Decode 是常见形态,不是无需测量就成立的标签。

30 秒复习
  • 一句话:把算子的 FLOPs 与实际搬运的 Bytes 放进 Roofline,才能判断性能更受算力还是带宽限制。
  • 三个判断:算术强度低于机器平衡点时先查数据搬运;高于平衡点时先查计算效率;Prefill 常偏计算密集、Decode 常偏带宽密集,但 batch、上下文、量化和 kernel 都会移动结论。
  • 核心模型AI=FLOPs/Bytes\operatorname{AI}=\operatorname{FLOPs}/\operatorname{Bytes}Perfmin(Ppeak,Bpeak×AI)\operatorname{Perf}\le \min(P_{\text{peak}}, B_{\text{peak}}\times \operatorname{AI})
  • 边界:Roofline 给出上界与调查方向,不会自动解释排队、通信、同步、调度空洞或 kernel 启动开销。

1. 先分清两个上限

GPU 执行一个算子,同时消耗:

  1. 计算能力:Tensor Core、CUDA Core 等完成矩阵运算;
  2. 数据供给能力:HBM、片上缓存和互联把权重、激活、KV 搬到计算单元。

算术强度定义为:

AI=FLOPsBytes moved\operatorname{AI}=\frac{\operatorname{FLOPs}}{\operatorname{Bytes\ moved}}
  • AI 低:每搬一字节只做少量计算,更容易受带宽限制;
  • AI 高:同一批数据被重复用于更多计算,更容易受算力限制。

这里的 Bytes 应尽量来自实际内存流量。只按张量逻辑大小估算,会漏掉缓存命中、重复读取、临时张量、融合和量化元数据。

2. 为什么 Prefill 常偏 Compute-bound

Prefill 同时处理一段输入 token。以线性层为例:

XM×KWK×N=YM×NX_{M\times K}W_{K\times N}=Y_{M\times N}

M=batch×tokensM=\text{batch}\times\text{tokens} 较大时,同一份权重可服务更多 token,GEMM 的数据复用与算术强度通常上升。长 prompt、足够大的 batch 和适配良好的 kernel 因此更容易接近计算上限。

但“Prefill = Compute-bound”只是起点。以下情况仍可能让它落到别处:

  • 小 chunk 或形状不规则,GEMM 没有吃满硬件;
  • Attention 读写 KV 或中间结果过多;
  • MoE dispatch/combine、跨卡通信成为主路径;
  • CPU 调度、shape 构造或同步让 GPU 等待;
  • 量化反量化、布局转换或 kernel 启动开销占比升高。

所以优化前应先看算子级 FLOPs、HBM 流量、kernel 形状和 timeline,而不是只按阶段命名。

3. 为什么 Decode 常偏 Memory-bound

自回归 Decode 每一步通常只增加一个 token。单请求或小 batch 下,线性层更接近矩阵-向量运算:读取大量权重,却只为少量 token 做计算。

一个用于容量估算的下界是:

Tweightsresident weight bytesBHBM,effT_{\text{weights}} \gtrsim \frac{\operatorname{resident\ weight\ bytes}} {B_{\text{HBM,eff}}}

它解释了三类常见优化:

  • Continuous Batching:让一次权重读取服务更多活跃请求;
  • 权重量化:减少每步需要搬运的权重字节;
  • Tensor Parallelism:把权重读取和计算分摊到多卡,同时引入通信成本。

这个下界不能直接当成 TPOT。真实 Decode 还包含 KV 访问、Attention、采样、同步、通信和调度间隔;MoE 模型读取的权重范围也取决于专家放置与路由。

4. Roofline 模型:可视化性能瓶颈

Roofline 把两个上限写成同一个式子:

Attainable Performancemin(Ppeak,Bpeak×AI)\operatorname{Attainable\ Performance} \le \min\left( P_{\text{peak}}, B_{\text{peak}}\times \operatorname{AI} \right)

机器平衡点是:

AIridge=PpeakBpeak\operatorname{AI}_{\text{ridge}} = \frac{P_{\text{peak}}}{B_{\text{peak}}}
性能
  │                 ───────── 计算上限
  │               /
  │             /
  │           /  带宽上限
  │         /
  └────────────────────────── 算术强度

              平衡点
  • 位于斜线段:提高峰值算力通常无效,先减少 Bytes 或提高有效带宽;
  • 位于水平段:先改善计算 kernel、形状、并行度或有效算力;
  • 远低于 Roofline:瓶颈可能是 launch、同步、通信、分支或调度,而非两个理论上限。

峰值规格只适合作为上界。做工程判断时,应使用目标精度对应的峰值算力、可达到的有效带宽和实测算子流量。

5. 从判断映射到动作

证据优先检查常见动作
低 AI,HBM 接近有效上限权重、KV、临时张量流量量化、融合、缓存、增大 batch
高 AI,计算单元接近有效上限GEMM/Attention 形状和精度路径更合适的 kernel、并行与硬件
HBM 与计算都低,timeline 有空洞CPU、调度、同步、通信减少同步,改善 admission 与流水
跨卡时间显著collective、拓扑、分片合同调整 TP/EP/PP 和 placement

同一项优化可能移动 Roofline 位置:量化既减少 Bytes,也可能改变可用计算吞吐;增大 batch 提高数据复用,也会增加 KV 和排队压力。最终验收仍要回到 workload 下的 TTFT、TPOT、吞吐和 SLO。

6. 最小分析清单

记录以下字段,才有可能复现瓶颈判断:

model, precision, hardware, kernel/backend,
batch/concurrency, input_length, output_length,
FLOPs, bytes_moved, achieved_compute, achieved_bandwidth,
TTFT, TPOT, throughput, timeline gaps

如果只有一个 utilization 百分比,最多说明“某个计数器高或低”,不能独立证明 compute-bound 或 memory-bound。

相关页面

参考资料