Skip to content

推理基准测试实践

本页速览 推理优化的数字怎么测、怎么报、怎么防作弊?本文给出 LLM 推理基准测试方法论:测什么(吞吐/TTFT/TPOT/p99/显存)、用什么测(vLLM offline / mlperf-llm / sglang bench / lm-eval-harness)、怎么控制变量、怎么写报告,附防作弊清单与报告模板。

推理基准测试实践

没有测准的数字,比没有数字更危险——它给优化决策披上"科学"的外衣,却掩盖了真实的瓶颈。

推理优化圈有一句老话:"我的模型在你的硬件上跑得比你快"——这是营销话术,不是工程结论。同一模型、同一 GPU,两家测出来的 tokens/s 能差 3 倍,原因在测试方法:batch size 不同、prompt 长度不同、量化精度不同、KV cache 配置不同、cold/warm start 不分。没有方法论的 benchmark 比没有 benchmark 更害人——它让你在错误的方向上持续投入。

本文给出一套可复用、可对比、可防作弊的 LLM 推理基准测试方法论。读完本文,你应该能:写出任何两个引擎对比都能复现的测试报告,识别出 5 种最常见的"benchmark 作弊",并把测试结果转成决策依据。这是 从零部署一个推理服务渐进式教程 性能数字的来源方法。

本文的边界

本文聚焦单实例 LLM 推理基准——单机单卡或多卡上的引擎对比。分布式系统级基准(集群 QPS、跨实例延迟、网络开销)是另一套方法论,本文不展开。详见 Triton 推理服务模型服务化与编排

一、测什么:LLM 推理的核心指标

LLM 推理与经典 ML 推理最大的差别:指标不是一个数字,而是一组。只看 tokens/s 等于只看平均分——它会掩盖长尾延迟、掩盖首字延迟、掩盖并发退化。下面五个指标缺一不可。

1. 五个核心指标

指标定义业务含义测什么
TTFT (Time To First Token)从请求到收到第一个 token 的时间聊天场景的"响应感"、用户耐心边界prefill 阶段 + queue 等待
TPOT (Time Per Output Token)生成阶段平均每 token 时间流式生成的"打字速度"decode 阶段 + KV cache 访问
端到端延迟 (E2E)从请求到收到完整输出批处理、文档摘要等"等结果"场景TTFT + N × TPOT
吞吐 (tokens/s)单位时间生成的总 token 数集群吞吐能力、成本核算(并发数 × output_len) / 总时间
显存峰值 (peak GPU memory)推理过程中显存最高占用部署可行性、并发上限权重 + KV pool + 临时

2. 延迟分布:p50 / p95 / p99

平均延迟会骗人——30 个并发里 28 个 1s、2 个 10s,平均 1.6s 看着还行,但那 2 个 10s 的请求在聊天场景下用户已经走了。生产环境必须看分位数

延迟分布(32 并发,TPOT 排序后):
p50  = 22 ms    ← 中位数,"正常情况下的体验"
p90  = 35 ms    ← 90% 的请求快于此值
p95  = 50 ms    ← SRE 关心的"长尾"
p99  = 180 ms   ← 真正的"倒霉用户"
p999 = 1200 ms  ← 系统在退化时的极端案例
  • p50:业务体感的代表,但掩盖了长尾
  • p95:SRE 主看这个——它代表"大多数用户的下限"
  • p99:成本敏感场景看这个——为了把 p99 从 200ms 降到 180ms,可能要多花一倍机器
  • p999:通常不报,因为 0.1% 的极端案例往往来自 GC、网络抖动等非模型因素

平均值与分位数的纪律

  • 对外汇报:报 p50 + p99(一对,反映中心与长尾)
  • 内部 SRE:报 p50/p90/p95/p99/p999(一组,反映分布形状)
  • 永远不要只报平均值——平均值会让 1 个慢请求被 99 个快请求平均掉,问题看不见

详见 延迟、吞吐与并发 的"延迟分布与排队论"。

3. 显存峰值的三层

显存不是一个数字,是三层:

内容谁负责
权重层模型参数本身量化、剪枝、蒸馏优化(详见 模型量化基础
KV cache 层历史 token 的 K/V 张量PagedAttention、block_size、max_num_seqs 优化
临时层attention 中间矩阵、激活kernel fusion、FlashAttention 优化

nvidia-smi 看到的"显存占用"是三者之和——不看每一层,调参时就抓瞎:"为啥 14 GB 模型占了 36 GB?" 答案是 KV pool 占了 22 GB。详见 显存层次与带宽墙

二、用什么测:工具盘点

LLM 推理基准测试的工具有四大类,每类测的指标不同、用途不同:

1. 工具矩阵

工具主要用途测什么谁维护
vLLM benchmarks/vLLM 自身性能基准与对比吞吐、延迟、显存vLLM 项目组
MLPerf-LLM跨硬件/跨引擎的标准化基准吞吐、延迟、成本MLCommons
SGLang bench/SGLang 与 vLLM 对比吞吐、延迟、复杂调度SGLang 项目组
lm-eval-harness模型质量评测(不是性能)MMLU/HellaSwag 等精度EleutherAI
trtllm-benchTensorRT-LLM 性能基准吞吐、延迟NVIDIA
openllm-bench跨引擎、跨量化对比全维度社区

2. vLLM offline 推理基准(最常用)

vLLM 自带的 benchmarks/benchmark_throughput.pybenchmark_latency.py 是最常用的"入门级"基准测试:

bash
# 离线吞吐基准(不通过 HTTP,直接 Python API)
python benchmarks/benchmark_throughput.py \
    --model meta-llama/Llama-2-7b-chat-hf \
    --backend vllm \
    --input-len 1024 \
    --output-len 256 \
    --num-prompts 512 \
    --dtype bfloat16 \
    --max-model-len 4096

# 单请求延迟基准
python benchmarks/benchmark_latency.py \
    --model meta-llama/Llama-2-7b-chat-hf \
    --backend vllm \
    --input-len 1024 \
    --output-len 256 \
    --batch-size 1 \
    --num-iters 100

它的优点是与 vLLM 内部 API 直连,没有 HTTP 层开销,测的是引擎本身。缺点是只能测 vLLM(要测其他引擎得用其他脚本)。详见 vLLM 与 PagedAttention

3. MLPerf-LLM(标准化对比)

MLPerf-LLM 是跨硬件、跨引擎的标准化基准——所有参测方按相同规则测,结果可公开对比:

维度测什么
Single-stream单请求延迟(TTFT + TPOT)
Multi-stream多请求并发下的延迟分布
Offline纯吞吐(无并发约束)
Server在线 QPS 与 SLO 达成率

MLPerf 的纪律很严:所有参测方必须报完整配置(硬件型号、driver 版本、引擎版本、模型权重 hash),结果必须可复现。这是工业级对比的金标准——你的 vLLM 在 A100 上 1100 tok/s 的数字,与 MLPerf 公开榜单的数字能直接对得上,否则就是你的方法有问题。

4. SGLang bench(对比测试)

SGLang 项目的 bench/ 提供了 vLLM 与 SGLang 的对比脚本——它对复杂场景调度(多轮对话、长上下文、structured output)的覆盖比 vLLM 自带脚本更细:

bash
# SGLang vs vLLM 对比
python -m sglang.bench_serving \
    --backend vllm \
    --base-url http://localhost:8000 \
    --model meta-llama/Llama-2-7b-chat-hf \
    --dataset-name random \
    --random-input-len 1024 \
    --random-output-len 256 \
    --num-prompts 512

详见 vLLM 与 PagedAttention推理引擎选型对比 中"复杂调度场景"。

5. lm-eval-harness(模型质量)

性能不是全部——量化、剪枝、蒸馏后模型是不是变笨了?这是 lm-evaluation-harness 的事:

bash
# 跑 MMLU 5-shot 评测
lm_eval --model vllm \
    --model_args pretrained=meta-llama/Llama-2-7b-chat-hf \
    --tasks mmlu \
    --num_fewshot 5 \
    --batch_size 8

# 跑 AWQ 量化模型
lm_eval --model vllm \
    --model_args pretrained=./Llama-2-7b-chat-hf-awq,quantization=awq \
    --tasks mmlu,hellaswag,arc_challenge \
    --num_fewshot 5

性能数字必须配质量数字一起报——只报 tokens/s 不报 MMLU,等于只报成本不报效果。详见 模型量化基础 的"量化是 trade-off"。

三、关键变量:什么会显著影响数字

下面这些变量每一个都能让数字差一倍以上。报告必须显式声明每个变量的取值,否则不可复现。

1. 变量矩阵

变量默认值影响方向典型影响
batch_size / max_num_seqs1 / 256大→吞吐↑但 p99 延迟↑5–10×
input_len (prompt 长度)不固定长→TTFT↑、KV cache↑线性
output_len (生成长度)不固定长→单请求延迟↑、TPOT 不变线性
并发数1高→吞吐↑但 p99 延迟↑3–30×
量化精度bf16INT4→显存↓但 TPOT 也↓1.3–2×
KV cache size (gpu_mem_util × block_size)0.9 × 16大→能接更多并发2–5×
模型不固定大→所有指标都退化5–10×
GPU 型号A100 40GB新卡更快(A100→H100:2×)1.5–3×
CUDA / driver 版本最新不匹配可能掉 30%1.0–1.5×

2. 公平对比的纪律

两个引擎对比时,必须控制

固定模型(同权重 hash)
固定 GPU(同型号、同 driver)
固定 batch_size 或并发数
固定 input_len 与 output_len
固定量化精度
固定 max_model_len 与 KV pool
唯一变量:引擎本身

少一个变量,对比就不公平。最经典的反例是"vLLM 默认开 PagedAttention,TGI 默认不开"——直接跑默认参数对比,vLLM 必赢,但赢的不是引擎本身而是 KV pool 配置。公平的对比必须把两边都调到各自最优配置,而不是默认配置。

"默认配置对比"是耍流氓

很多"vLLM 比 TGI 快 5×"的对比文章都是默认配置对比——一边开 PagedAttention 一边不开。真正的对比是"vLLM 最优 vs TGI 最优",这才是用户买来用会调成的状态。详见 推理引擎选型对比

四、防作弊:5 种最常见的小动作

benchmark 圈的 5 种"作弊"——多数不是故意,而是测错了不知道:

1. Cold start vs Warm start 不分

症状:第一次跑很慢,后续跑很快,报告只报后续。

根因:CUDA kernel 编译、CUDA Graph capture、KV cache 预热都发生在前几次推理里。cold start 慢 3–10 倍是常态。

修复

python
# 标准做法:warmup N 次(N ≥ 3),然后再 bench
for _ in range(3):
    _ = model.generate(**inputs, max_new_tokens=8)   # warmup

# 正式测试
t0 = time.perf_counter()
out = model.generate(...)
t1 = time.perf_counter()

报告里写明"warmup 3 次后测试 100 次,取 p50/p99"。

2. CPU-GPU overlap 没算

症状:用 time.time() 测端到端,结果包含了 Python 解释、HTTP 序列化等 CPU 时间。

根因:CUDA 是异步的——model.generate 返回时 GPU 还在跑,没 torch.cuda.synchronize() 就测时间等于测了"Python 启动 GPU 的时间"。

修复

python
torch.cuda.synchronize()
t0 = time.perf_counter()
out = model.generate(...)
torch.cuda.synchronize()    # ← 等 GPU 真跑完
t1 = time.perf_counter()

HTTP 服务测试则要用客户端收完最后一个 chunk 的时间,不是 request.send 的时间。

3. Padding 把延迟拉高

症状:batch 里所有 prompt 长度不同时,被 pad 到最长,每个请求都按最长 prompt 算 prefill。

根因:经典 batching 没 PagedAttention 时,必须 pad 等长。vLLM 的 PagedAttention 解决了这个问题——但如果你测的是非 vLLM 引擎,padding 是常见拉高延迟的原因。

修复:报告里写明 padding 策略,最好用相同长度的 prompt 测(--random-input-len 1024)。

4. 单 batch 测延迟当生产延迟

症状:报"延迟 30ms"——结果只测了 batch=1 的理想情况,生产环境 32 并发时延迟 200ms。

根因:单 batch 延迟是引擎最优情况,不是生产情况。生产延迟必须带并发测。

修复:永远同时报单请求延迟 + N 并发延迟,最好画"并发数 vs 延迟"曲线:

并发    p50   p99
1       22    25
4       24    30
16      28    50
32      35    180
64      50    1200  ← 这里开始退化

这是 常见陷阱与反模式 的"单 batch 测延迟就当成品级延迟"。

5. 量化精度不标

症状:报"vLLM 跑 Llama-2-7B 吞吐 1100 tok/s"——结果用的是 AWQ INT4 模型,而对比的 TGI 用 bf16。

根因:量化版本和原始版本的吞吐本就差 1.5–2×,不是引擎差异而是模型差异

修复:模型版本、量化精度、权重组大小(q_group_size)必须显式声明,对比时两边量化精度必须一致

自检清单

报出 benchmark 数字前,过一遍这五条:

  • [ ] warmup 至少 3 次,再测至少 100 次
  • [ ] 用 torch.cuda.synchronize() 或 HTTP 完整往返时间
  • [ ] 显式声明 prompt 长度与 padding 策略
  • [ ] 同时报单请求延迟 + 至少 3 个并发档位延迟
  • [ ] 模型权重 hash、量化精度、CUDA 版本都写在报告里

少一项,你的数字就不可信。详见 常见陷阱与反模式部署设计原则 的"端到端基准而非单算子基准"。

五、报告模板

一份合格的推理基准报告应该包括五部分:

markdown
# 推理基准报告:<模型名> 在 <硬件> 上的对比

## 1. 环境
- 硬件:NVIDIA A100 80GB × 1
- Driver:535.104.05, CUDA 12.4, cuDNN 9.0
- 引擎:vLLM 0.6.3, TensorRT-LLM 0.13.0
- 模型:Llama-2-7b-chat-hf(HuggingFace, sha256: ...)
- 量化:bf16(无量化)

## 2. 配置
- max_model_len: 4096
- max_num_seqs: 32
- gpu_memory_utilization: 0.9
- input_len: 1024, output_len: 256
- 并发档位: 1 / 4 / 16 / 32 / 64
- warmup: 3 次,测试: 100 次/档

## 3. 结果

| 并发 | 引擎 | p50 (ms) | p99 (ms) | 吞吐 (tok/s) | 显存峰值 (GB) |
|---|---|---|---|---|---|
| 1 | vLLM | 200 | 250 | 50 | 18 |
| 1 | TRT-LLM | 180 | 220 | 55 | 17 |
| 32 | vLLM | 35 | 180 | 1100 | 36 |
| 32 | TRT-LLM | 30 | 150 | 1300 | 32 |

## 4. 结论
- TRT-LLM 在所有档位都比 vLLM 快 10–20%
- 但 TRT-LLM 部署复杂度更高(需 build engine)
- 在线场景推荐 vLLM(开发效率优先),离线场景推荐 TRT-LLM(吞吐优先)

## 5. 复现
- 代码:`scripts/bench_vllm_vs_trtllm.sh`
- 模型权重:HuggingFace `meta-llama/Llama-2-7b-chat-hf`
- 命令:`bash scripts/bench_vllm_vs_trtllm.sh`

模板的纪律

报告五部分缺一不可:

  • 缺环境:换机器就复现不了
  • 缺配置:别人不知道你 vLLM 怎么调的
  • 缺结果矩阵:没法做对比决策
  • 缺结论:报告变成"数据堆"
  • 缺复现命令:报告等于"我的话"

详见 基准数据与工具档案 的"如何读 benchmark 榜单"。

六、把数字转成决策

benchmark 不是终点,是决策依据。下面是把数字转成决策的常见模式:

1. 引擎选型

测出 vLLM 与 TRT-LLM 的对比数字后,决策路径:

延迟差 < 10%     → 选 vLLM(部署简单、社区大)
延迟差 10–30%   → 看团队:有 NVIDIA 背景选 TRT-LLM,没有选 vLLM
延迟差 > 30%    → 业务对延迟极敏感 → 选 TRT-LLM
吞吐差 > 50%    → 离线批处理 → 选 TRT-LLM

详见 推理引擎选型对比

2. 量化决策

测出 AWQ INT4 与 bf16 的对比后:

吞吐提升 > 50%, MMLU 下降 < 1   → 全量上线 AWQ
吞吐提升 20–50%, MMLU 下降 1–3  → 灰度 20%,看业务指标
吞吐提升 < 20%, MMLU 下降 > 3   → 不上 AWQ,保留 bf16

详见 模型量化基础权重量化与混合精度

3. 并发调参

测出"并发数 vs p99 延迟"曲线后,找拐点:

1  → 22ms
4  → 28ms
16 → 35ms    ← 拐点之前
32 → 180ms   ← 拐点!p99 突然飞涨
64 → 1200ms  ← 严重退化

max_num_seqs = 16(拐点之前),超过的请求走队列或 autoscale。详见 调参与性能调优 的"max_num_seqs 调参"。

4. 硬件升级决策

测出 A100 与 H100 的对比后:

吞吐提升 < 1.5×   → 不值得升级(H100 贵 2×)
吞吐提升 1.5–2×   → 看业务 SLA 是否吃紧
吞吐提升 > 2×    → 升级划算

详见 硬件基础速查GPU 体系结构与优化

七、延伸阅读

参考资料