Converge the two SWA predicates, and stop conditioning the capture sink on the pool - #37550
Merged
Merged
Conversation
ch-wan
requested review from
Fridge003,
HaiShaw,
Qiaolin-Yu,
Ying1123,
alphabetc1,
hanming-lu,
hebiao064,
hnyls2002,
huangtingwei9988,
hzh0425,
ispobock,
merrymercy,
xiezhq-hermann and
yizhang2077
as code owners
September 2, 2026 06:26
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This was referenced Sep 2, 2026
ch-wan
force-pushed
the
cheng/unified-drop-capture-tables
branch
from
September 2, 2026 08:11
9540561 to
d6b0123
Compare
ch-wan
requested review from
BBuf,
DarkSharpness,
HydraQYH,
celve and
yuan-luo
as code owners
September 2, 2026 08:11
ch-wan
force-pushed
the
cheng/unified-read-path-audit-fixes
branch
2 times, most recently
from
September 2, 2026 09:19
e848419 to
214eab1
Compare
ch-wan
force-pushed
the
cheng/unified-read-path-audit-fixes
branch
from
September 2, 2026 09:26
214eab1 to
ee7ae56
Compare
ch-wan
force-pushed
the
cheng/unified-drop-capture-tables
branch
from
September 2, 2026 19:50
d6b0123 to
308631e
Compare
ch-wan
force-pushed
the
cheng/unified-read-path-audit-fixes
branch
from
September 2, 2026 19:50
ee7ae56 to
d25053c
Compare
ch-wan
force-pushed
the
cheng/unified-drop-capture-tables
branch
from
September 2, 2026 20:54
308631e to
f315619
Compare
ch-wan
force-pushed
the
cheng/unified-read-path-audit-fixes
branch
from
September 2, 2026 20:54
d25053c to
b6f551c
Compare
ch-wan
force-pushed
the
cheng/unified-drop-capture-tables
branch
from
September 2, 2026 23:55
f315619 to
4841c24
Compare
Two of the three remaining audit findings on the translator series.
**The same question had two answers.** Backends decide "does this pool have a
full->swa mapping" through `_resolve_swa_kv_pool`, which keys on
`BaseSWAKVPool`; the translator decided it again for the write loc, keying on
`SWAKVPool`. `translate_loc_from_full_to_swa` is an `@abstractmethod` on the
base, so every `BaseSWAKVPool` has it and the narrower spelling was simply
wrong: it drops `DeepSeekV4TokenToKVPool`, which is a `BaseSWAKVPool` and not a
`SWAKVPool`. A backend that resolved such a pool as SWA would pass the outer
guard and then `copy_(None)`. The translator now keys on the class that
declares the capability.
**The capture sink is about the phase, not the pool.** Three sites read
if in_capture and self.kv_index_translator.is_translating:
swa_out_cache_loc[:n].zero_()
else:
swa_out_cache_loc[:n].copy_(sliding_window_write_loc_for(...))
which is four combinations for two wanted behaviours, and only the unified one
got the sink. The capture forward does write KV, so under a static SWA pool the
`else` branch derived a real slot from a dummy `out_cache_loc` and wrote there.
Nothing depends on the value: graph capture bakes pointers, not contents, and
`_apply_cuda_graph_metadata` refills on every replay-prep. So `in_capture`
alone decides, and zeros route the capture write to slot 0, the reserved sink,
for either pool. The comments said "zeros are the page-0 sink" while sitting
above a branch that computes a live one; they now say why the phase is the
whole condition.
Neither fix has an end-to-end run: the pools they change behaviour for are
DSv4 (not runnable with trtllm_mha, which rejects MLA) and hybrid-SWA (the one
such model here, gemma-4-31b-it, dies under unified memory on plain main).
Checked for collateral damage on the two configurations that do run --
Kimi-Linear TP2 + flashinfer_mla 0.9200 and Falcon-H1 + fa3 0.7925, both inside
their bands -- plus 2127 unit tests.
The third finding is NOT fixed. ROCm gfx950 DeepSeek MHA FP8 runs
`filter_dcp_local_kv_indices` + `translate_dcp_read_ids` in
`forward_normal_prepare`, a per-layer method, over `page_table_1_flattened`,
a per-step field -- so it recomputes one tensor once per layer. Every clean
hoist needs either a mutable field on the frozen `DSAMetadata` or module-level
memo state, and the path wants ROCm gfx950 + FP8 KV + unified + DCP + prefill,
none of which is reachable here. Not worth an untested change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ch-wan
force-pushed
the
cheng/unified-read-path-audit-fixes
branch
from
September 2, 2026 23:55
b6f551c to
ceb4aa4
Compare
StevenChenSE
pushed a commit
to StevenChenSE/sglang
that referenced
this pull request
Sep 6, 2026
…nk on the pool (sgl-project#37550) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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
Two findings from auditing the
KVIndexTranslatorseries (#35245 → #34613 → #37307). Both predate that series in effect; both were given their current form by it.The same question had two answers. A backend decides "does this pool have a full→swa index mapping" through
_resolve_swa_kv_pool, which keys onBaseSWAKVPool. The translator decided it again, for the write loc, keying onSWAKVPool:translate_loc_from_full_to_swais an@abstractmethodonBaseSWAKVPool, so everyBaseSWAKVPoolhas it. The narrow spelling dropsDeepSeekV4TokenToKVPool, which is aBaseSWAKVPooland not aSWAKVPool— a backend that resolves such a pool as SWA passes its outer guard and then handsNonetocopy_.The capture sink was conditioned on the pool, and three backends had no sink at all. Three sites (flashinfer, trtllm_mha, flashattention) read:
Four combinations for two wanted behaviours, and only the unified one got the sink. The capture forward does write KV, so under a static SWA pool the
elsebranch derived a real slot from a capture batch's dummyout_cache_locand wrote KV there.Modifications
BaseSWAKVPool— the class that declares the capability, and whatupdate_sliding_window_bufferin the triton backend already used.cuda_graph_swa_out_cache_locnow condition onin_capturealone. Nothing depends on the value either way: graph capture bakes pointers, not buffer contents, and the same code refills on every replay-prep. Zeros route the capture write to slot 0, the reserved sink in every id space, whatever the pool is.triton_backend._fill_cuda_graph_swa_out_cache_loc(called from inside theif in_capture:branch),aiter_backend.init_forward_metadata_out_graph(function-body top level, so both phases) andtrtllm_mha._write_ragged_verify_graph_metadatahad no sink at all -- they derived a live slot from a capture batch's dummyout_cache_locand wrote KV there unconditionally.in_captureis threaded into the first and third; aiter already had it in scope.Accuracy Tests
Neither fix has an end-to-end run, because the pools whose behaviour they change are not reachable here: DSv4 (trtllm_mha rejects MLA models) and hybrid-SWA under the static pool.
What is checkable is collateral damage on the configurations that do run:
The gpt-oss row covers the new triton sink specifically: hybrid-SWA on triton, so
_fill_cuda_graph_swa_out_cache_locruns on both phases. aiter is ROCm and unreachable here.Both one question outside the band's edge, which is inside the ±2 that three runs of one unchanged server reproduce here.
test/registered/unit/mem_cache/: 2127 passed.Speed Tests and Profiling
No performance effect. The sink change removes a per-capture gather on the static-SWA path (once per graph, not per step); the predicate change is an
isinstanceat construction.Checklist
A third finding, deliberately not fixed
ROCm gfx950 DeepSeek MHA FP8 (
forward_mha.py,forward_mha_rocm.py) runsfilter_dcp_local_kv_indices+translate_dcp_read_idsinsideforward_normal_prepare— a per-layer method — overpage_table_1_flattened, which is a per-step field. Both are pure functions of it, so the same tensor is recomputed once per layer.Every clean hoist needs either a mutable field on the frozen
DSAMetadataor module-level memo state, and the path wants ROCm gfx950 + FP8 KV + unified + DCP + prefill, none of which is reachable on this box. I would rather leave it named than ship an untested change to it.CI States
Latest PR Test (Base): 🚫 Run #33697277863
Latest PR Test (Extra): 🚫 Run #33697277668
Latest PR Test (AMD ROCm 7.2): 🚫 Run #33697277873