[PENDING: #735] test: side-by-side offered-load parity against vllm bench - #736
Open
Bslabe123 wants to merge 4 commits into
Open
[PENDING: #735] test: side-by-side offered-load parity against vllm bench#736Bslabe123 wants to merge 4 commits into
Bslabe123 wants to merge 4 commits into
Conversation
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Bslabe123 The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Bslabe123
marked this pull request as ready for review
August 18, 2026 16:51
Bslabe123
force-pushed
the
test/tool-parity-absorber
branch
from
August 18, 2026 17:05
9bf8546 to
33dfda0
Compare
Bslabe123
force-pushed
the
test/tool-parity-absorber
branch
from
August 18, 2026 18:19
33dfda0 to
500c2f0
Compare
Bslabe123
force-pushed
the
test/tool-parity-absorber
branch
from
August 19, 2026 20:16
500c2f0 to
5631d4d
Compare
Bslabe123
force-pushed
the
test/tool-parity-absorber
branch
from
August 26, 2026 15:50
5631d4d to
76f4bee
Compare
Bslabe123
force-pushed
the
test/tool-parity-absorber
branch
from
August 26, 2026 17:48
76f4bee to
289f833
Compare
Sim-backed e2e for the stimulus side of the load generator: that the load actually offered matches the load that was configured. Nothing verified this before, although docs/loadgen.md states the concurrent load type "achieves the exact concurrency specified". Adds e2e/utils/load_shape.py with the reconstruction helpers (in-flight sweep line, closed-loop plateau window, arrival-process tolerance) so the worker matrix in kubernetes-sigs#632 can reuse them. Adds a test module with four sim-backed cases (constant and poisson rate stages, concurrency levels divisible and not divisible by num_workers) plus eight helper self-tests that prove the assertions can go red. Delivered concurrency is reconstructed from the raw per-request start and end timestamps, not read off load_summary["concurrency"], which reportgen copies straight from the stage config. Part of kubernetes-sigs#633.
… serve Point both tools at an absorber (an OpenAI-compatible server whose job is to record every request while streaming realistically paced responses) and assert on the load each tool actually offered: request count, per-request prompt token lengths and max_tokens, sampling flags, realized arrival rate, and peak concurrency. Reported-metric parity is deliberately out of scope; historically the discrepancies live in workload interpretation (range-ratio semantics, warmup requests, arrival process, worker caps), not in the runners. Cross-tool metric deltas are unowned behavior, so this is a diagnostic, never a merge gate. Each case is a directory: an inference-perf config, a verbatim vllm bench serve arg file, and the invariants both must satisfy, so adding a parity case means adding files, not editing Python. Per-tool warmup traffic is declared per case (vllm bench's initial test request), keeping the asymmetry visible instead of silently absorbed. Every vllm flag in the case files was read off the pinned tag's vllm/benchmarks/serve.py and datasets.py rather than guessed, including the --random-range-ratio semantics that motivated the issue and the single unconditional initial test request the warmup trim accounts for. The vllm leg resolves an executable from $VLLM_BENCH_BIN or an opt-in cached provision of a pinned vllm, and skips cleanly when neither exists; the inference-perf leg and the absorber need no external binary, so the suite asserts something everywhere it runs. The case invariant files are excluded from the repo-wide config schema gate by a glob, so a new case directory stays a files-only change while its sibling inference-perf config keeps being schema-validated.
Docstrings, comments, README and assertion messages only; no code, YAML values or vllm args change. Adds a plain-language summary above every function in the parity test, defines the terms (workload, case, absorber) up front in the README, and replaces the statistics derivation in a_fixed_rate/expected.yaml with the practical reading of it.
The absorber now records when each reply finished (done_s) alongside the arrival time and stops keeping its own in-flight counter. The parity test feeds those arrival/finish pairs to e2e/utils/load_shape.py: rate via observed_send_rate, concurrency via the sweep line and assert_delivered_concurrency (peak never above C, time-weighted plateau mean within half a slot), so there is one definition of each in the e2e tier. rate_rel_tol is gone from expected.yaml. Each tool declares its spacing pattern (tools.<tool>.arrival: constant|poisson) and the tolerance is rate_tolerance(num_requests, arrival). Case a rises from 40 requests at 8/s to 600 at 40/s, the smallest count at which the Poisson side earns a useful bound (16%), matching the load-shape accuracy test. Measured against the absorber: rate 40.01/s (5% budget), plateau mean 7.88 of 8 (half-slot budget); C-1 and C+1 both fail.
Bslabe123
force-pushed
the
test/tool-parity-absorber
branch
from
September 3, 2026 20:30
289f833 to
9c7dfad
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #481. Runs inference-perf and
vllm bench serveagainst the same recording server and asserts the two tools offered the same workload, which nothing in this repo checks today.Row in #606: "End-to-end / Peer-benchmark skew (#481)", type
sim.Stacked on #735 (
test/load-shape-accuracy-633,9b8c938); its commit shows in this diff until it merges. Rate and concurrency here are computed by #735'se2e/utils/load_shape.py, so the e2e tier has one definition of each. #735 reads the client's own timestamps; this reads the server's.Why this is needed
Two recent skew reports were first read as inference-perf bugs and both decomposed into workload non-equivalence (the legacy
range_ratiofootgun,0.0meaningUniform[0, len]; length-sampling, max-model-len and warmup deltas). Nothing could ask whether the two tools were even asked for the same thing.This harness never merge-gates, by design. A delta can move from an inference-perf regression, a peer-tool change, or workload non-equivalence, and a gate cannot attribute which. The workload mapping is ours and asserted loudly; peer results are not ours and never asserted on.
What the test does
e2e/utils/absorber.py), an OpenAI-compatible aiohttp server that records every request (arrival, reply-finished, body) while streaming at a configured TTFT and inter-chunk interval. The recorded requests are the offered workload; no stored baseline.expected.yaml: exact request count,max_tokensmultiset,streamandignore_eosflags, per-request prompt tokens under the shared tokenizer (with tolerance), and either delivered rate withinrate_tolerance(n, arrival)or delivered concurrency viaassert_delivered_concurrency(never above C, time-weighted plateau mean within half a slot).tools.<tool>.arrival: constant|poisson); the tolerance follows from the request count. Tightening a case means raisingnum_requests.leading_extra_requeststrims the earliest N arrivals for one tool; a nonzero value is itself a parity finding.The drop-in case contract (the reusable part)
Adding a case touches no Python. Starter cases:
a_fixed_rate(40 QPS, 15s, 600 requests: the smallest count at which the Poisson side earns a useful 16% bound, matching #735) andb_fixed_concurrency(48 requests at concurrency 8).Verified against the pinned vllm source, not by running it
Read from tag
v0.10.0:benchmark()always runs one warmup prompt first (leading_extra_requests: 1);--random-range-ratio 0gives fixed lengths;--max-concurrencyis a semaphore;--random-input-lenis reduced by the special-token count (henceprompt_tokens_rel_tol);--request-rateat default--burstiness 1.0is Poisson (arrival: poisson);--backendis vestigial, so args files corrected to--endpoint-type openai;stream: trueis hardcoded, sostream: falseis not expressible on the vllm leg.transformers<5is required (5.13 droppedall_special_tokens_extended).Status
Verified locally:
pdm run validateclean;pdm run test898 passed, 16 skipped;pdm run pytest e2e/tests/parity3 passed, 4 skipped. Against the absorber: casearate 40.01/s on a 5% budget; casebplateau mean 7.88 of 8 on a half-slot budget (the server sees the client's turnaround gap; client-side timestamps do not); C-1 and C+1 both fail.Not verified:
vllm bench's parsing, or that both tools land inside tolerance.prompt_tokens_rel_tol: 0.15is sized by argument, not observation.VLLM_PIN_DATEstill warns, deliberately.aiperfnot started.