[PP] Batch independent chunks for small-chunk disaggregated prefill - #36214
Closed
YAMY1234 wants to merge 5 commits into
Closed
[PP] Batch independent chunks for small-chunk disaggregated prefill#36214YAMY1234 wants to merge 5 commits into
YAMY1234 wants to merge 5 commits into
Conversation
YAMY1234
force-pushed
the
pp-small-chunk-upstream-main-5commits-20260824
branch
3 times, most recently
from
August 24, 2026 19:37
7fc5386 to
d4dda5d
Compare
YAMY1234
force-pushed
the
pp-small-chunk-upstream-main-5commits-20260824
branch
from
August 24, 2026 20:53
d4dda5d to
7eca8ef
Compare
Collaborator
Author
|
Closing this draft because it changes aggregate batch construction and does not address the genuine fixed-small-forward PP bubble. The corrected implementation and matched benchmarks are in #36248. |
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.
Motivation
In PP disaggregated prefill,
chunked_prefill_sizecurrently serves two different purposes: the per-request chunk boundary and the aggregate token budget of the entire forward batch. Withchunked_prefill_size=2048, this limits every PP prefill forward to approximately 2K tokens even when many independent requests are waiting, so increasing client concurrency cannot recover GPU utilization and pipeline efficiency.This PR separates those two limits for an opt-in PP disaggregated-prefill path: each request remains capped by
chunked_prefill_size, while the batch can aggregate independent chunks up tomax_prefill_tokens. For the evaluated 2K configuration, one forward can therefore combine up to approximately 16 independent chunks instead of launching one approximately 2K-token forward at a time.Modifications
This PR is organized as five dependency commits:
PrefillAdderand usemax_prefill_tokensas the aggregate budget, allowing multiple independent middle chunks in one PP prefill batch.ignore_eosadmission path so it cannot consume the aggregate budget as one request.The first item is the throughput mechanism. Items 2-5 are correctness and liveness requirements introduced by batching multiple independent middle chunks; they are not unrelated scheduler fixes. The new path is guarded by
SGLANG_PP_BATCH_INDEPENDENT_CHUNKSand currently requires PP disaggregated prefill,max_prefill_tokens > chunked_prefill_size, overlap scheduling disabled, and ChunkCache (--disable-radix-cache). The default path is unchanged.The patch intentionally excludes one-page tail merging, pure-middle-chunk PP output skipping, and 2K prefill BCG because their controlled peak contributions were small, inconsistent, or negative.
Accuracy Tests
Matched GSM8K A/B used the same Qwen3.5 NVFP4 model, 4-GPU TP1 PP4 prefill, 4-GPU TP4 decode, and 2K per-request chunks. The protocol was 200 questions, five-shot chat, 128 threads,
temperature=0.6,top_p=0.95, andtop_k=20.Both runs completed 200/200 requests without errors, and their captured request payloads were byte-identical. Since the protocol uses stochastic sampling without a per-request seed, this is an accuracy non-regression result rather than an accuracy-improvement claim.
Scheduler correctness tests: 6/6 passed.
git diff --check, seven-filepy_compile, and lint also passed.Speed Tests and Profiling
Setup
nvidia/Qwen3.5-397B-A17B-NVFP4-V2chunked_prefill_size=2048, aggregate budget=2048chunked_prefill_size=2048,max_prefill_tokens=33792, aggregate FlashInfer dispatch budget=33792chunked_prefill_size=max_prefill_tokens=32768The controlled five-point performance run used the final no-tail/no-output-skip ablation source with runtime semantics equivalent to this PR. After diagnosing the C256 result, a same-configuration C128/C256 follow-up changed only the partial-capacity queue-ordering rule and source identity. The five commits were then cleaned and transplanted onto current upstream
main; the final main-based branch reran the targeted correctness and formatting tests but did not repeat the GB300 sweep. Every benchmark point completed all requests with exact 8192/1 lengths and zero non-empty errors.Baseline chunk-size sweep
The original 2K peak reached only 17.18% of the 32K peak. Raising client concurrency from 16 to 256 reduced 2K throughput by 2.68%, confirming that the aggregate forward shape, rather than request supply, was the limiting factor.
2K before and after
Peak-to-peak, the final core path improves 2K throughput from 30,507 tok/s at C16 to 171,489 tok/s at C256: 5.621x / +462.12%. It reaches 96.74% of the matched-concurrency 32K reference while preserving a 2K per-request chunk boundary. C128 also remains non-regressed at 170,652 tok/s, and C256 is 0.49% above C128 rather than falling 20.53% below it.
The C256 follow-up directly isolates the partial-capacity queue-ordering change:
Both C256 runs completed 2560/2560 requests with exact 8192/1 lengths and zero non-empty errors. Before the fix, a large waiting queue still produced repeated 2K multiples because a few newly available request slots were consumed by slotless requests before the scan reached slot-owning continuations. After the fix, the full-batch ratio rises to 95.94%, which explains the throughput recovery without changing the 2K per-request cap or any kernel.
An earlier batching-only prototype already reached 52,246 / 92,368 / 143,483 tok/s at C16/C32/C64, or 1.71x / 3.05x / 4.77x over the original 2K baseline, before request-slot saturation stopped C128. This isolates independent-chunk aggregation as the primary throughput mechanism; the slot reuse and queue-ordering commits make the new mechanism complete at C128/C256 rather than accelerating an individual GPU forward.
Excluded micro-optimizations
These increments were measured in the controlled sweep before the final partial-capacity queue follow-up and are not combined with the new C256 result.
Tail merging plus output skipping increased peak throughput from 168,421 to 170,363 tok/s, only +1.15% in one run, while showing inconsistent effects across concurrency. They are intentionally left out of this PR so the upstream patch contains only the dominant batching mechanism and its required correctness/liveness support.
Checklist