Repository navigation
perf: cut per-token lookups and RNG cost in vLLM speculative emission - #637
Conversation
📝 Summary
Merge Risk:
|
emit_speculative_ready_tokens looked each ready request up about eight times per pass plus three more times per emitted token, and recounted the decode batch that emit_ready_tokens had already counted. Build one burst record per ready request (limit, remaining tokens, acceptance eligibility, decode length), price the forward from the surviving records, then sample and emit each burst under a single get_mut. Sampling order and draw count are unchanged, so replay output is identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
The ChaCha12 StdRng behind SpeculativeDecodeSampler cost 4-6% of speculative replay. Acceptance sampling only needs a fast seeded stream, so use rand's SmallRng (Xoshiro256++ on 64-bit targets), which the default rand features already provide. This changes the sampled acceptance stream at fractional rates for vLLM and SGLang. Seeds, per-rank offsets and rates of 0 and 1 are unchanged. The fractional-rate pin test is re-recorded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
efb7176 to
093fa1c
Compare
tedzhouhk
left a comment
There was a problem hiding this comment.
Reviewed speculative reservation, survivor-only timing, acceptance accounting, and emission/completion boundaries. Local Rust unit/integration suites passed 2,579 tests (one data-dependent test intentionally ignored). An independent 168-case replay matrix matched the parent exactly on the refactor-only commit; the final head differed only in the 41 fractional-acceptance cases, with completed-request and output-token totals preserved. The disclosed RNG stream change also reaches the TensorRT-LLM simulation through the shared core. No actionable correctness findings; current-head Full CI is green. Author-reported performance benchmarks were not rerun.
…ai-dynamo#637) * perf: look up each request once per pass in vLLM speculative emission emit_speculative_ready_tokens looked each ready request up about eight times per pass plus three more times per emitted token, and recounted the decode batch that emit_ready_tokens had already counted. Build one burst record per ready request (limit, remaining tokens, acceptance eligibility, decode length), price the forward from the surviving records, then sample and emit each burst under a single get_mut. Sampling order and draw count are unchanged, so replay output is identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: jthomson04 <jwillthomson19@gmail.com> * perf: sample speculative acceptance with SmallRng The ChaCha12 StdRng behind SpeculativeDecodeSampler cost 4-6% of speculative replay. Acceptance sampling only needs a fast seeded stream, so use rand's SmallRng (Xoshiro256++ on 64-bit targets), which the default rand features already provide. This changes the sampled acceptance stream at fractional rates for vLLM and SGLang. Seeds, per-rank offsets and rates of 0 and 1 are unchanged. The fractional-rate pin test is re-recorded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: jthomson04 <jwillthomson19@gmail.com> --------- Signed-off-by: jthomson04 <jwillthomson19@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Why and what changed
Speculative replay (ngram, MTP) spent about 40% of replay in
VllmCore::emit_speculative_ready_tokens. Most of that was repeatedFxHashMap<Uuid, _>lookups: about 8 per ready request per pass, plus 3 per emitted token. The ChaCha12 acceptance sampler accounted for another 4–6%.get_mut. RNG draw order and draw count are unchanged.rand'sSmallRng(Xoshiro256++) instead ofStdRng(ChaCha12). Fractional acceptance rates now produce different seeded streams for vLLM and SGLang. Seeds, per-rank offsets, and rates of 0 and 1 are unchanged.Review map
speculative_burstsandemit_speculative_ready_tokensincrates/core/src/engine/scheduler/vllm/core.rs, especially decode pricing after reservation drops or preempts a request.SmallRng's algorithm, and so the stream for a given seed, may change on arandupgrade. This is noted on the sampler.Evidence
cargo test -p aisimulate-core --lib --tests;pytest -c pytest.ini tests/test_ngram_cli.py tests/test_runner.pyand the other speculative replay suites; SDK speculation tests.max_model_len, and preemption. It was recorded on main, passes unchanged on commit 1, and is re-recorded by commit 2.wall_time_ms.prediction.jsonmatches main for both workloads and for SGLang MTP.--capture-per-request.Modeling or data provenance
N/A
🤖 Generated with Claude Code