Repository navigation
[DSV4] Chunk the indexer MQA logits by query rows under a free-memory budget - #39095
Merged
Merged
Conversation
shikicloud
requested review from
1am9trash,
Fridge003,
HaiShaw,
Qiaolin-Yu,
YAMY1234,
hebiao064,
hubertlu-tw,
ispobock,
kkHuang-amd,
merrymercy and
rainj-me
as code owners
September 11, 2026 13:45
Signed-off-by: Shiki Wu <shikiw@nvidia.com>
shikicloud
force-pushed
the
dsv4-indexer-chunk
branch
from
September 14, 2026 05:54
23774d1 to
97d76ba
Compare
Signed-off-by: Shiki Wu <shikiw@nvidia.com>
Signed-off-by: Shiki Wu <shikiw@nvidia.com>
Fridge003
reviewed
Sep 17, 2026
Signed-off-by: Shiki Wu <shikiw@nvidia.com>
Signed-off-by: Shiki Wu <shikiw@nvidia.com>
Fridge003
approved these changes
Sep 17, 2026
Collaborator
|
Extra tests passed https://github.com/sgl-project/sglang/actions/runs/35192680570 |
# Conflicts: # python/sglang/srt/layers/attention/dsv4/metadata.py # test/registered/unit/layers/test_dsv4_nonpaged_indexer.py
kpham-sgl
approved these changes
Sep 19, 2026
This was referenced Sep 20, 2026
4 of 5 tasks
SouthWest7
added a commit
to SouthWest7/sglang
that referenced
this pull request
Sep 20, 2026
The kpool indexer's ragged extend path builds one dense fp32 logits tensor whose two dimensions are both summed over the whole batch, while each q row may only read its own request's column window. Peak memory is therefore quadratic in the request count and each row's useful area is ~1/B of the allocation, so long-context traffic with prefix-cache hits kills every TP rank inside deep_gemm.fp8_mqa_logits. The kpool path carried a dead, drifted copy of the budget predicate and never called it. Delete it, take the shared policy from attention/mqa_logits_utils.py (sgl-project#39095) instead, and split the kpool computation per request and then per q-row chunk under that budget. The single-call fast path is preserved unchanged when the dense tensor fits. Fixes sgl-project#37712
SouthWest7
added a commit
to SouthWest7/sglang
that referenced
this pull request
Sep 20, 2026
The kpool indexer's ragged extend path builds one dense fp32 logits tensor whose two dimensions are both summed over the whole batch, while each q row may only read its own request's column window. Peak memory is therefore quadratic in the request count and each row's useful area is ~1/B of the allocation, so long-context traffic with prefix-cache hits kills every TP rank inside deep_gemm.fp8_mqa_logits. The kpool path carried a dead, drifted copy of the budget predicate and never called it. Delete it, take the shared policy from attention/mqa_logits_utils.py (sgl-project#39095) instead, and split the kpool computation per request and then per q-row chunk under that budget. The single-call fast path is preserved unchanged when the dense tensor fits. Fixes sgl-project#37712
SouthWest7
added a commit
to SouthWest7/sglang
that referenced
this pull request
Sep 20, 2026
The kpool indexer's ragged extend path builds one dense fp32 logits tensor whose two dimensions are both summed over the whole batch, while each q row may only read its own request's column window. Peak memory is therefore quadratic in the request count and each row's useful area is ~1/B of the allocation, so long-context traffic with prefix-cache hits kills every TP rank inside deep_gemm.fp8_mqa_logits. The kpool path carried a dead, drifted copy of the budget predicate and never called it. Delete it, take the shared policy from attention/mqa_logits_utils.py (sgl-project#39095) instead, and split the kpool computation per request and then per q-row chunk under that budget. The single-call fast path is preserved unchanged when the dense tensor fits. Fixes sgl-project#37712
5 tasks
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
The DeepSeek-V4 C4 indexer scores every query row of a prefill chunk against every compressed (c4) position of the context into one fp32 logits matrix,
[query_rows, align256(max_compressed_seq_len)], allocated inside DeepGEMM (fp8_paged_mqa_logitson the paged path,fp8_mqa_logitson the nonpaged path) once per layer. Nothing sized by--mem-fraction-staticaccounts for it, and it grows linearly with context:So a long prefill deterministically OOMs mid-request on every TP rank once the KV pool has consumed the headroom. The DSA (V3.2) indexer already solves the same problem in
_get_topk_raggedby chunking the query rows under a free-memory budget; the DSV4 indexer had no equivalent on either path, while SM120 already chunked the paged path (fixed 4096 rows, DeepGEMM metadata kernel cap) and ROCm FP4 chunked into a pooled buffer.Modifications
dsa/utils.py: DSA budget logic (_get_mqa_logits_budget_bytes,_should_chunk_mqa_logits) extracted into shared helpers;dsa_indexer.pydelegates, behavior unchanged. Knob staysSGLANG_DSA_MQA_LOGITS_FREE_MEM_FRACTION; no new env var.dsv4/metadata.py:PagedIndexerMetadata.__post_init__decides once per forward: onemem_get_info,rows_per_chunk = min(SM120 cap, rows the budget allows), then a DeepGEMM schedule and a top-k v2 plan per chunk. The SM120 list mechanism becomes the generic one. No chunking under prefill CUDA graph, stream capture, BCG/piecewise, or below 8M elements.dsv4/indexer.py: the SM120 list loop steps byrows_per_chunkand uses per-chunk top-k plans (slices previously reused the full-batch plan on CUDA); the nonpaged path gathers K once and chunksfp8_mqa_logitsby rows.Accuracy Tests
test_dsv4_indexer_chunk.py,test_dsv4_nonpaged_indexer.py, existingtest_dsa_mqa_logits_chunking.py).fp8_paged_mqa_logits/fp8_mqa_logitslogits bit-identical; per-chunk top-k v2 plans select the same pages as the full plan.--mem-fraction-static 0.95(3.7 GB free), prefill completes in 49 s with no OOM (late steps chunk to 411 rows x 173K cols).Speed Tests and Profiling
Checklist
Review and Merge Process
/tag-and-rerun-ci,/tag-run-ci-label,/rerun-failed-ciCI States
Latest PR Test (Base): ✅ Run #35405295077
Latest PR Test (Extra): ✅ Run #35405873102
Latest PR Test (AMD ROCm 10): ❌ Run #35405295029