为什么大模型推理 GPU 利用率不高?
简化版
GPU 利用率低不一定代表算力闲置。LLM 推理包含 Prefill 和 Decode:Prefill 通常计算密集,Decode 每步 Token 少、反复读取权重和 KV Cache,常受显存带宽限制;此时 SM 利用率不高,但带宽可能已经接近上限。
排查要先拆分排队、CPU 预处理、Host-to-Device、Prefill、Decode 和网络流式输出,再同时看 SM、Tensor Core、显存带宽、Kernel 间隙、Batch、KV 水位和 Tokens/s。优化通常包括连续批处理、长度/Token 组批、算子融合、量化、Pinned Memory、异步流水和减少同步点,最终以 SLO 内的有效吞吐验收。
详细版
常见原因分四类:负载不足或批次太小;Decode 的访存瓶颈;CPU/网络/调度导致 GPU 等待;Kernel 形状、量化或多卡通信效率差。仅看 nvidia-smi 的 GPU-Util 无法区分这些原因。
request -> tokenize -> schedule -> H2D -> prefill/decode -> sample -> stream
CPU wait GPU compute CPU/network wait
应先用时间线 Profile 找空洞,再看 Roofline 判断计算还是带宽受限。低流量下不应为了提高利用率故意凑大 Batch、破坏 TTFT;高流量下则在 TTFT/TPOT/P99 约束内提高连续批大小。指标目标是成功请求数或输出 Tokens/s,而不是单独追求 100% GPU-Util。
完整版教学
1. GPU 利用率指标代表什么
nvidia-smi 的 GPU-Util 通常表示采样窗口内是否有 Kernel 在运行,并不直接等于 Tensor Core 使用率,也不能说明 Kernel 是否高效。一个低效率 Kernel 持续运行也可能显示很高。
诊断需要结合 SM Active、Tensor Core、DRAM 吞吐、占用率、Kernel 时长和端到端吞吐。不同监控工具的定义和采样周期可能不同,面试回答应先说明指标口径。
2. Prefill 与 Decode 为何表现不同
Prefill 一次处理整段 Prompt,大矩阵乘法具有较高算术强度,通常更容易利用 Tensor Core。Decode 每序列每轮只有一个新 Token,却要读取模型权重及历史 KV。
Prefill: many tokens × large GEMM -> often compute-bound
Decode : one token/sequence -> often memory-bandwidth-bound
因此混合统计会掩盖问题,必须按阶段分别看利用率和耗时。
3. 低 Batch 为什么吃不满 GPU
Batch 太小时矩阵维度不足,线程块数量有限,权重搬运也无法被更多 Token 摊薄。Kernel 启动、采样和同步等固定开销占比随之变大。
连续批处理能在请求完成后立即补入新序列,保持 Decode 批次。但 Batch 增大会推高 KV 占用和 TPOT,调优边界仍由服务 SLO 决定。
4. 带宽瓶颈为何看起来“利用率低”
算术强度可粗略表示为:
arithmetic_intensity = FLOPs / bytes_moved
Decode 的 FLOPs/Byte 较低,计算单元可能在等待显存数据。若 DRAM 吞吐接近硬件上限、SM 算术管线却不满,继续优化纯计算 FLOPs 通常收益有限,应减少字节数或提高复用。
5. CPU 与数据流水如何制造空洞
Tokenize、请求组批、Logits 后处理、采样和网络发送若串行执行,GPU 会在相邻 Kernel 间等待。同步读取结果或频繁调用设备同步也会破坏流水。
可使用线程池或独立进程做 Tokenize、Pinned Memory 加速拷贝、异步 Stream 重叠 H2D/计算,并批量处理采样。但需要 Profile 证明瓶颈在 CPU,不能盲目增加线程制造锁竞争。
6. Kernel 形状与融合的影响
小矩阵、非对齐维度或过多独立算子会产生低占用与启动开销。融合 RMSNorm、RoPE、残差和采样等操作,可以减少中间结果写回显存。
| 现象 | 可能原因 | 优先检查 |
|---|---|---|
| Kernel 间空洞多 | CPU/同步/调度 | 时间线与 CPU 火焰图 |
| DRAM 接近满载 | Decode 访存 | Batch、量化、KV 布局 |
| Tensor Core 低 | 形状或精度不匹配 | GEMM 尺寸、数据类型 |
| 多卡通信占比高 | 并行度过大 | Collective 时间与拓扑 |
优化后的 Kernel 还要验证数值与模型质量。
7. 量化为什么可能提高利用效率
权重量化减少 Decode 每步需要搬运的字节;FP8/INT8 等合适 Kernel 还可提高硬件吞吐。KV 量化则针对长上下文的缓存带宽和容量。
但位宽降低不保证等比例加速。反量化、Scale 读取、硬件支持和矩阵形状都会影响实际效果,应比较端到端 TPOT 与质量,而非只看模型文件大小。
8. KV Cache 管理如何影响执行
KV 碎片或过度预留会限制可进入 Batch 的序列数;分页管理按需分配块,可以提高有效容量。块表查找和不连续访问也要求专门优化的 Attention Kernel。
KV 水位过高时发生 Swap 或重算,会形成突发延迟并让 GPU 等待传输。应通过准入控制避免长期运行在危险水位。
9. 多卡通信为什么拖慢利用率
张量并行每层通常包含 All-Reduce/All-Gather。Batch 小或网络拓扑差时,通信无法被计算隐藏,GPU 会等待其他 Rank。
需要查看通信 Kernel、链路带宽和各 Rank 时间差。模型能单卡容纳时,增加 TP 度未必更快;跨节点并行尤其应计算通信成本。
10. 负载本身不足怎么办
低 QPS 服务没有足够并行请求,利用率低是正常结果。为了漂亮的监控数字等待凑批,会无谓增加用户延迟。
此时可通过多个模型/租户安全共置、缩容、MIG 或更小 GPU 提高经济利用率。目标应是满足 SLO 的成本,而不是强行让单卡满载。
11. 如何用 Profile 定位
先记录一条请求与高并发两种时间线,标出 CPU、拷贝、计算、通信和网络。再对主要 Kernel 看算术吞吐、DRAM 吞吐、占用率和 Warp Stall 原因。
stage_ms = {
"tokenize": t1 - t0,
"queue": t2 - t1,
"prefill": t3 - t2,
"decode": t4 - t3,
"stream": t5 - t4,
}
没有分阶段数据时,看到 GPU-Util 低就换 Kernel,往往会优化错层。
12. 怎样设置验收指标
性能验收应固定模型、硬件、输入/输出长度分布和并发,报告 TTFT、TPOT、P99、Requests/s、Tokens/s、功耗和单位成功请求成本。
优化若让 GPU-Util 从 60% 升到 90%,却让 P99 翻倍或取消率上升,就不是在线服务的有效优化。需要在同一 SLO 约束下比较最大稳定吞吐。
GPU 是为了服务业务负载,而不是为了让利用率仪表盘始终显示满格。
13. 常见误区与追问
- 误区:GPU-Util 低就一定是 GPU 算力瓶颈。 可能是带宽、CPU、网络或流量不足。
- 误区:Batch 越大越好。 大 Batch 可能恶化 TTFT、TPOT 和显存水位。
- 误区:Prefill 与 Decode 的利用率可以混看。 两阶段常分别受计算和带宽限制。
- 误区:量化比例等于加速比例。 Kernel 与反量化开销决定实际收益。
- 误区:多卡一定比单卡快。 通信成本可能超过计算收益。
- 追问:如何判断访存瓶颈? 看 DRAM 吞吐接近上限而计算管线未满,并结合 Roofline。
- 追问:低流量如何降成本? 优先缩容、共置或换合适卡型,不为利用率牺牲延迟。
14. 加强记忆
- 先记口径:GPU-Util 不等于 Tensor Core 效率。
- 再分阶段:Prefill 常算力密集,Decode 常带宽受限。
- 再看流水:CPU、拷贝、同步、网络都会制造空洞。
- 再看负载:Batch 小或 QPS 低时利用率低可能正常。
- 再做优化:连续批、融合、量化、异步和并行度调整。
- 再做 Profile:时间线加 Roofline,先定位再改。
- 最后验收:SLO 内有效吞吐和单位成功成本才是目标。