Repository navigation
fix(scheduler): advance the input-logprob offset for skipped prefill requests - #36939
Open
EnesYilmazcode wants to merge 2 commits into
Open
EnesYilmazcode wants to merge 2 commits into
EnesYilmazcode wants to merge 2 commits into
Conversation
EnesYilmazcode
requested review from
Ying1123,
hnyls2002,
merrymercy and
xiezhq-hermann
as code owners
August 29, 2026 01:34
rwang5203
reviewed
Sep 15, 2026
Comment on lines
+114
to
+118
| result = SimpleNamespace( | ||
| copy_done=None, | ||
| auxiliary_host_output=None, | ||
| routed_experts_output=None, | ||
| indexer_topk_output=None, |
Collaborator
There was a problem hiding this comment.
On current main, this fixture lacks sampling_mask_output, so the regression test fails before checking logprob offsets. Consider adding the current optional output fields to the fixture.
Author
There was a problem hiding this comment.
Thanks, fixed in 488b56a. Rebased on main and switched the fixture to the real GenerationBatchResult and LogitsProcessorOutput dataclasses, so new optional fields pick up their defaults instead of breaking the test. It passes on current main and still fails with the scheduler fix reverted.
…reqs The flat input-logprob array holds one block per request in the batch, whether or not that request asked for logprobs, which is why _apply_prefill_logprobs advances logprob_pt outside its return_logprob guard. The finished/retracted branch skips a request without advancing that cursor, so every later request in the same batch reads a shifted slice and is served another request's prompt logprobs. The length assertion downstream only checks the block size, not its offset, so nothing raises. The disaggregated prefill loop already handles this with advance_logprob_pt on each of its skip paths.
The SimpleNamespace fixture broke whenever main added an optional output field (sampling_mask_output, finalize_input_logprobs). Using GenerationBatchResult and LogitsProcessorOutput picks up their defaults.
EnesYilmazcode
force-pushed
the
fix/prefill-logprob-offset-skipped-reqs
branch
from
September 25, 2026 23:30
0f362a9 to
488b56a
Compare
Author
|
@rwang5203 could you add the |
This branch has not been deployed
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
I was reading the two prefill result loops side by side, because
disaggregation/prefill.py:703definesadvance_logprob_pt()and calls it on all three of its skip paths, and the loop inbatch_result_processor.pyhas no equivalent. It needs one.The flat input-logprob array holds one block per request in the batch, whether or not that request asked for logprobs.
_apply_prefill_logprobsis written that way on purpose: it advanceslogprob_ptoutside itsreturn_logprobguard, so the cursor tracks positions rather than interest. The producer agrees, buildingextend_logprob_pruned_lens_cpufrom every sequence in the batch with the sameextend_len - start_lenformula the consumer uses.The finished-in-a-mixed-batch and retracted branch at line 307 skips a request without advancing that cursor. Every later request in the batch then reads a shifted slice and is served another request's prompt logprobs.
Nothing raises. The check in
logprob_result_processor.pyvalidates the slice length, not its offset, and the shift is always backwards so it never runs off the end.input_top_logprobs_val[i]is indexed per request and stays correct whileinput_token_logprobsis sliced by the cursor and goes wrong, which is the diagnostic signature and probably why this has been quiet.It bites when the skipped request itself asked for input logprobs. At the default
logprob_start_lenof-1its block is zero rows and the skip is harmless. Overlap scheduling is on by default and retraction is ordinary under KV pressure, so no unusual flag is involved.Reported in #36938.
Two open PRs touch this block without covering this path:
req.to_finishpath. That is a pending finish, soreq.finished()is false and it routes through the normal branch, not this skip.deferred_mm_abortbranch immediately above thiscontinueand advances the cursor there, leaving this branch alone.Modifications
Advance
logprob_ptby the skipped request's block before thecontinue.I used
calculate_num_input_logprobsrather than subtracting the lengths directly because it keeps multi-item scoring batches correct, where only delimiter positions have logprobs. If you would rather keep the skip path cheap and do the plain subtraction, that is a one-line change and I am happy either way.Added
test/registered/unit/managers/test_batch_result_processor_logprobs.py, built on the harness in the existingtest_batch_result_processor_hidden_states.pyand registered asregister_cpu_ci(est_time=2, suite="base-a-test-cpu"). It drives the realprocess_batch_result_prefillwith a retracted request in position 0 and asserts the following request gets its own block.Accuracy Tests
Two prefill requests, the first retracted,
extend_input_len_per_req=[2, 3],extend_logprob_start_len_per_req=[0, 0], over a flat array of[-1.0, -2.0, -30.0, -31.0, -32.0]:Checking out the previous revision of the source file while keeping the new test reproduces the first row.
test/registered/unit/managers/on CPU: 572 passed before, 573 after, the extra one being this test. The 2 failures and 3 errors in that directory (test_mm_process_config.py,test_customized_info_streaming.py) are present either way.Speed Tests and Profiling
N/A. One integer add per skipped request, and only when
batch.return_logprobis set.Checklist
pre-commit. isort 7.0.0, black 26.1.0 and ruff 0.15.1 are clean on both files.The new test runs on CPU in about 8 seconds and needs no GPU.
CI States
Latest PR Test (Base): ❌ Run #36201305886
Latest PR Test (Extra): ❌ Run #36201305577
Latest PR Test (AMD ROCm 10): ❌ Run #36201305890