Vllm benchmarking
Claude Code plugin marketplace — 58 installable reference skills across vLLM/SGLang inference, Kubernetes & Harvester, GPU host bring-up, observability, security, and agent workflows.
npx -y skills add air-gapped/skills --skill vllm-benchmarkingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Run production vLLM benchmarks — `vllm bench` (serve, throughput, latency, sweep, startup, mm-processor), request-rate vs max-concurrency semantics, TTFT/TPOT/ITL/E2EL percentiles, goodput SLO measurement, prefix-cache workloads, air-gapped operation (HF_ENDPOINT, ModelScope, hf-mirror, offline cache). Methodology split — SLO health checks vs A/B change sweeps — plus pitfalls that produce misleading numbers (no warmup, wrong tokenizer, random-as-prod, `--request-rate inf` alone).
SKILL.md
11.1 KB, ~2.6k tokens by cl100k_base, as published. Nobody here has run it
vLLM benchmarking
Target audience: operators producing defensible latency/throughput numbers against production or pre-production vLLM deployments, on datacenter GPUs, often in containerized or air-gapped environments.
This skill measures; it does not tune. Once a number is trusted and the
verdict is "too slow", the knobs live elsewhere in the vllm plugin:
vllm-performance-tuning (scheduler, MoE kernels, CUDA graphs, parallelism),
vllm-caching (KV tiering when the bottleneck is prefill or cache capacity),
vllm-nvidia-hardware (the SKU's own ceiling). Measure → change one thing →
re-measure with the same methodology; a tuning change compared against a
differently-shaped benchmark run is not evidence.
Why this matters
Bad benchmarks are worse than no benchmarks — they drive the wrong decisions with false confidence. The three common failure modes:
- Wrong methodology.
--request-rate infanswers "saturation throughput," not "TTFT my users see." Mixing those up leads to buying GPUs to solve a latency problem, or shipping a latency regression because total throughput looked fine. - Wrong workload.
--dataset-name randomhas zero prefix structure. Real coding-agent or RAG traffic has heavy prefix reuse. Benchmarking caching wins on random produces numbers that don't survive contact with prod. - No warmup / wrong tokenizer. First N requests hit cold CUDA graphs. Token counts are fiction unless
--tokenizermatches the served model exactly.
The cost of getting this right is small; the cost of getting it wrong is buying the wrong hardware.
Decision tree — which subcommand
| Question | Command | Why |
|---|---|---|
| "Saturation throughput of this offline batch" | vllm bench throughput | Submits N prompts at once, measures tok/s. No server. |
| "Single-batch generation latency" | vllm bench latency | Fixed batch size, repeated N times. Warmup included. Good for kernel-level regression. |
| "Production serving performance" | vllm bench serve | HTTP-level, Poisson arrivals, percentile metrics, honors concurrency caps. Use this for serving. |
| "Find best config under SLO" | vllm bench sweep | Parameter sweep + auto-tune. Finds max throughput subject to P99 < X ms. |
| "Cold-start / container boot latency" | vllm bench startup | Time from process launch to first-token-ready. |
| "Multimodal processor overhead" | vllm bench mm-processor | Image/video preprocessing cost before decode. |
Most production questions route to vllm bench serve. Reach for the others only when the question is specifically kernel-level (latency), offline-batch (throughput), or SLO auto-tuning (sweep).
The two methodologies operators actually need
Methodology A: health check / SLO validation
Question: "Does my running deployment meet the latency SLO under realistic load?"
- Fixed
--max-concurrencymatching the production in-flight ceiling (NOT--request-rate). - Realistic input/output length distribution — ideally replayed from production logs via
--dataset-name customwith a JSONL file. - Sustained 10+ minute run to cover warmup + steady state.
- Report: P50/P95/P99 TTFT, P95/P99 ITL, throughput (tok/s, req/s).
- Compare against the SLO. Pass/fail.
vllm bench serve \
--model <served-model> \
--base-url http://<endpoint> \
--dataset-name custom \
--dataset-path /data/captured-prod-prompts.jsonl \
--max-concurrency 32 \
--num-prompts 2000 \
--percentile-metrics ttft,tpot,itl,e2el \
--metric-percentiles 50,95,99 \
--save-result --output-json health-check.json
Methodology B: change comparison / A/B
Question: "Does config change X make it faster, and at what cost?"
- Request-rate sweep, not a single rate: e.g. 1, 2, 4, 8, 16, 32, inf req/s.
- Plot throughput vs P99 latency — the knee of the curve is the usable operating point. A config that shifts the knee right is a win.
- Same seeds, same
--num-prompts(≥500), same dataset on both sides. - Run A and B back-to-back on the same hardware in the same session to avoid thermal/neighbor noise.
See scripts/bench-sweep.sh for a parametrized sweep runner that emits one JSON file per rate for plotting.
Critical pitfalls
- No warmup. First 30–60 s hit cold CUDA graphs / torch.compile caches.
vllm bench servedoes not auto-warm (v0.11–v0.25;--num-warmupsdefault re-read as0on 2026-07-21) — pre-flight the server with a few requests, or set--num-promptslarge enough (≥500) to amortize.latencydoes warm up via--num-iters-warmup(default 10). - Wrong tokenizer.
--tokenizerdefaults to--model, but if they differ (e.g., served via a local path while benching with a HF ID), every token count in the output is fiction. Always specify explicitly. --dataset-name randomas a proxy for production traffic. Random has zero prefix structure, overstates prefill work, understates prefix-cache hit rate, makes chunked prefill look worse than reality. For anything involving caching claims, usecustomwith a real-traffic JSONL, orprefix_repetitionfor synthetic prefix-heavy tests.--request-rate infalone. Measures saturation throughput, not the latency regime users experience. Always include a concurrency sweep for serving comparisons.--endpoint-typeis removed. Deprecated in v0.11.0, now gone. Use--backend. Current full value set (docs.vllm.ai, verified 2026-04-24):openai,openai-chat,openai-audio,openai-embeddings,openai-embeddings-chat,openai-embeddings-clip,openai-embeddings-vlm2vec,vllm,vllm-chat,vllm-pooling,vllm-rerank,infinity-embeddings,infinity-embeddings-clip.- Conflating tok/s with req/s. High total-tokens/sec can coexist with terrible TTFT. Always report both plus P99 ITL.
- Noisy neighbor. Shared GPU, unrelated container load, MIG partition changes mid-run — check
nvidia-smi dmonfor unrelated activity before trusting numbers. latencysubcommand disables prefix caching by default (to keep numbers clean). If benchmarking prefix-cache behavior, useservewith theprefix_repetitiondataset.
For the full flag reference for each subcommand, see references/commands.md. For the dataset catalog and when to use each, see references/datasets.md.
Air-gapped environments
Operators who can't reach huggingface.co have three working patterns:
- Reroute to a mirror — set
HF_ENDPOINT=https://hf-mirror.com(or an internal reverse-proxy URL).huggingface_hubtreats it transparently. - ModelScope — set
VLLM_USE_MODELSCOPE=Trueplustrust_remote_code=True. Historical gap: LoRA adapter loading through ModelScope (vLLM issue #32841, closed 2026-01-23). Re-verify on your vLLM version before relying on LoRA-via-ModelScope; issue closure without a linked PR means status is unclear — test first. - Fully offline with pre-seeded cache —
HF_HUB_OFFLINE=1+TRANSFORMERS_OFFLINE=1,HF_HOMEpointing at a pre-populated directory (NFS, PVC, or JuiceFS/S3).
For benchmark datasets specifically: sonnet is in-tree at vllm/benchmarks/sonnet.txt — never downloads. random is synthetic — never downloads. sharegpt must be pre-staged: wget the JSON on a connected host, rsync into the enclave, point --dataset-path at it.
For the full air-gapped recipe (HF proxy setup, gated model tokens, MinIO-as-HF-cache, transformer cache warming), see references/air-gapped.md.
Measuring the outcomes that matter
Default metrics (--percentile-metrics ttft,tpot,itl,e2el):
- TTFT — time-to-first-token. User-facing responsiveness. Dominated by prefill.
- TPOT — time-per-output-token (averaged across decode). Steady-state perceived speed.
- ITL — inter-token latency (per-step). Catches stalls that TPOT averages away.
- E2EL — end-to-end request latency. Only one that matters for pooling/embedding models.
Reporting guideline: always P50 and P99 together. Either in isolation is misleading. Add P95 if ITL has a long tail.
Goodput SLO — --goodput KEY:VALUE (milliseconds) tracks requests that completed within an SLO budget. Example: --goodput ttft:500 itl:50. Goodput is what actually matters in production; raw throughput that violates SLO is useless.
For methodology detail (warmup protocols, sweep design, SLO-constrained auto-tune, how to capture real-traffic prompts for replay), see references/methodology.md.
When numbers look wrong or a run crashes
See references/troubleshooting.md for the failure modes: tokenizer mismatch (numbers off 20–40%), cold-cache contamination (suspiciously fast), air-gapped hang (incomplete HF_HUB_OFFLINE setup), goodput=0 (unit error), noisy-neighbor ITL variance, and the full "what to include in a bug report" checklist.
Parsing the output JSON
See references/output-schema.md for the field layout in --output-json — top-level fields (request_throughput, output_throughput, total_token_throughput), the mean_/median_/std_/p<N>_<metric>_ms pattern, speculative decoding fields, and which names are stable across versions vs renamed.
External references
- vLLM bench CLI docs: https://docs.vllm.ai/en/latest/benchmarking/cli/
vllm bench servereference: https://docs.vllm.ai/en/stable/cli/bench/serve/- Performance dashboard (nightly reference numbers): https://docs.vllm.ai/en/latest/benchmarking/dashboard/
- In-tree benchmarks dir: https://github.com/vllm-project/vllm/tree/main/benchmarks
- Air-gapped discussion thread: https://discuss.vllm.ai/t/setting-up-vllm-in-an-airgapped-environment/916
- vLLM env vars (including
VLLM_USE_MODELSCOPE): https://docs.vllm.ai/en/stable/configuration/env_vars/ - Blog: Anatomy of a High-Throughput LLM Inference System (2025-09-05): https://blog.vllm.ai/2025/09/05/anatomy-of-vllm.html
- Blog: Large Scale Serving — DeepSeek @ 2.2k tok/s/H200 (2025-12-17): https://blog.vllm.ai/2025/12/17/large-scale-serving.html
What ships with it: 9 files
50.5 KB alongside SKILL.md, 1 of them executable
references/
- air-gapped.md5.3 KB
- commands.md6.9 KB
- datasets.md5.3 KB
- improvement-backlog.md3.9 KB
- methodology.md5.9 KB
- output-schema.md4.8 KB
- sources.md9.0 KB
- troubleshooting.md7.1 KB
scripts/
- bench-sweep.shruns2.4 KB