Skip to content

[Fix] Fix DSA indexer fusion for NeoX RoPE - #30111

Merged
Fridge003 merged 2 commits into
mainfrom
codex/skip-neox-dsa-indexer-fusion
Jul 4, 2026
Merged

Fridge003 merged 2 commits into
mainfrom
codex/skip-neox-dsa-indexer-fusion

Conversation

@Fridge003

@Fridge003 Fridge003 commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Skip DSA indexer fusion for is_neox_style=True indexers while keeping the global fusion env enabled by default.
  • Use self.use_dsa_indexer_fusion as the only fusion branch guard; the module-level _use_dsa_indexer_fusion helper was removed.
  • Restore SGLANG_DISABLE_DSA_INDEXER_FUSION to EnvBool(False) on latest main.
  • Restore both DeepSeek V3.2 index-cache GSM8K thresholds to 0.935.

Root Cause

DSA indexer fusion was controlled only by the global SGLANG_DISABLE_DSA_INDEXER_FUSION env flag. NeoX-style RoPE models could still take the fused indexer path, but that path is not compatible with is_neox_style=True rotation handling, causing the observed accuracy regression.


CI States

Latest PR Test (Base): ❌ Run #28702478657
Latest PR Test (Extra): ❌ Run #28702478568

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the DSA indexer by making the indexer fusion flag instance-specific (self.use_dsa_indexer_fusion) and disabling it when is_neox_style is active. It also increases the accuracy threshold in the DeepSeek-V32 index cache test from 0.93 to 0.935. There are no review comments, and we have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@Fridge003 Fridge003 changed the title [codex] Fix DSA indexer fusion for NeoX RoPE [Fix] Fix DSA indexer fusion for NeoX RoPE Jul 4, 2026
@Fridge003
Fridge003 force-pushed the codex/skip-neox-dsa-indexer-fusion branch from 982bd4a to 2d8cf0a Compare July 4, 2026 09:46
@Fridge003

Copy link
Copy Markdown
Collaborator Author

/rerun-test test/registered/8-gpu-models/test_deepseek_v32_indexcache.py test/registered/models_e2e/test_dsa_glm52_tp_mtp.py test/registered/models_e2e/test_dsa_glm52_dp_mtp.py test/registered/models_e2e/test_dsa_glm52_nvfp4_tp_mtp.py test/registered/models_e2e/test_dsa_glm52_nvfp4_dp_mtp.py

@Fridge003
Fridge003 marked this pull request as ready for review July 4, 2026 09:52
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Results for /rerun-test test/registered/8-gpu-models/test_deepseek_v32_indexcache.py test/registered/models_e2e/test_dsa_glm52_tp_mtp.py test/registered/models_e2e/test_dsa_glm52_dp_mtp.py test/registered/models_e2e/test_dsa_glm52_nvfp4_tp_mtp.py test/registered/models_e2e/test_dsa_glm52_nvfp4_dp_mtp.py:

🚀 8-gpu-h200 (3 tests): ✅ View workflow run

cd test/ && python3 registered/8-gpu-models/test_deepseek_v32_indexcache.py
cd test/ && python3 registered/models_e2e/test_dsa_glm52_tp_mtp.py
cd test/ && python3 registered/models_e2e/test_dsa_glm52_dp_mtp.py

🚀 4-gpu-b200 (2 tests): ✅ View workflow run

cd test/ && python3 registered/models_e2e/test_dsa_glm52_nvfp4_tp_mtp.py
cd test/ && python3 registered/models_e2e/test_dsa_glm52_nvfp4_dp_mtp.py

@Fridge003
Fridge003 merged commit e552f6e into main Jul 4, 2026
101 of 115 checks passed
@Fridge003
Fridge003 deleted the codex/skip-neox-dsa-indexer-fusion branch July 4, 2026 10:20
vincentzed added a commit to vincentzed/sglang that referenced this pull request Jul 8, 2026
… for DeepSeek-V3.2

The DSA lightning-indexer fused Q/K kernels (PR sgl-project#27705) hardcoded the
interleave/GPT-J RoPE pairing (2i, 2i+1), so is_neox_style=True models
(DeepSeek-V3.2) were parked on the slow split path by sgl-project#30111 after the
wrong rotation corrupted indexer top-k selection (~2.4pt GSM8K drop,
0.955 -> 0.931, sgl-project#30088).

Add a compile-time kIsNeox branch to both kernels that pairs dim i with
i + rope_dim/2 via a lane shuffle (partner pack lives at lane ^ 8) and
loads the cos/sin halves layout with per-element frequency indexing;
the cache layout itself is identical between the two conventions. Plumb
is_neox through the JIT wrappers and drop the `and not is_neox_style`
fusion gate clause.

The interleave path is untouched (GLM-5.x byte-identical); Hadamard
behavior (kHadamard) and the DeepSeek-V4 native indexer are unchanged.

Tests: parametrize the fused-kernel unit tests over is_neox and add a
fused-vs-eager NeoX top-k checksum guard (an interleave-only rotation
collapses overlap to ~topk/3).
Chronostasys pushed a commit to MindLab-Research/sglang that referenced this pull request Aug 24, 2026
sumin-hong added a commit to moreh-dev/sglang that referenced this pull request Aug 27, 2026
…to one aiter kernel

The DSA indexer Q/K fusion has been CUDA-only. On ROCm the indexer still runs
the unfused path: rope on q, LayerNorm + rope on k, an fp8 quant of each, the
head-gate scale, and the index-K cache write, as separate launches per layer per
step. All of it is launch-bound.

aiter's indexer_qk_rope_quant_and_cache does the whole thing in one launch, so
extend the existing fusion switch to ROCm rather than build a second one: the
fused wk_weights_proj GEMM, the no-Hadamard invariant, the weight loader and the
graph split-op plumbing are all platform-agnostic already.

- Probe aiter for the kernel at import and fall back with a warning; aiter is
  pinned per image and an older one would only fail at the first forward.
- Build k_norm in fp32 whenever fusion is on. The kernel requires fp32 norm
  params, as the CUDA kernels already do; bf16 stays for the unfused ROCm path,
  where matching x.dtype is what selects aiter's CK layernorm.
- Read cos/sin off aiter's rope module, which keeps them apart as
  [max_position, 1, 1, rope_dim/2] instead of one cos_sin_cache.
- Give _fused_k_prepare_and_store a ROCm branch. Its CUDA fallback is a JIT
  kernel, and the k-only decode fast path reaches it whenever fusion is on.
- Gate the fused-store branch on _is_cuda so non-CUDA stops paying for a JIT
  compile attempt that can only fail.

Two adjacent fixes:
- lora_manager imported _use_dsa_indexer_fusion, which sgl-project#30111 deleted, so the
  indexer-LoRA guard raised ImportError instead of its intended error. Restored
  as dsa_indexer_fusion_supported().
- The ROCm branch of _store_index_k_cache read forward_batch.out_cache_loc,
  ignoring the sliced out_cache_loc its caller passes under the graph split-op
  contract.

The two K-cache writers stay live at once -- the k-only decode path writes
unfused -- and they are not byte-identical: the unfused path rounds to bf16
before quantizing while the fused kernel goes fp32 -> fp8 directly, so a value
near an fp8 midpoint can land on either neighbour. Measured on 41x128: scales
identical, 15/5248 elements differ, each by one fp8 code.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Sumin Hong <sumin.hong@moreh.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant