⚡ 模块八:LLM 推理优化深度(MUSA)

推理指标体系:TTFT / TPOT / ITL / Goodput / P99

进阶·⏱ 60分钟·📅 2026-06-01
大纲调整说明(2026-11-14)
本课提到的“即将开课的 m8-l4”(FlashAttention-3 与 MATE FMHA 深度)已合并至 m6-l7,不再单独开课;m8-l3 已改名为“投机解码(MTP / DSpark on vLLM-MUSA)”,仍在编写中。“本课定位”中的技术列表已据此把“EAGLE-3”改为“投机解码(MTP / DSpark)”。
📊
本课定位
这是模块八「LLM 推理优化深度」的开篇课。后续 m8-l2 ~ m8-l8 的所有优化技术(PagedAttention、投机解码(MTP / DSpark)、FA3、FP8、Disaggregated Serving、模型路由)都将以本课定义的指标作为评估基准。本课在 MTT S5000(PH100)/ MTT S4000 + vllm-musa 上完成所有实测。

一、为什么先讲指标?

过去三周,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 流式返回
⚠️
两段计算特性截然不同
Prefill 是计算密集型(compute-bound),FLOPs 主导,受益于 FlashAttention 与 CUDAGraph;Decode 是访存密集型(memory-bound),KV Cache 读取带宽主导,受益于 PagedAttention、投机解码、MTP。混在一起算单一吞吐数字会掩盖真实瓶颈,这是分离式部署(m8-l7)的根本动因。

三、核心指标定义

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 服务

  1. 拉取最新镜像:
    docker pull registry.mthreads.com/mcconline/musa-pytorch-release-public:rc4.3.0-v2.9.0-S5000-py310
  2. 启动容器(挂载模型权重目录):
    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
  3. 容器内安装最新 vllm-musa:
    docker exec -it vllm-bench bash
    pip install -U git+https://github.com/MooreThreads/vllm-musa.git@main
  4. 启动 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
  5. 验证服务:
    curl http://localhost:8000/v1/models

4.3 Step-by-Step:使用 GenAI-Perf 测量五大指标

  1. 安装 genai-perf:
    pip install genai-perf
  2. 运行混合负载基准测试(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
  3. 报告包含的关键字段:
    • time_to_first_token_ms:TTFT 的 avg / p50 / p95 / p99
    • inter_token_latency_ms:ITL 的 avg / p50 / p95 / p99
    • output_token_throughput:tok/s(总)
    • request_throughput:req/s
  4. 计算 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)820ms1860ms62ms96ms2.1 req/s0.4 req/s
+ prefix cache410ms1240ms62ms96ms3.4 req/s1.1 req/s
+ FULL CUDAGraph (PR #52)410ms1240ms31ms52ms5.2 req/s4.0 req/s
+ Qwen3 P/D split (PR #44)360ms980ms27ms44ms5.8 req/s5.3 req/s
💡
读懂这张表
Throughput 从 2.1 提升到 5.8 是 2.76×,但 Goodput 从 0.4 提升到 5.3 是 13.25×。两个倍数都是真的——前者是宣传口径,后者是用户口径。生产环境永远要看 Goodput。

六、本课检查清单(动手前必读)

  • ✅ 永远启用流式(--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
✅
运行环境兼容性
本课所有命令在 MTT S5000(PH100,80GB HBM)单卡和 8 卡集群、MTT S4000(48GB)双卡均已验证;MUSA SDK 5.1.0+、torch_musa v2.9.0+ 必需;不依赖任何 NVIDIA 工具链。