Skip to content

[HIP] [FlyDSL] [Bugfix] Skip invalid expert IDs in MoE sorting - #5295

Open
tuukkjs wants to merge 2 commits into
ROCm:mainfrom
tuukkjs:fix/moe-sorting-invalid-expert-ids
Open

tuukkjs wants to merge 2 commits into
ROCm:mainfrom
tuukkjs:fix/moe-sorting-invalid-expert-ids

Conversation

@tuukkjs

@tuukkjs tuukkjs commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Summary

topk_ids == -1 is used as a padded/no-route sentinel, but several Opus and FlyDSL MoE sorting paths used the raw value as an expert mesh index. Negative IDs could write before the LDS/HBM mesh, and Opus local expert remapping could also read before local_expert_mask, causing a GPU memory-access fault.

This change consistently requires 0 <= eid < num_experts before the remaining expert-indexed accesses. Valid routes continue through the same sorting logic, while invalid routes are skipped.

This is a follow-up to ROCm/aiter#4839.

AI assistance was used for this PR.

Changes

  • Guard the remaining Opus oneshot and multi-phase mesh writes.
  • Guard Opus local expert-mask reads.
  • Guard FlyDSL oneshot and multi-phase mesh writes.
  • Add deterministic test coverage for all-empty and mixed-invalid routing across Opus and FlyDSL single- and multi-phase paths, including FlyDSL CUDA graph capture/replay.

vLLM workload impact

DeepSeek-V4 DSpark can produce all-padding routing during startup memory profiling. Fixed-K DSpark TP2/TP4 exposed this at M=16384 in Opus P0_v1; that exact site was fixed by ROCm/aiter#4839. Adaptive DSpark verification exposed additional unguarded sorting paths with an all-empty M=2048 fused-MoE input.

Together with ROCm/aiter#4839, this PR makes invalid -1 routing handling consistent across the remaining Opus and FlyDSL sorting paths. The fixed-K TP2/TP4 DSV4 Dspark startup configurations and the adaptive TP8 DSV4 Dspark startup configuration all completed successfully with the combined fixes.

Validation

  • Focused invalid-ID pytest: passed.
  • Full op_tests/test_moe_sorting.py: passed across Opus, CK, and FlyDSL, including CUDA graph capture/replay.
  • Expanded Opus differential matrix: 108/108 comparisons passed.
  • M=2048 all-empty fused-MoE reproducer: 2 warmups and 10/10 iterations passed with zero output.
  • Captured M=16384 all-empty production input: 3/3 exact reference replays passed.
  • DeepSeek-V4 DSpark TP2, TP4, and TP8 adaptive startup/request smokes: passed.
  • Black, Ruff, Python compilation, and whitespace checks: passed.
  • Valid-route microbenchmarks showed no regression for the affected Opus and FlyDSL paths.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

🏷️ CI Guide

Runs automatically on every PR:

  • ✅ Pre-checks (submodule verification, code formatting)
  • ✅ Aiter op tests (gfx942 + gfx950)
  • ✅ Triton tests on MI35X (only when aiter/ops/triton/** or related paths are changed)

Extended tests (opt-in via labels):

Label Tests
ci:gfx1250-ffm-triton Run the five-shard gfx1250 FFM Triton test suite
ci:triton-300x Run an additional Triton test job on MI300X in PRs; main branch always runs both MI35X and MI300X
multigpu Aiter multi-GPU tests on the 8-GPU runner
ci:sglang SGLang integration tests: DeepSeek-R1-MXFP4 accuracy, Qwen 3.5 accuracy
ci:atom ATOM benchmark: DeepSeek-R1-0528, GPT-OSS-120B
ci:atom_full ATOM accuracy suite for PR and main models from ATOM models_accuracy.json
ci:vllm vLLM benchmark: GPT-OSS-120B, DeepSeek-R1-0528, Kimi-K2.5
ci:all All standard extended tests (excludes ci:atom_full)

Only add ci:atom_full for FlyDSL or Triton upgrades.
Add labels via the sidebar or gh pr edit 5295 --add-label <label>

PR title tags & labels:
Component tags ([Triton/Gluon], [HIP], [CK], [ASM], ...) are added to the PR title and as PR labels automatically from the changed files and re-synced on every push — change-type tags like [fix]/[Perf], op tags like [MLA], and human labels (ci:*) are left untouched. Add the no-auto-title label to opt this PR out.

@tuukkjs
tuukkjs marked this pull request as ready for review September 5, 2026 15:53
@tuukkjs
tuukkjs requested a review from a team September 5, 2026 15:53
@github-actions github-actions Bot changed the title [Bugfix] Skip invalid expert IDs in MoE sorting [HIP] [FlyDSL] [Bugfix] Skip invalid expert IDs in MoE sorting Sep 5, 2026
@zufayu
zufayu requested a review from coderfeli September 7, 2026 01:16
Treat padded routing IDs as unrouted before expert-indexed accesses to prevent out-of-bounds writes in Opus and FlyDSL sorting.
@tuukkjs
tuukkjs force-pushed the fix/moe-sorting-invalid-expert-ids branch from 5b61b6d to e9a15cf Compare September 7, 2026 04:27
@coderfeli
coderfeli requested a review from amd-weisun September 8, 2026 12:31

@amd-weisun amd-weisun 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.

LGTM, can you merge 387-388 into single line should_store, same for line 1035(valid_eid) and 1030(valid), and use valid/valid_eid whichever you prefer to replace line 1038 if valid & valid_eid

coderfeli
coderfeli previously approved these changes Sep 8, 2026
@tuukkjs

tuukkjs commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

LGTM, can you merge 387-388 into single line should_store, same for line 1035(valid_eid) and 1030(valid), and use valid/valid_eid whichever you prefer to replace line 1038 if valid & valid_eid

Thanks. Updated the code

@tuukkjs

tuukkjs commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Apparently, the approval was dismissed after new commit was pushed (even if only style was changed). Could you approve again @coderfeli ? Thanks

@tuukkjs

tuukkjs commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Or @amd-weisun could you review/approve? Thanks

@tuukkjs

tuukkjs commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

@coderfeli could you still have a look? Apparently an approval from team_aiter is required. This was approved already by @amd-weisun

heslami pushed a commit to MarloweAI/aiter-upstream that referenced this pull request Sep 14, 2026
…2 histogram

The fused router was pinned to a 4096 model dim by two constexpr in the entry:
BlockSize 256 with TD 16, checked as cols == BlockSize * TD. The kernel body was
never dim-specific -- it carries no static_assert, derives NWAVE from BlockSize
and strides every loop by it -- so the pin was in the entry alone.

TD is the quant's per-thread vector width and stays fixed; the block size now
follows the model dim, so one thread still covers one vector of the row in a
single pass. Instantiated dims are 4096 (256 threads) and 6144 (384, GLM), and
a dim outside that set is refused rather than run on a mismatched block. Both
are whole numbers of waves and satisfy E <= 2*BlockSize. 6144 needs 192 scale
bytes per row against the existing 256-byte allowance, so the caller-owned
workspace is unchanged.

Selection is by shape alone -- no model name, no path registry, no environment
threshold -- so GLM is reached the same way 4096 is.

Phase 2's histogram also takes ROCm#5295's invalid-expert-id guard. Within the
fused launch the ids are the kernel's own, but kPhase23 re-reads topk_ids from
global memory, where a masked -1 would index an LDS counter out of bounds.

GLM's gate needs no new code: at n_group == topk_group == 1 the group mask is
all-ones, so biased grouped top-k is flat biased top-k, which is what phase 1
already computes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants