首页
/ vLLM 性能基准测试体系:latency / throughput / serving 三类测试用例、执行脚本与结果发布机制详解

vLLM 性能基准测试体系:latency / throughput / serving 三类测试用例、执行脚本与结果发布机制详解

2026-09-06 19:29:59作者:余洋婵Anita

本文基于 vLLM 仓库的 Buildkite 性能基准描述文件 performance-benchmarks-descriptions.md 展开,完整讲解三类基准测试(延迟、吞吐、在线服务)的输入长度、批量策略与评估指标定义,以及这份"模板文档"如何被 convert-results-json-to-markdown.py 填充为真实结果表并发布到 CI。读完你能理解:vLLM 的 PR 级性能回归检测是如何定义测试工况、如何采集结果、如何转成 Markdown 表格和可复用的 JSON 数据,以及如何在本地复现同一套基准流程。

1. 概述:这套基准测试测什么

vLLM 在 .buildkite/performance-benchmarks/ 目录下维护了一套面向开发者的基准测试套件,用于判断某个 PR 是否提升或劣化了引擎性能。核心组成:

组件 相对路径 作用
基准描述模板 .buildkite/performance-benchmarks/performance-benchmarks-descriptions.md 定义 latency / throughput / serving 三类测试的工况与指标,内含待填充的 Markdown 表格占位符
总执行脚本 .buildkite/performance-benchmarks/scripts/run-performance-benchmarks.sh 检测硬件、下载数据集、依次执行各测试、后处理并上传 Buildkite
测试用例 JSON .buildkite/performance-benchmarks/tests/ 下的 latency-tests.jsonthroughput-tests.jsonserving-tests.json 以 JSON 声明每个测试用例的参数
结果转换脚本 .buildkite/performance-benchmarks/scripts/convert-results-json-to-markdown.py 把 JSON 结果格式化进描述模板,生成 benchmark_results.mdbenchmark_results.json
结果对比脚本 .buildkite/performance-benchmarks/scripts/compare-json-results.py 对比本次与基线结果

覆盖的硬件平台(见 README.md)包括 B200、A100、H100、Intel Xeon 处理器、Intel Gaudi 3 加速器与 Arm Neoverse,完整一轮基准大约需要 1 小时,README 也建议开发者自行新增用例时把时长控制在这一量级。

2. 延迟测试(Latency tests):固定工况下的端到端延迟

描述文档中 latency 一节给出的标准工况:

  • 输入长度:32 tokens;
  • 输出长度:128 tokens;
  • 批大小:固定 8;
  • GPU/HPU 模型:llama-3.1 8B、llama-3 70B、mixtral 8x7B;
  • CPU 模型:llama-3.1 8B;
  • 评估指标:端到端延迟(mean、median、p99)。

文档中 {latency_tests_markdown_table} 占位符在结果生成后会被真实表格替换。表格各列并非凭空约定,而是由转换脚本中的列映射固定下来(见 convert-results-json-to-markdown.py):

  • Test name:测试名(取自 JSON 的 test_name);
  • GPU:硬件型号,多卡时会归一化为 8xGPU型号 形式(脚本在生成表格前会把 nvidia-smi 输出里按行重复的型号折叠成 Nx型号,见 脚本第 370-374 行);
  • Mean latency (ms)Median latency (ms)P99 latency (ms):原始结果以秒为单位,脚本把 avg_latency 以及 P10/P25/P50/P75/P90/P99 各分位数统一乘以 1000 转成毫秒(见 脚本第 280-285 行),表中只保留 Mean、Median(P50)、P99 三列。

对应测试用例定义在 latency-tests.json,每个用例形如:

{
    "test_name": "latency_llama8B_tp1",
    "parameters": {
        "model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
        "tensor_parallel_size": 1,
        "load_format": "dummy",
        "num_iters_warmup": 5,
        "num_iters": 15
    }
}

parameters 中的每个键值对会被执行脚本 json2args 转成 vllm bench latency 的命令行参数,下划线自动替换为短横线(见 run-performance-benchmarks.sh 第 92-106 行),上例最终执行为 --model meta-llama/Meta-Llama-3.1-8B-Instruct --tensor-parallel-size 1 --load-format dummy --num-iters-warmup 5 --num-iters 15。默认文件中的三条用例分别覆盖 8B/TP1、70B/TP4、Mixtral-8x7B/TP2。README 特别提醒:延迟数字对参数取值高度敏感,且脚本会自行保存 JSON 结果,不要在用例 JSON 里再配置 --output-json,以免与脚本的 --output-json $RESULTS_FOLDER/${test_name}.json 冲突(见 run-performance-benchmarks.sh 第 536-538 行)。

3. 吞吐测试(Throughput tests):ShareGPT 真实分布下的极限吞吐

描述文档中 throughput 一节的工况:

  • 输入长度:从 ShareGPT 数据集随机采样 200 条 prompt(固定随机种子);
  • 输出长度:这 200 条 prompt 对应的输出长度;
  • 批大小:由 vLLM 动态决定以达成最大吞吐;
  • GPU/HPU 模型:llama-3.1 8B、llama-3 70B、mixtral 8x7B;
  • CPU 模型:llama-3.1 8B;
  • 评估指标:吞吐(throughput)。

用例定义在 throughput-tests.json,参数直接透传给 vllm bench throughput,例如:

{
    "test_name": "throughput_llama8B_tp1",
    "parameters": {
        "model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
        "tensor_parallel_size": 1,
        "load_format": "dummy",
        "dataset": "./ShareGPT_V3_unfiltered_cleaned_split.json",
        "num_prompts": 200,
        "backend": "vllm"
    }
}

ShareGPT 数据集由执行脚本在运行前自动下载(ensure_sharegpt_downloaded,从 Hugging Face 拉取 ShareGPT_V3_unfiltered_cleaned_split.json,见 脚本第 83-90 行)。与延迟测试的固定批量不同,吞吐测试让引擎自行攒批到极限,因此 README 指出该数字同样"稳定但敏感"——微小的工况变化都可能引起较大波动。

吞吐结果表的列映射(见 convert-results-json-to-markdown.py 第 33-41 行)包括:Test nameGPU# of req.Total # of tokensElapsed time (s)Tput (req/s)Tput (tok/s),正好对应"请求数、总 token 数、耗时、每秒请求数、每秒 token 数"这组吞吐口径。

4. 服务测试(Serving tests):QPS、到达过程与 TTFT/ITL 指标

描述文档中 serving 一节的定义:

  • 输入/输出长度:同样从 ShareGPT 采样 200 条 prompt(固定随机种子)及其对应输出长度;
  • 批大小:由 vLLM 与请求到达模式共同动态决定;
  • 平均 QPS(query per second):取 1、4、16 与 inf。QPS = inf 表示所有请求一次性到达;其他 QPS 值下每条查询的到达时间由(固定随机种子的)泊松过程决定;
  • GPU/HPU 模型:llama-3.1 8B、llama-3 70B、mixtral 8x7B;另外在 GPU 上为 llama-3 70B 增加了 QPS 2 下的推测解码(speculative decoding)测试;
  • CPU 模型:llama-3.1 8B,并额外增加随机数据集测试,以 100 条 prompt 固定输入/输出长度来压测;
  • 评估指标:吞吐、TTFT(首 token 延迟,mean/median/p99)、ITL(inter-token latency,mean/median/p99)。

{serving_tests_markdown_table} 的列由 convert-results-json-to-markdown.py 第 45-74 行 的映射定义,覆盖面很广:ModelDataset NameInput LenOutput LenTP SizePP SizedtypeGPU# of req.qps# of max concurrency.Tput (req/s)Total Token Tput (tok/s)Output Tput (tok/s),以及 Mean/Median/P99/STD 四组 TTFT 和 Mean/Median/P99 三组 TPOT/ITL 列。

4.1 serving-tests.json 的 defaults + tests 结构

当前默认的用例文件 serving-tests.json 采用"默认参数 + 用例覆盖"结构:顶层 defaults 对全部 serving 测试全局生效,单条 tests 内可覆盖。摘录其骨架:

{
  "defaults": {
    "qps_list": ["inf"],
    "max_concurrency_list": [12, 16, 24, 32, 64, 128, 200],
    "server_parameters": {
      "model": "meta-llama/Llama-3.1-8B-Instruct",
      "tensor_parallel_size": 1,
      "dtype": "bfloat16"
    },
    "client_parameters": {
      "model": "meta-llama/Llama-3.1-8B-Instruct",
      "backend": "vllm",
      "ignore-eos": "",
      "temperature": 0,
      "num_prompts": 200
    }
  },
  "tests": [
    {
      "test_name": "serving_llama8B_tp1_sharegpt",
      "server_parameters": { "tensor_parallel_size": 1 },
      "client_parameters": {
        "dataset_name": "sharegpt",
        "dataset_path": "./ShareGPT_V3_unfiltered_cleaned_split.json"
      }
    },
    {
      "test_name": "serving_llama8B_tp1_random_2048_128",
      "client_parameters": {
        "dataset_name": "random",
        "random-input-len": 2048,
        "random-output-len": 128
      }
    }
  ]
}

tests 中的其余用例覆盖了 random 数据集的四种长度组合(128/128、128/2048、2048/128、2048/2048)、Llama-3.3-70B TP4(附带 async_schedulingno_enable_prefix_cachingmax_num_batched_tokens=8192 等服务器开关)等。注意 qps_listmax_concurrency_list 来自 defaults,脚本会先把二者合并进每个用例,再以 --request-rate--max-concurrency 传给客户端(合并逻辑见 run-performance-benchmarks.sh 第 566-606 行merge_serving_tests_stream;qps 遍历见 第 770-799 行)。

执行流程是:先用 server_parametersmodel 作为位置参数)拉起 vllm serve,轮询 http://localhost:8000/v1/models 等待就绪(最多 1200 秒),再运行:

vllm bench serve \
  --save-result \
  --result-dir results/ \
  --result-filename ${test_name}_qps_${qps}_concurrency_${max_concurrency}.json \
  --request-rate $qps \
  --max-concurrency $max_concurrency \
  --metadata tensor_parallel_size=$tp \
  <client_parameters 转换来的参数>

因此 README 的警告是:serving 用例 JSON 中不要配置 --save-results 之类的结果保存参数,保存动作由脚本统一完成。与 latency/throughput 相比,serving 数字受 ShareGPT 随机采样影响波动更大(README 原文:该测试数字不如延迟/延迟基准稳定,但 5% 量级的变化仍会引起明显差异)。脚本还支持通过 PROMPTS_PER_CONCURRENCY 环境变量按 max_concurrency 动态放大 --num-prompts,以及 REMOTE_HOST/REMOTE_PORT 对远端已有 vLLM 服务直接压测(见 脚本第 667-699 行第 740-763 行)。

5. 结果发布:模板占位符如何被填充

描述文档本质是一个带 5 个占位符的模板,转换脚本在结尾读取它并逐一填充(见 convert-results-json-to-markdown.py 第 390-405 行):

占位符 填充内容
{latency_tests_markdown_table} 延迟结果表(tabulate 的 pipe 格式)
{throughput_tests_markdown_table} 吞吐结果表
{serving_tests_markdown_table} 服务结果表
{platform_markdown_table} 平台信息表
{benchmarking_results_in_json_string} 三张结果表的合并 JSON 字符串

脚本按文件名把 results/ 下的 JSON 分流为三类:

  1. serving:额外读取同名 .commands 文件(记录本次实际执行的 server/client 命令),从中解析 --tensor-parallel-size--pipeline-parallel-size--dtype--dataset-name--random-input-len--random-output-len--request-rate,补全 TP/PP/dtype/数据集/QPS 等表格列(解析函数 parse_client_command脚本第 133-191 行);
  2. latency:从 percentiles 字段取 P10-P99 并换算为毫秒;
  3. throughput:直接附加命令元数据。

之后用 tabulate 渲染成 Markdown 表格,按 Test name 排序,写入 results/benchmark_results.mdresults/benchmark_results.json。在 Buildkite 环境中,执行脚本最后调用 upload_to_buildkitebuildkite-agent annotatebenchmark_results.md 贴到 job 页面,artifact upload 上传 results/ 全部内容(见 run-performance-benchmarks.sh 第 174-191 行);没有 agent 时静默跳过,本地运行时流程依然完整。

6. JSON 版本数据与 pandas 加载方式

描述文档专门保留了一节"json version of the benchmarking tables",说明表格数据同时以 JSON 形式内嵌在 Markdown 文件中,可直接载入 pandas:

import json
import pandas as pd

benchmarking_results_json = """The json string"""
benchmarking_results = json.loads(benchmarking_results_json)
latency_results = pd.DataFrame.from_dict(benchmarking_results["latency"])
throughput_results = pd.DataFrame.from_dict(benchmarking_results["throughput"])
serving_results = pd.DataFrame.from_dict(benchmarking_results["serving"])

这里的 JSON 字符串即模板中 {benchmarking_results_in_json_string} 占位符被替换后的内容,其顶层键为 latencythroughputserving,与各表 DataFrame 的 to_dict() 结果一一对应(序列化逻辑见 results_to_json)。文档同时提示:原始实验数据(每个用例的 JSON 结果文件)可以在 Buildkite 页面的 Artifact 标签页中查看。这意味着做性能趋势分析、跨版本对比时无需解析 Markdown 文本,直接消费 JSON 即可。

7. 平台信息表(Platform Information)

描述文档的 {platform_markdown_table} 占位符由脚本采集的机器信息填充(见 convert-results-json-to-markdown.py 第 317-336 行):

  • Physical cores / Total cores:psutil.cpu_count() 分别取物理核与逻辑核数;
  • Total Memory:psutil.virtual_memory().total 换算成 KB/MB/GB 单位;
  • Total NUMA nodes:在安装了 numa 包时通过 numa.info.get_num_configured_nodes() 获取;
  • CPU Brand:在安装了 cpuinfo 包时读取 brand_raw

这套信息解释了描述文档中"CPU Models"与 GPU/HPU 并存的原因:执行脚本通过 ON_CPU=1check_cpus(依赖 NUMA 节点数而非 GPU 数),并按 uname -m 区分 cpuarm64-cpu 后缀,自动选用 latency-tests-cpu.jsonthroughput-tests-cpu.jsonserving-tests-cpu.json(或 arm64 对应版本);Gaudi 3 则通过 hl-smi 识别并附加 -hpu 后缀(见 run-performance-benchmarks.sh 第 52-68 行第 836-886 行)。

8. 本地复现:触发方式与环境变量

整套基准需要在仓库根目录手动触发:

bash .buildkite/performance-benchmarks/scripts/run-performance-benchmarks.sh

运行前提:HF_TOKEN 必须设置且以 hf_ 开头(脚本会校验,check_hf_token),依赖 wgetcurljqlsof(缺失时会尝试 apt-get 安装),GPU 场景要求至少 1 块可见 GPU,CPU 场景要求至少 1 个 NUMA 节点。主要环境变量(README 列出的核心项):

变量 默认值 说明
ON_CPU 0 在 Intel Xeon 与 Arm Neoverse 上设为 1
SERVING_JSON / LATENCY_JSON / THROUGHPUT_JSON 空(用默认文件) 指定对应的测试用例 JSON 文件名
REMOTE_HOST / REMOTE_PORT 对远端已有 vLLM 服务压测
TEST_SELECTOR 只运行 test_name 匹配该正则的用例
DRY_RUN 0 为 1 时只打印命令不执行(可配合 MODEL_FILTERDTYPE_FILTER 过滤)

执行顺序为:先 serving(启动真实服务器),再 latency、startup、throughput;结束后 pip install tabulate pandas,运行转换脚本生成 benchmark_results.md/json,再运行 compare-json-results.py 与基线对比。需要留意:serving 用例中 GPU/HPU 的 70B 用例需要 4 卡(TP4),8 卡以下机器上 TP4 的 70B 用例会被脚本以"GPU 数量不足"自动跳过(见 run-performance-benchmarks.sh 第 720-725 行);load_format: "dummy" 表示用随机权重压测引擎性能而非具体模型精度,因此这套数字只应解读为引擎层面的性能回归信号,不代表该模型的端到端真实服务质量。

9. 小结

  • 描述文档定义了"测什么":latency 固定 32 输入/128 输出/batch 8,报 mean/median/p99 端到端延迟;throughput 用 200 条 ShareGPT prompt 让引擎自攒批冲极限吞吐;serving 用 QPS 1/4/16/inf(泊松到达或一次性灌入)测吞吐、TTFT 与 ITL 的 mean/median/p99;
  • 执行脚本定义了"怎么测":JSON 用例经 json2args 转成 vllm bench latency|throughput 参数,serving 测试则由脚本拉起 vllm serve 并以 vllm bench serve --request-rate --max-concurrency 压测;
  • 转换脚本定义了"怎么读":结果按列映射渲染为 Markdown 表格回填占位符,同时输出可被 pandas 直接加载的 JSON,原始数据以 Artifact 形式留存;
  • 想评估自己 PR 的性能影响,最稳妥的做法是用同一组测试 JSON、同一硬件与同一 load_format 跑前后两次,再用 JSON 结果做对比,避免被随机采样带来的正常抖动误导。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391