llm-inference-benchmark — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited llm-inference-benchmark (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
One tool, one methodology, engine-agnostic: `sglang.bench_serving` as a pure HTTP load generator, always hitting the OpenAI `/v1/completions` endpoint (every serious engine serves it), always running as a standalone dockerized client in its own net namespace — never docker exec into the server, never --network host. The server's identity (engine, quant, flags) is measured into the log, not assumed: every run opens with a PROVENANCE header.
The point of a sweep is the saturation curve's two knees. Read them off a wide concurrency sweep on a non-binding server: the min knee (highest concurrency where TTFT/TPOT is still flat — the latency-optimal cap) and the max knee (where output throughput goes flat — the throughput ceiling). A production concurrency cap belongs between them — see Finding the saturation knees below.
The reference dataset (Kimi-K2.6 on 8× RTX PRO 6000 Blackwell SE, deployed by deploy-kimi-k26-on-rtx-pro-6000) lives in REFERENCE.md — use it as the comparison anchor when re-benchmarking that hardware after an image bump, config change, or engine swap.
/v1/completions on TARGET_HOST:PORT (local LAN IP or a peer host's).$HF_HOME (random-ids needs onlythe vocab; any same-tokenizer repo works — see cross-host notes in REFERENCE.md).
lmsysorg/sglang:v0.5.12.post1-cu130 by default — theclient is CPU-only; vLLM's image ships no bench tool, so even vLLM servers are benched with this).
bash scripts/bench_sweep.sh # local server, conc {1,8,16,32,64,128}, 1024in/256out
TARGET_HOST=192.168.55.227 MODEL_NAME=kimi-k2.6 \
MODEL_REPO=nvidia/Kimi-K2.6-NVFP4 bash scripts/bench_sweep.sh # cross-host (peer LAN IP)
CONC="1 8 16 64 128" PROMPTS_PER=8 LOG=./bench.log bash scripts/bench_sweep.sh| Knob | Default | Meaning |
|---|---|---|
TARGET_HOST | this host's LAN IP | server address (a bridged client can't use the server-host's 127.0.0.1) |
PORT | 30000 | server port |
MODEL_NAME | kimi-k2.6 | the request model field — MUST match the server's served name |
MODEL_REPO | moonshotai/Kimi-K2.6 | tokenizer source, resolved offline from the client host's $HF_HOME |
CONC | 1 8 16 32 64 128 | concurrency sweep points (dense enough to locate the knee — c16/c32 matter) |
PROMPTS_PER | 8 | num_prompts = PROMPTS_PER × concurrency (sustained load — see Methodology) |
IN / OUT | 1024 / 256 | random-ids input/output lengths |
SERVER_NAME | (empty) | LOCAL server container name — stamps its launch flags + KV pool into the header (auto-skipped for remote targets) |
LOG | ./bench.log | output log (PROVENANCE header + per-point metrics + parsed summary table) |
BENCH_IMG | the SGLang image | client image |
num_prompts = PROMPTS_PER × concurrency (uniform prompts_per=8).Short bursts never reach steady state and over-report high concurrency (a 192-prompt c128 run read 613 tok/s where the sustained number is 377.7).
CONC, PROMPTS_PER, IN/OUT, same endpoint.a MAX_SEQS=16 server is 16-wide with a 48-deep queue). Never read across tables with different caps.
/v1/completions (`--backendsglang-oai, byte-identical to the vllm` backend) and a bridged (own-netns) client. Client placement/network mode alone moves c1 readings by up to ~10% (see REFERENCE.md); never mix client paths or endpoints within a comparison.
/v1/models, launch flags + KVpool when local, grid) — a number without its header is not a baseline.
A wide concurrency sweep on a non-binding server (uncapped, or one fixed cap above your top sweep point with a KV pool that holds it) exists to surface two knees:
usually does) → the latency-optimal cap.
concurrency buys only TTFT).
They needn't coincide: TTFT (prefill + queue) usually degrades before output throughput (decode) plateaus, so min knee ≤ max knee (equal only when decode-bound). Put a production cap (--max-num-seqs / SGLang --max-running-requests) in [min knee, max knee] — toward min for latency, max for throughput.
Keep the cap non-binding, or you measure the cap, not the box. Throughput/TPOT are set by the running concurrency (the server cap); --max-concurrency is only the offered concurrency. A cap below your top sweep point fakes a knee at the cap (every offered ≥ cap runs cap-wide → tput + TPOT flat, only TTFT climbs). Never set cap = per-point concurrency (resizes the server and its KV pool each point, erasing the signal — that measures throughput-vs-batch-width, not saturation).
Real knee vs false knee — three checks:
binding running below offered). A real compute knee instead has tput flatten while TTFT and TPOT rise together, gently — a genuinely wider batch with the GPU as bottleneck, not a queue.
num_running_reqs/num_waiting_reqs, or vLLM running/pending):running plateaus at MAX_SEQS → cap binding (raise it); running plateaus below cap and below offered → KV pool exhausted (e.g. marlin's 139K pool caps c128 at ~108 → raise fp8/util); running keeps tracking offered but tput is flat → real compute/comm knee.
climbs the knee was an artifact, so keep raising until tput stops responding. The concurrency past which a bigger cap buys no throughput is the real knee.
Picking the production cap — the running batch sets throughput + TPOT; offered load above it just queues, surfacing as TTFT (at a cap of 64: c64 = 64 running / 0 queued, c128 = 64 running / 64 queued — same throughput + TPOT, far worse TTFT). Choose by goal:
throughput is flat anyway; capping there only avoids non-productive running requests and bounds TPOT).
the max knee. (E.g. SGLang INT4's throughput knee is ~c32 at 345 tok/s / ~2.3 s TTFT; by c64 throughput is flat but TTFT is ~24 s — an SLA of TTFT < 1 s would cap below c32.)
Forced-cap exception: an engine that can't boot uncapped at the target context is benched through a fixed cap and its curve is valid only up to it (NVFP4 flashinfer_b12x uncapped profiles a 49K pool < one 131K request → won't start; a c > cap point is just cap + queue).
Prefill- vs decode-bound (read it off the same sweep). Two tells: (1) knee gap — min knee ≪ max knee (TTFT degrades well before throughput plateaus) ⇒ prefill/queue is the first bottleneck at this shape; min ≈ max ⇒ decode-bound (combo A: min≈max≈c32, decode-bound; combo B: min≈c32 ≪ max > c128, prefill-contended). (2) c1 rates — prefill rate ≈ IN/TTFT, decode rate ≈ 1/TPOT; compare per-request prefill time (IN/prefill_rate) vs decode time (OUT × TPOT). Boundedness is shape-dependent (the default 1024-in/256-out is input-heavy, 4:1), so to classify the box directly sweep two shapes — prefill-heavy (IN=4096 OUT=16) vs decode-heavy (IN=128 OUT=2048) — and see which one saturates first.
TARGET_HOST=<peer-lan-ip>; MODEL_REPO must be cached client-side (it's only thetokenizer — an NVFP4 host benching a remote INT4 server uses its local NVFP4 repo).
--base-url https://<host> and -e OPENAI_API_KEY=<key> (auto-sent as Authorization: Bearer). Measured Caddy overhead on the reference host: ~1% throughput, +15 ms TTFT @ c1 — REFERENCE.md.
PROVENANCE header prints but zero metrics + instant SWEEP_DONE → a host INPUT firewall is dropping the bridged client (src 172.17.x); "<repo> not in HF cache" → cache the tokenizer repo on the client host; empty /v1/models in the header → wrong TARGET_HOST/PORT or server not up; all-? summary rows → requests failing, check MODEL_NAME matches the server. More in REFERENCE.md.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.