Enable context parallel in HIP - #5
Open
PiDinosauR2804 wants to merge 5 commits into
Open
PiDinosauR2804 wants to merge 5 commits into
PiDinosauR2804 wants to merge 5 commits into
Conversation
PiDinosauR2804
marked this pull request as ready for review
September 11, 2026 06:39
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.
Purpose
This PR adds an opt-in Indexer M-split for ROCm, behind
SGLANG_DSA_INDEXER_M_SPLIT(default off), that shards the indexer's query rows (theMdimension) across attn-TP ranks:SGLANG_DSA_INDEXER_M_SPLIT_STRIPErows (default 512), and stripeiis owned by ranki % tp_size. Interleaving rather than contiguous blocks matters because the workload is causal: late rows score against far more keys than early rows. With interleaved stripes every rank's total stays at roughlyM^2 / 2 / tp_size.fp8_mqa_logitskernel and the sametopk_transformper-row-range contract the existing chunked path already uses, and writes its indices into the sharedtopk_resultbuffer, which is pre-filled with-1.topk_result[:M]merges the partial results. Rows a rank did not compute are-1, so MAX recovers the owner's indices and every rank ends up with the full top-k, bit-identical to the replicated result.Per rank, the indexer logits GEMM and top-k shrink by
~tp_size; the added cost is oneM x 2048 x int32all-reduce per layer (256 MiB atM = 32768, on the same collective path as the rest of the TP layer). The K-cache store, the K-cache gather, the decode path (_get_topk_paged), and every non-ROCm platform are unchanged.What changed
python/sglang/srt/environ.py:SGLANG_DSA_INDEXER_M_SPLIT(EnvBool, defaultFalse) andSGLANG_DSA_INDEXER_M_SPLIT_STRIPE(EnvInt, default512), grouped under the existing DSA backend section.python/sglang/srt/layers/attention/dsa/dsa_indexer.py:Indexer.__init__reads the two flags (ROCm-only gate) and logs once at layer 0 when active._get_topk_raggedgets a dedicated branch right after the OOM-chunk decision. It calls the new_get_topk_ragged_m_split, which returnsNonewhen there is nothing to split (attn-TP size 1, or fewer rows than ranks); in that case the existing replicated paths run untouched._get_topk_ragged_m_splitimplements the stripe loop. Each stripe reuses the exact per-row-range contract the existing OOM-chunk path already uses (ks[start:end],ke_offset=lengths,topk_indices_offset_override=global_offset[start:end]for the RAGGED top-k method; per-tokencu_seqlens_q+token_to_batch_idxfor the PAGED method), so top-k semantics are identical to the replicated path. When the OOM-chunk check fires, the stripe is additionally capped by the per-row logits budget (aiter's 2 GiBbuffer_storelimit on ROCm)._m_split_all_reduce_maxissues the MAX all-reduce.GroupCoordinator.all_reduceis SUM-only, so this callstorch.distributed.all_reduce(op=MAX)on the attn-TPdevice_group, using PyNCCL when a graph is being captured, mirroring_broadcast_indexer_topk_from_rank0_impl.When it engages
All of the following must hold, otherwise the existing replicated indexer runs:
SGLANG_DSA_INDEXER_M_SPLIT=1is_hip()): the branch only wires the aiter Tritonfp8_mqa_logits; CUDA (DeepGEMM) and XPU keep their paths._get_topk_ragged(decode, target-verify, and draft-extend stay on_get_topk_paged)tp_sizequery rows in the batchTest Plan
lmsysorg/sglang:v0.5.19-rocm720-mi35x(ROCm 7.2.0, torch 2.9.1+rocm7.2.0, triton 3.7.0, aiterc16d44b93), SGLang editable at this branch on top of2f7393f0d.GlmMoeDsaForCausalLM,index_topk=2048,index_n_heads=32,index_head_dim=128, 78 layers).--reasoning-parser glm45so the<think>block lands inreasoning_contentand the graders see only the final answer incontent):Activation check. Each TP rank must log this once at startup; its absence means the flag did not reach the schedulers or the platform gate failed:
Accuracy gates follow the AMD "GLM-5.2 MXFP4 - vLLM status and validation" deck (GSM8K ~92%, GPQA-Diamond ~92%+, RULER/NIAH ~90%+), run against the served endpoint:
lm_eval --model local-completions --tasks gsm8k \ --model_args "model=<model>,base_url=http://127.0.0.1:$PORT/v1/completions,num_concurrent=64,max_retries=3,tokenized_requests=False,timeout=600"Test Result
8x MI355X, TP8, GLM-5.2-MXFP4 throughout.
Accuracy summary (all three deck gates, Before vs After)
niah_single_2@ 64k, 500 samplesniah_single_2@ 128k, 500 samplesE2E serving throughput, ISL 8192 / OSL 1024
num_prompts = 10 x CONC.E2E serving throughput, ISL 50000 / OSL 1024
num_prompts = 10 x CONC.Essential Elements of an Effective PR Description Checklist