Repository navigation
[CUDA] Add fused decode routing, single-pass finalize, and PDL overlap for NVFP4 QMoE - #33366
Draft
Tianlei Wu (tianleiwu) wants to merge 2 commits into
Draft
Tianlei Wu (tianleiwu) wants to merge 2 commits into
Tianlei Wu (tianleiwu) wants to merge 2 commits into
Conversation
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261013/nvfp4-qmoe-decode-gemv
branch
from
October 16, 2026 05:32
4b4e16e to
60cd1fb
Compare
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261014/nvfp4-qmoe-decode-route-pdl
branch
from
October 16, 2026 21:51
3aa261a to
a35a504
Compare
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261013/nvfp4-qmoe-decode-gemv
branch
from
October 19, 2026 06:07
99626e6 to
a20b5c5
Compare
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261014/nvfp4-qmoe-decode-route-pdl
branch
from
October 19, 2026 08:17
5e08544 to
26ab25a
Compare
…p for NVFP4 QMoE
For the offline K-packed (weights_prepacked=1) NVFP4 QMoE decode path on SM90+:
- Fused softmax + top-k + expert-map kernel (FusedSoftmaxTopKMapsKernel) for E=512, num_rows <= 4, k in {1, 2, 4, 6, 8, 10}, reproducing LaunchSoftmaxTopK + fusedBuildExpertMapsSortFirstToken bit-exactly in a single CTA launch (ORT_FP4_GEMV_FUSED_ROUTE=0 disables).
- Single-pass finalizeMoeRoutingKernel with one thread per 128-bit column vector (up to 1024 threads) and batched loads of up to 16 expert rows while preserving top-k accumulation order.
- Programmatic dependent launch (PDL) overlap of FC1 -> FC2 -> finalize so FC2 prefetches weights/scales and finalize loads routing metadata before waiting on the producer grid (ORT_FP4_GEMV_PDL=0 disables; ORT_FP4_GEMV_FC1_PDL=1 optionally enables PDL for FC1 behind fused routing).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Guard FusedSoftmaxTopKMapsKernel inline PTX instructions only for __CUDA_ARCH__ >= 900 (with a warp-shuffle fallback for __reduce_max_sync below SM80) and verify compiled SM90 PTX/SASS via cudaFuncGetAttributes in LaunchFusedRouteMapsT. - Gate fc2_finalize_pdl on sm_ >= 90 (and disable PDL inside the autotune timing loop), and verify SM90 PTX/SASS in finalizeMoeRoutingKernelLauncher before enabling programmaticStreamSerializationAllowed. - Clamp finalizeMoeRoutingKernel blockDim to the compiled specialization's register-limited maxThreadsPerBlock and check cudaLaunchKernelEx return status. - Extend test_nvfp4_offline_row_major_decode_gemv_bit_exact to cover 512-expert fused routing, PDL opt-out, and wide hidden_size=5120 finalize. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261014/nvfp4-qmoe-decode-route-pdl
branch
from
October 19, 2026 08:58
26ab25a to
c9e3dcc
Compare
This branch has not been deployed
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.
Description
Optimizes the non-GEMV kernels and inter-kernel launch serialization along the offline K-packed (
weights_prepacked=1) NVFP4QMoEdecode path on SM90+:FusedSoftmaxTopKMapsKernel): ReplacesLaunchSoftmaxTopK+fusedBuildExpertMapsSortFirstTokenin a single CTA launch fornum_rows <= 4,num_experts == 512, andk in {1, 2, 4, 6, 8, 10}. One warp per row reproduces theSoftmaxTopKMergeKernel<T, 128, 4>reduction trees operation for operation and emits the(expert, token)-sorted expert maps bit-identically (ORT_FP4_GEMV_FUSED_ROUTE=0disables).finalizeMoeRoutingKernel: Sizes the block to one thread per 128-bit column vector (up to 1024 threads instead of a fixed 256) so hidden dimensions up to 4096 (such as Qwen3.8'shidden=2560) reduce in a single pass, and issues batched loads of up to 16 expert rows together while preserving top-k accumulation order (7.7 us -> 4.0 usper layer on H200).PDL) overlap ofFC1 -> FC2 -> finalize: Launches FC2 andfinalizeMoeRoutingKernelwithcudaLaunchAttributeProgrammaticStreamSerialization(ORT_FP4_GEMV_PDL=0disables;ORT_FP4_GEMV_FC1_PDL=1optionally enables PDL for FC1 behind fused routing). FC1 triggers dependents at start, FC2 prefetches its first batch of weights/scales before waiting on FC1's output, andfinalizeMoeRoutingKernelstages routing metadata into shared memory before waiting on FC2's output (~2.2 ussaved per layer on H200, preserved under CUDA Graph capture).All three optimizations preserve exact floating-point evaluation order and produce bit-identical outputs.
Summary of Changes
onnxruntime/contrib_ops/cuda/moe/qmoe_fused_route.cuhFusedSoftmaxTopKMapsKernelsingle-CTA fused softmax + top-k + expert-map kernel (E=512,rows <= 4,k in {1,2,4,6,8,10})onnxruntime/contrib_ops/cuda/moe/qmoe_kernels.h/.cuLaunchFusedRouteMapsdeclarations and launcheronnxruntime/contrib_ops/cuda/llm/moe_gemm/moe_kernels.cu/moe_util_kernels.hfinalizeMoeRoutingKernel(blockDim.xup to 1024,FINALIZE_LOAD_BATCH=16) andearly_routing_loadsPDL supportonnxruntime/contrib_ops/cuda/llm/moe_gemm/moe_gemv_fp4.h/.cugriddepcontrol.wait/griddepcontrol.launch_dependentsinMoeGemvFp4DecodeKernelandprogrammatic_dependent_launchattribute inLaunchMoeGemvFp4RawNPacked(ORT_FP4_GEMV_PDL)onnxruntime/contrib_ops/cuda/moe/moe_quantization.ccLaunchFusedRouteMapsandfc2_finalize_pdlintoQMoE::ComputeInternaldocs/contrib_ops/cuda/moe_qmoe.mdORT_FP4_GEMV_FUSED_ROUTE,ORT_FP4_GEMV_PDL, andORT_FP4_GEMV_FC1_PDLTesting
Validated on NVIDIA H200 (
sm_90a, CUDA 13.0):python -m pytest onnxruntime/test/python/transformers/test_qmoe_nvfp4_cuda.py: 178 passed, 8 skipped, 0 failed (includingtest_nvfp4_offline_row_major_decode_gemv_bit_exactfor FP16 and BF16).v12b3-session CUDA-graph + MTP engine, 48 MoE layers + 1 MTP layer):engine_gate.py --prefill stepspasses 6/6 with 100% identical token sequences (256/256tokens ontext2048andprose2048) compared against the baseline without fused routing / PDL.bench_engine_mtp.py, 256 generated tokens, median of 3 runs):#33354only)ms/cyclems/cycletok/s)lintrunneron all touched files: no issues.