[AMD][DSV4] perf: MXFP8 MoRI dispatch to match the w4a8 MoE input format - #36119
Open
karverma-amd wants to merge 2 commits into
Open
[AMD][DSV4] perf: MXFP8 MoRI dispatch to match the w4a8 MoE input format#36119karverma-amd wants to merge 2 commits into
karverma-amd wants to merge 2 commits into
Conversation
DSv4's MoE runs per_1x32 (MXFP4 weights), so AITER wants fp8 activations carrying group-32 e8m0 microscales. None of MoRI's three shipped dispatch dtypes produce that: bf16 -> no scales -> receiver must quantize fp8 -> group-128 fp32 -> fp8->bf16 upscale round trip fp4 -> group-32 e8m0, but an fp4 payload -> upscale_mxfp4 bf16 therefore wins by default only because it is the one with no upscale kernel. But it pushes the bf16->fp8 conversion to the receive side, and that is where it hurts: AITER sizes its quant grid from the input row count, and the input is MoRI's padded receive buffer (num_max_dispatch_tokens_per_rank * world_size = 24576 rows) rather than the ~112 live tokens decode actually carries. This adds an mxfp8 dispatch mode that quantizes on the send side over live tokens, which is effectively what DSR-1 gets for free with its w8a8 per-128 fp8 dispatch: activations arrive already in the MoE's dtype, so AITER takes the `hidden_states.dtype == q_dtype_a` branch and runs no quant kernel at all. Opt-in via SGLANG_MORI_DISPATCH_DTYPE=mxfp8; the default stays bf16. Requires the matching aiter change (a8w4 mxfp8 passthrough in fused_moe.py), which must land first. Adds a unit test for the layout arithmetic and env wiring: group size 32, one scale per 32 channels, 1-byte e8m0 scales, and the empty-token-batch scale shape. These are the parts that regress silently -- a wrong scale group or dtype still runs, but reintroduces the upscale round trip the mode exists to remove. Co-authored-by: Cursor <cursoragent@cursor.com>
…pport SGLANG_MORI_DISPATCH_DTYPE=mxfp8 needs an aiter whose per_1x32 quant accepts scale_type, so it can emit the group-32 e8m0 byte layout the MoE kernels consume. Against an older aiter the quant still returns fp8, but with continuous fp32 scales, which the MoE then reads as e8m0 bytes -- wrong numbers rather than an exception. Probe the signature once at startup and fall back to bf16 with a warning if the support is missing, so an sglang updated ahead of its aiter degrades instead of silently corrupting. Co-authored-by: Cursor <cursoragent@cursor.com>
karverma-amd
marked this pull request as ready for review
August 24, 2026 03:47
karverma-amd
requested review from
BBuf,
Edwardf0t1,
Fridge003,
HaiShaw,
Ying1123,
ch-wan,
ispobock and
merrymercy
as code owners
August 24, 2026 03:47
Contributor
Author
|
Companion aiter PR: ROCm/aiter#4954 ([AMD][DSV4] feat: MXFP8 activation passthrough in fused_moe). That side adds the 12-line branch letting The two are safe to merge in either order. With |
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
DSv4's MoE runs
per_1x32(MXFP4 weights), so AITER wants fp8 activationscarrying group-32 e8m0 microscales. None of MoRI's three shipped dispatch dtypes
produce that:
upscale_mxfp4bf16 wins by default only because it is the one with no upscale kernel. But it
pushes the bf16->fp8 conversion to the receive side, and that is where the
cost is: AITER sizes its quant grid from the input row count
(
aiter/csrc/kernels/quant_kernels.cu,rows = input.numel() / cols), and theinput is MoRI's padded receive buffer
(
num_max_dispatch_tokens_per_rank * world_size= 3072 * 8 = 24576 rows) ratherthan the ~112 live tokens decode actually carries.
num_rowsis a devicepointer used only for a per-block early exit, so it cannot shrink the grid.
DSR-1 never hits this: it is w8a8, its dispatch delivers fp8 with per-128 fp32
scales which is already the MoE's input format, so AITER takes the
hidden_states.dtype == q_dtype_abranch and runs no quant kernel at all.Modification
Adds an
mxfp8dispatch mode that quantizes on the send side, over livetokens, emitting the fp8 + group-32 e8m0 layout the MoE kernels consume
directly. Opt-in via
SGLANG_MORI_DISPATCH_DTYPE=mxfp8; the default staysbf16, so existing deployments are untouched.Depends on the matching aiter change (a8w4 mxfp8 passthrough in
fused_moe.py), which must land first.Performance
DeepSeek-V4-Pro, MI355X (gfx950),
rocm/sgl-dev:v0.5.18-rocm720-mi35x-20260822,8192 in / 1024 out, TP8 + DP8 attention + EP8/MoRI + EAGLE MTP. Both arms are the
same build; the only difference is
SGLANG_MORI_DISPATCH_DTYPE.TPOT mirrors throughput at every point, which is harder to attribute to drift
than either metric alone. For scale: repeat runs of an identical build on this
setup span 0.5-2.7%, so every cell here is well outside run-to-run noise.
One run per cell.
Commands
Note: under DP attention
--max-running-requestsis divided bydp_size, so avalue below the DP degree floors to 0 per rank and trips
assert max_running_request > 0. At$CONC4 it was raised to 8.Accuracy
GSM8K, 1319 questions, parallel 1319: 0.945, invalid 0.000.
Unit test
test/registered/unit/layers/test_moriep_mxfp8_dispatch.py(9 cases) pins thebyte layout and env wiring, which are the parts that regress silently -- an fp8
payload with the wrong scale group or dtype still runs, but reintroduces the
upscale round trip this mode exists to remove, and the only symptom is lost
throughput:
DispatchDtypevalue is distinct, andmxfp8is reachable from the envChecklist
CI States
Latest PR Test (Base): ❌ Run #32679407041
Latest PR Test (Extra): ❌ Run #32679406901
Latest PR Test (AMD ROCm 7.2): ❌ Run #32679406994