Skip to content

Fuse Rubin MegaMoE input staging for the MXFP8 family - #7601

Closed
Victor49152 wants to merge 2 commits into
flashinfer-ai:mainfrom
Victor49152:mingyuanm/sm107-mx-fused-staging
Closed

Victor49152 wants to merge 2 commits into
flashinfer-ai:mainfrom
Victor49152:mingyuanm/sm107-mx-fused-staging

Conversation

@Victor49152

@Victor49152 Victor49152 commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

📌 Description

On SM107 (Rubin), the MegaMoE kinds with MXFP8 activations (mxfp8_e4m3, mxfp8_e5m2 and mxfp4_mxfp8) still staged BF16 inputs with Torch ops. The path is an FP32 upcast, then per-block amax, scale and quantize ops, then per-tensor copies into the symmetric workspace. That costs 46–570 µs per forward at 16–8,192 tokens per rank. #6398 fused this preparation for nvfp4 only, which takes 14–39 µs.

This PR routes the MX kinds through the same fused CuTe-DSL stager (fused_quant_stage). That stager already supports mxfp8_e4m3 and mxfp8_e5m2 output. mxfp4_mxfp8 uses E4M3 activations.

mxfp8_mxfp8_bf16_cutedsl/staging.py: calls the fused stager when the layout allows, using the same conditions as the NVFP4 path:

BF16, contiguous, 16-byte-aligned activations and routes;
hidden size a multiple of 128;
an output buffer whose dtype matches the kind, and hidden / 32 scale columns;
FP16, BF16 or FP32 route weights.
It calls note_staged_tokens first, as the NVFP4 path does, so the shared stager's tail memo stays correct. The Torch path stays as the fallback for other layouts. FLASHINFER_MEGA_FUSED_STAGE=0 still forces it; this is the existing switch.

Same staged bytes. Both paths round the E8M0 scale up from amax / fp8_max and round the data to nearest even, so the staged data is identical. Only the scale byte of an all-zero block can differ: Torch clamps its exponent to 2^-126. That scale multiplies zero data, so the result is unchanged.

mxfp4_mxfp8 needs no change of its own. It shares this staging module, so it gets the fused path too.

MegaMoE forward, µs (lower is better)

Kind Staging 16 64 128 256 512 1,024 2,048 4,096 8,192
mxfp4_mxfp8 torch (before) 186.0 228.2 234.2 244.8 261.7 294.8 387.0 654.8 1,195.9
fused (after) 148.4 194.0 196.6 201.0 206.4 218.0 256.7 394.8 692.2
speedup 1.25× 1.18× 1.19× 1.22× 1.27× 1.35× 1.51× 1.66× 1.73×
mxfp8_e4m3 torch (before) 266.4 347.4 354.5 366.9 385.2 418.5 503.7 766.2 1,262.0
fused (after) 229.8 313.7 317.0 323.4 330.5 342.4 372.7 504.7 757.1
speedup 1.16× 1.11× 1.12× 1.13× 1.17× 1.22× 1.35× 1.52× 1.67×
mxfp8_e5m2 torch (before) 271.6 351.1 358.9 370.8 388.6 428.4 515.3 782.7 1,292.0
fused (after) 230.9 313.4 317.6 322.9 328.0 342.9 372.2 503.7 756.7
speedup 1.18× 1.12× 1.13× 1.15× 1.18× 1.25× 1.38× 1.55× 1.71×
nvfp4 (unchanged) fused 152.8 201.5 204.1 208.7 212.8 221.0 250.0 352.4 604.6

🔍 Related Issues

🚀 Pull Request Checklist

Thank you for contributing to FlashInfer! Before we review your pull request, please make sure the following items are complete.

✅ Pre-commit Checks

  • I have installed pre-commit by running pip install pre-commit (or used your preferred method).
  • I have installed the hooks with pre-commit install.
  • I have run the hooks manually with pre-commit run --all-files and fixed any reported issues.

If you are unsure about how to set up pre-commit, see the pre-commit documentation.

🧪 Tests

  • Tests have been added or updated as needed.
  • All tests are passing (unittest, etc.).

🔬 Experimental Track

  • This PR is experimental: it adds or changes code under flashinfer/experimental/ and/or an @flashinfer_experimental_api. Tracking issue: #
    • The tracking issue names an owner, the reason for the experimental path, and a graduation plan with a target release.
    • Core changes are limited to a thin entry point (signature, shared validation, feature-gate check, backend selection, handoff).
    • [] Tests live in tests/experimental/ and were validated on the intended hardware; a runnable example is included.
    • Nothing is registered in flashinfer/aot.py, and no experimental backend is reachable from backend="auto" without FLASHINFER_ALLOW_EXPERIMENTAL_AUTO_BACKENDS=1. (Calling an @flashinfer_experimental_api or naming a backend explicitly is itself the opt-in and needs no environment variable.)
    • Test scope declared below. The experimental CI lane runs exactly these targets, so keep them as narrow as the change allows.
# One target per line: a directory or a file. (A pytest ::selector is not
# supported -- the sharding runner cannot consume one.) Must be under
# tests/experimental/ and must exist. Delete these comment lines and add yours, e.g.
#
#   tests/experimental/test_my_backend.py
#   tests/experimental/my_backend/
#
# Declaring the whole tree (tests/experimental/) is allowed but means every
# experimental PR pays for every other feature's tests, in every matrix cell.

Reviewer Notes

Summary by CodeRabbit

  • New Features
    • Added an optimized staging path for supported mixture-of-experts inputs. Eligible inputs can use fused processing, while inputs that do not meet the requirements continue through the existing staging path.
    • Both paths produce equivalent staged data for normal input blocks. This change preserves existing behavior when fused processing is unavailable or disabled.

Victor49152 and others added 2 commits October 27, 2026 10:34
…on kinds

The SM107 MX kinds (mxfp8_e4m3, mxfp8_e5m2, mxfp4_mxfp8) staged BF16 inputs
with torch ops: an FP32 upcast, a dozen elementwise/reduce launches and
per-tensor copies, 46-570 us per forward for DSv4.1-Flash (hidden 5120) at
16-8192 tokens/rank, against 14-39 us for the NVFP4 kind's fused stager.

Route them through the same fused SM100 CuTe-DSL stager (fused_quant_stage)
the NVFP4 kind uses; it already has mxfp8_e4m3 / mxfp8_e5m2 modes. Both paths
round the E8M0 scale up from amax / fp8_max and the data to nearest even, so
the staged data is identical; only an all-zero block's unused scale byte can
differ. The torch path remains the fallback for unsupported layouts and for
FLASHINFER_MEGA_FUSED_STAGE=0.

AI-assisted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage the same BF16 inputs through the fused stager and the torch path
(FLASHINFER_MEGA_FUSED_STAGE=0) for mxfp8_e4m3, mxfp8_e5m2 and mxfp4_mxfp8
with int32/int64 routes, at live counts 64, 8, 0 and 32 in a 64-row buffer,
including zero, tiny and large blocks. Data, routes, route weights and every
non-zero block's scale must be bitwise equal; an all-zero block's scale byte
is excluded since the two paths encode it differently.

AI-assisted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c20a6315-cfa8-4d4b-8254-cfaa67f77518
Commits

Reviewing files that changed from the base of the PR and between 002529e and 81fe616.

Files selected for processing: 2
  • flashinfer/moe_ep/backends/mega/kernel/sm107/mxfp8_mxfp8_bf16_cutedsl/staging.py
  • tests/moe_ep/test_sm107_preparation.py

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Walkthrough

The SM107 staging function now selects fused quantization staging for eligible inputs when enabled. Other inputs use the existing Torch-composed path. A new test compares fused and Torch staging outputs for MXFP8 and MXFP4 configurations.

Changes: MXFP8 staging

Layer / File(s) Summary
Fused staging selection and parity
flashinfer/moe_ep/backends/mega/kernel/sm107/mxfp8_mxfp8_bf16_cutedsl/staging.py, tests/moe_ep/test_sm107_preparation.py
The staging function selects a quantization type and uses fused_quant_stage when the environment setting and input requirements allow it. Otherwise, it uses the existing Torch path. Tests compare outputs across quantization kinds, routing-ID dtypes, and live-row counts. Scale comparisons exclude all-zero input blocks.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Refactor

Possibly related issues

  • flashinfer-ai/flashinfer#7504 — The issue tracks exact quantization and CuTe DSL MoE testing; this PR adds fused-versus-Torch staging comparisons.

Possibly related PRs

Suggested labels: arch: sm107

Suggested reviewers: akaashrp, jiahanc

Merge Risk: Minimal · up to 81fe6

No actionable merge-blocking issue is established; the change is ready for normal validation.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surv… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly identifies the main change: fusing Rubin MegaMoE input staging for the MXFP8 family.
Description check Passed The description is detailed and covers the implementation, fallback behavior, correctness considerations, performance results, and test updates. The related-issues section is empty, and the checklist …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is detailed and covers the implementation, fallback behavior, correctness considerations, performance results, and test updates. The related-issues section is empty, and the checklist does not confirm that all tests or pre-commit checks passed, but the description is otherwise mostly complete.

Full details: Docstring Coverage

Explanation

Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 4 functions across 2 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
🧪 Generate unit tests (beta)
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Victor49152

Victor49152 commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor Author

Closing as covered in #7062

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant