一、为什么先讲指标?
过去三周,vllm-musa 合入了 8 个性能相关 PR(#44~#52):Qwen3 prefill/decode 分离、tilelang RoPE TVM-CPP、flashinfer sampler、dflash + Gemma-4-31B FULL CUDAGraph、ccache。每一个 PR 在 release notes 里都标注了「TPOT 改善 12~18%」「predictable 4.08×」「prefill 10.7×」等数字。这些数字到底意味着什么?
"快"不是一个工程指标。在生产环境中,同一个模型同一个硬件可以同时是"快"和"慢"——取决于你测的是哪一段、用的是哪种负载、关心的是平均值还是尾延迟。本课的目标,是建立一套可测量、可对比、可优化的 LLM 推理指标体系,并用 vllm-musa 实测每一项。
二、LLM 推理流水线总览
一次 LLM 请求的完整生命周期由以下阶段组成:
- Queue Wait:请求进入调度器排队等待
- Prefill:模型一次性处理整段 prompt,建立 KV Cache
- Decode:自回归逐 token 生成,每一步读取并扩展 KV Cache
- Detokenize + Stream:将 token 还原为字符并通过 SSE 流式返回
三、核心指标定义
3.1 TTFT — Time To First Token
从客户端发出请求到收到第一个 token 的延迟。等于 queue_wait + prefill_time + first_decode_step。
- 影响因素:prompt 长度、批次满载程度、是否命中 prefix cache、prefill 是否被 chunked、prefill 是否与 decode 分离
- 用户体感:直接对应"按下回车后多久看到第一个字",是 Chat 类产品的首屏体验指标
- 典型阈值:交互式 Chat ≤ 500ms 优秀、≤ 1000ms 可接受、> 2000ms 用户开始流失
3.2 TPOT — Time Per Output Token
稳态解码阶段每生成一个新 token 的平均时间。等于 (total_latency − TTFT) / (output_tokens − 1)。
- 影响因素:KV Cache 读取带宽、attention 实现(FA3 / mate FMHA)、是否启用 FULL CUDAGraph、是否启用投机解码、batch size
- 用户体感:对应"打字速度"。<30ms(>33 tok/s)人眼无感知;>80ms 用户会明显感觉卡顿
- vllm-musa PR #44 实测:Qwen3 prefill/decode 分离后 TPOT 改善 12~18%
3.3 ITL — Inter-Token Latency
相邻两个流式 token 之间的实际间隔。TPOT 是 ITL 的均值,但 ITL 的方差同样重要——抖动大的输出在前端表现为"一卡一卡",比恒定 TPOT 慢的体验还差。
- 用 P50 / P95 / P99 ITL 三个分位数刻画稳定性
- 投机解码(m8-l3)会让 ITL 不再恒定——接受率高的 step 会一次返回 N 个 token,接受率低的 step 退化为单步
3.4 Goodput — 满足 SLO 的有效吞吐
传统 throughput(tok/s 或 req/s)只看产出,不看质量。Goodput 在 throughput 的基础上加了SLO 约束:
Goodput = throughput of requests satisfying (TTFT < X) ∧ (TPOT < Y)
同一个集群在 batch=128 时 throughput 最高,但 TTFT P99 可能爆掉;batch=32 时 throughput 低 30%,但 TTFT 全部达标。Goodput 是唯一不会在调优时反向欺骗你的指标。
3.5 P99 — 尾延迟
对所有请求按延迟排序,第 99 分位的值。生产 LLM 服务的 SLO 通常基于 P95 / P99 而非均值,因为:
- 均值会被大量短请求拉低,掩盖少量长请求的灾难性体验
- P99 直接对应"100 个用户里最不幸的那 1 个"的体验
- 用户对差体验的记忆远比好体验深,1% 的差体验足以毁掉口碑
四、在 MUSA + vllm-musa 上搭建测量平台
4.1 环境准备
本节示例基于以下软硬件配置(截至 2026-06-01):
- GPU:MTT S5000(PH100 芯片,80GB HBM)单卡 / 8 卡节点
- MUSA SDK:5.1.0(2026-05-18 发布)
- vllm-musa:master @ PR #52(dflash + Gemma-4-31B FULL CUDAGraph 默认开启)
- torch_musa:v2.9.0
- 测试模型:Qwen3-32B(兼顾 prefill / decode 两阶段可观测性)
4.2 Step-by-Step:启动 vllm-musa 服务
- 拉取最新镜像:
docker pull registry.mthreads.com/mcconline/musa-pytorch-release-public:rc4.3.0-v2.9.0-S5000-py310 - 启动容器(挂载模型权重目录):
docker run -d --name vllm-bench --gpus all --shm-size 32g -v /data/models:/models -p 8000:8000 registry.mthreads.com/mcconline/musa-pytorch-release-public:rc4.3.0-v2.9.0-S5000-py310 sleep infinity - 容器内安装最新 vllm-musa:
docker exec -it vllm-bench bash pip install -U git+https://github.com/MooreThreads/vllm-musa.git@main - 启动 OpenAI 兼容 API 服务:
VLLM_MUSA_DFLASH_FULL_WRAP=1 python -m vllm.entrypoints.openai.api_server --model /models/Qwen3-32B --tensor-parallel-size 4 --max-model-len 32768 --gpu-memory-utilization 0.92 --enable-prefix-caching --port 8000 - 验证服务:
curl http://localhost:8000/v1/models
4.3 Step-by-Step:使用 GenAI-Perf 测量五大指标
- 安装 genai-perf:
pip install genai-perf - 运行混合负载基准测试(128 并发,输入 1024 token,输出 256 token):
genai-perf profile --model /models/Qwen3-32B --endpoint-type chat --service-kind openai --url http://localhost:8000 --num-prompts 1024 --concurrency 128 --synthetic-input-tokens-mean 1024 --synthetic-input-tokens-stddev 0 --output-tokens-mean 256 --output-tokens-stddev 0 --streaming --artifact-dir ./artifacts/qwen3-32b-c128 - 报告包含的关键字段:
time_to_first_token_ms:TTFT 的 avg / p50 / p95 / p99inter_token_latency_ms:ITL 的 avg / p50 / p95 / p99output_token_throughput:tok/s(总)request_throughput:req/s
- 计算 Goodput(GenAI-Perf 不直接给出,需后处理):
import json report = json.load(open('./artifacts/qwen3-32b-c128/profile_export_genai_perf.json')) slo_ttft_ms = 1000 slo_tpot_ms = 50 good = [r for r in report['requests'] if r['ttft'] < slo_ttft_ms and r['tpot'] < slo_tpot_ms] goodput = len(good) / report['duration_sec'] print(f"Goodput = {goodput:.2f} req/s")
五、PH100 + vllm-musa 参考实测表
下表为内部参考数据(Qwen3-32B / TP=4 / max_model_len=32k / input=1024 / output=256),仅供作为相对基线,绝对值因硬件与版本会有 ±10% 浮动:
| 配置 | TTFT P50 | TTFT P99 | TPOT | ITL P99 | Throughput | Goodput (TTFT<1s, TPOT<50ms) |
|---|---|---|---|---|---|---|
| baseline (eager) | 820ms | 1860ms | 62ms | 96ms | 2.1 req/s | 0.4 req/s |
| + prefix cache | 410ms | 1240ms | 62ms | 96ms | 3.4 req/s | 1.1 req/s |
| + FULL CUDAGraph (PR #52) | 410ms | 1240ms | 31ms | 52ms | 5.2 req/s | 4.0 req/s |
| + Qwen3 P/D split (PR #44) | 360ms | 980ms | 27ms | 44ms | 5.8 req/s | 5.3 req/s |
六、本课检查清单(动手前必读)
- ✅ 永远启用流式(
--streaming),否则无法测 TTFT 和 ITL - ✅ 至少跑 5 分钟 / 1000 请求,避免冷启动污染
- ✅ 单独测一次 prefill-heavy(input 4096 / output 64)和 decode-heavy(input 256 / output 2048)
- ✅ 明确报告 SLO 阈值,否则 Goodput 无意义
- ✅ 报告版本:MUSA SDK + torch_musa + vllm-musa commit + GPU 型号
- ✅ 不要混合不同 prompt 长度的请求做平均,会让分位数失真
七、本课小结与下节预告
本课定义了 LLM 推理优化中最重要的五个指标 TTFT / TPOT / ITL / Goodput / P99,并在 MTT S5000(PH100)+ vllm-musa 上给出了可复现的测量流程。建立指标体系是所有优化工作的前提——没有指标,"快"只是营销词。
- 下一课 m8-l2 KV Cache 与 PagedAttention:从指标走向第一项优化技术,解析 vllm-musa 的 PagedAttention 实现与 prefix cache 命中机制
- 本课表格中 PR #44 与 PR #52 的具体实现细节,参见 m5-l3 vLLM-MUSA 推理部署实战 第十九节和第二十二节
- FlashAttention-3 / mate FMHA 的底层算子设计,参见 m6-l7 mate 算子库 与即将开课的 m8-l4