Skip to content

Fix stale batch fullness after chunked prefill - #35609

Closed
guptaishaan wants to merge 1 commit into
sgl-project:mainfrom
guptaishaan:fix-35537
Closed

guptaishaan wants to merge 1 commit into
sgl-project:mainfrom
guptaishaan:fix-35537

Conversation

@guptaishaan

@guptaishaan guptaishaan commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

Fixes #35537.

batch_is_full could remain set after the final chunked-prefill pass. The next scheduler pass returned before recalculating available request slots, which left a waiting request queued until a running request finished.

Thanks to @atlantistony for the report and detailed trace.

Modifications

Reset batch_is_full at the start of each prefill admission pass. Add a regression test that starts with the stale post-chunk state and verifies that the waiting request reaches admission.

Accuracy Tests

Not applicable. This does not change model output computation.

Speed Tests and Profiling

Not run. The focused scheduler test passed on a Linux node with 8 NVIDIA A40 GPUs, with CUDA hidden for the CPU unit test. The full reported Qwen3.8 NVFP4 setup could not run because A40 is sm_86.

Checklist

Review and Merge Process

  1. Ping Merge Oncalls to start the process. See the PR Merge Process.
  2. Get approvals from CODEOWNERS and other reviewers.
  3. Trigger CI tests with comments or contact authorized users to do so.
    • Common commands include /tag-and-rerun-ci, /tag-run-ci-label, /rerun-failed-ci
  4. After green CI and required approvals, ask Merge Oncalls or people with Write permission to merge the PR.

CI States

Latest PR Test (Base): ❌ Run #38208264284
Latest PR Test (Extra): ❌ Run #38208264108
Latest PR Test (AMD ROCm 10): ❌ Run #38208264211

@guptaishaan

Copy link
Copy Markdown
Contributor Author

Rebased onto current main. The scheduler change is unchanged. In the regression test I added scheduler.processed_tokens_counter = 0, since calc_priority now takes it and the bare Scheduler in the test would otherwise fail on that instead of the behavior under test.

The pr-test-finish failure came from call-gate / pr-gate ("Require run-ci label"). No test job ran or failed, so it is not caused by the change. It will need the run-ci label or /tag-and-rerun-ci from a maintainer.

I re-ran test_scheduler_chunked_req_gate.py on CPU: it passes, and the new test fails when the scheduler change is reverted.

Reset batch_is_full before each prefill admission pass so current request
capacity is evaluated. Add a regression test for a waiting request after
the final chunked-prefill pass.
@guptaishaan

Copy link
Copy Markdown
Contributor Author

Rebased onto current main.

One conflict in _get_new_batch_prefill_raw: #41872 added a batch_is_full reset when running_batch.is_empty(). That does not cover this issue, where the running batch is non-empty and the flag was latched by the last chunked-prefill pass, so I kept the unconditional reset, which also covers the cases main handles.

I also set running_batch.is_empty.return_value = False in the regression test. With the mock's default truthy is_empty() the test would pass on main even without the fix. With that change it passes with the fix and errors without it. test_scheduler_chunked_req_gate.py passes on CPU.

@hnyls2002

Copy link
Copy Markdown
Collaborator

Thanks @guptaishaan, the symptom was real. Its cause was a slot double count rather than the latch itself: a chunked request keeps its req_to_token row across chunks, so available_size() already excluded it while can_run_list counted it again, which set batch_is_full on the final chunk with a row still free. #44401 fixes that count on main and keeps the latch, so resetting batch_is_full every pass is no longer needed. Closing as superseded; please reopen if #35537 still reproduces on main.

@hnyls2002 hnyls2002 closed this Oct 15, 2026
detain added a commit to detain/sglang that referenced this pull request Oct 29, 2026
[Fix] scheduler: keep chunked prefill within allocatable KV under memory
pressure. Three admission bugs: (1) a continuation chunk could ask
alloc_extend for more KV than is free -- PrefillBudget.
available_chunk_tokens now caps by real free KV minus the one-page
over-ask and defers (None) instead of forcing a full chunk; (2) the
single-unfinished-chunk guard now applies to ALL policies, not just
shortest-prefill-first (a second unfinished chunk was untrackable);
(3) batch_is_full is cleared unconditionally each round -- a latched
flag was otherwise only cleared when the running batch shrinks,
stalling the waiting queue until an unrelated finish (absorbs closed
sgl-project#35609).

UNION / DEVIATIONS:
- scheduler.py hunk hand-merged: our region carried the entry-198
  hybrid-SSM reset arm + is_empty arm; both are strict subsets of the
  unconditional clear and were removed. Entry-198's COW NO_TOKEN-retry
  semantics are unaffected (admission re-runs every round anyway).
- Consequently the two entry-198 gate tests were re-pinned to the new
  unconditional behavior (non-hybrid now retries every round too);
  their mamba-arm and COW-recovery cases pass unchanged.
- PR's new test_scheduler_batch_is_full_latch.py NOT imported: the
  file already exists in-tree (entry-222 wave) with fork stubs; kept
  ours, refreshed the stale sgl-project#37612-arm comment.
- AITER backend hunk + test_aiter_attention_backend_handler.py SKIPPED
  per instruction (ROCm aiter path irrelevant to this stack).
- test_prefill_memory_budget import hunk conflicted (our tree lacks the
  upstream ChainAllocator test rework): resolved as
  PrefillBudget + SWAPrefillBudget union; new TestContinuingChunkCap
  verbatim.
- Chunk-guard hunk applied verbatim: our _select_prefill_admission
  matched the PR base exactly; no mixed-chunk adaptation fights it
  (mixed-chunk tracks its rows via the scheduler, not new_chunked_req).

CPU: targeted (prefill_adder + memory_budget + 3 latch/retry +
held_row) 83P/67sub; full managers dir 993P/2F/3skip/904sub == the
2F are pre-existing order-dependent test_mm_process_config failures
(verified identical on the stashed baseline, 992P/2F).

(cherry picked from commit 0954308)
(cherry picked from commit d2bf2d29c4b5382291e672a3a1f0ac844cba196b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

batch_is_full latched during final chunked-prefill pass starves waiting queue until a running request finishes (self-healing variant of #28530 / #22518)

2 participants