[MoE] Route every trtllm-gen MoE call site through one PDL guard - #34789
Merged
Merged
Conversation
PDL on the trtllm-gen MoE can leave its grid-dependency wait unreleased when another stream overlaps the launch; the stalled rank never reaches its next collective and the whole TP group hangs. 6a1d1f4 (landed in sgl-project#31681) capped this by token count, but only at the two fp4 call sites in moe_runner/flashinfer_trtllm.py. The mxfp4 sites never passed enable_pdl at all, so FlashInfer defaulted it to device_support_pdl() -- on for SM90+, with no ceiling. That includes the Kimi-K3 SiTU routed path, which is how a production TP8 engine wedged mid-prefill at a 16384-token chunk, twice the existing threshold. Add trtllm_moe_enable_pdl() next to the threshold it reads and route every call site through it, so a new site cannot silently inherit PDL-on: - mxfp4.py: SiTU routed, SiTU bypassed-topk, and block-scale (GPT-OSS) - mxfp4_flashinfer_trtllm_moe.py: fp4 routed - the deferred-finalize path, which fuses the shared-expert add into sglang's own finalize kernel and gated PDL on the arch check alone - the two already-capped sites, now sharing the one definition trtllm_bf16_moe is left alone: no call site passes enable_pdl today, so its signature is unverified from this tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
kpham-sgl
marked this pull request as ready for review
August 13, 2026 23:49
kpham-sgl
requested review from
Alisehen,
AniZpZ,
BBuf,
Edwardf0t1,
FlamingoPg,
Fridge003,
HaiShaw,
OrangeRedeng,
Ying1123,
b8zhong,
ch-wan,
ispobock,
merrymercy and
mmangkad
as code owners
August 13, 2026 23:49
The four FlashInfer call sites had no arch gate at all -- they passed a bare token comparison, so on an arch without PDL they would have forced enable_pdl=True instead of letting FlashInfer fall back. Folding is_arch_support_pdl() in covers them and drops the duplicated `and` at the deferred-finalize site. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
BBuf
approved these changes
Aug 15, 2026
Collaborator
Author
|
/rerun-test registered/unit/layers/quantization/test_nvfp4_moe_backends.py registered/models_e2e/test_deepseek_v4_flash_fp4_b200.py registered/models_e2e/test_gpt_oss_4gpu_mxfp4.py |
Contributor
|
Results for 🚀 🚀 |
saturn-acc
pushed a commit
to saturn-acc/sglang
that referenced
this pull request
Aug 16, 2026
…-project#34789) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Atituiset
pushed a commit
to Atituiset/sglang
that referenced
this pull request
Sep 10, 2026
…-project#34789) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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
PDL on the trtllm-gen MoE can leave its grid-dependency wait unreleased when another stream overlaps the launch. The stalled rank never reaches its next collective, so the entire TP group hangs.
6a1d1f4422(landed in #31681) identified this and capped PDL by token count viaSGLANG_TRTLLM_MOE_PDL_MAX_TOKENS— but only at the two fp4 call sites inmoe_runner/flashinfer_trtllm.py.The mxfp4 call sites never passed
enable_pdlat all. FlashInfer then defaults it todevice_support_pdl()— on for SM90+, with no ceiling. The env var cannot reach those paths at any setting.That includes the Kimi-K3 SiTU routed path, where a TP8 SM103 engine hangs during long-context prefill at the default
--chunked-prefill-size 16384, twice the existing 8192 threshold.Evidence
From an 8-rank CUDA coredump taken by the watchdog while the ranks were still wedged:
moe::dev::finalize::finalizeKernelVecLoad<KernelParams<bfloat16_t,bfloat16_t,4,true>>— trailingtrueisUsePdl) sit at one PC:+5200, theACQBULKthat implementscudaGridDependencySynchronize(). Zero divergence across the whole grid.c2x1x1); every cluster pair occupies consecutive SM ids, so placement needs a co-schedulable SM pair that never appears.all_reduce_pull_norm_kernelon an unbounded semaphore loop with no timeout, waiting for the eighth participant.numBlocks = data.numTokens(trtllm_fused_moe_dev_kernel.cu:1034), one block per token.Changes
Add
trtllm_moe_enable_pdl(num_tokens)next to the threshold it reads, and route every call site through it so a new one cannot silently inherit PDL-on:mxfp4.py— SiTU routed (the path that hangs), SiTU bypassed-topk, and block-scale (GPT-OSS)mxfp4_flashinfer_trtllm_moe.py— fp4 routedmoe_finalize_fuse_sharedand gated PDL onis_arch_support_pdl()alone. Kimi-K3 takes this branch, and its PDL consumer is a different kernel from FlashInfer's in-op finalize, so threadingenable_pdlinto the trtllm call would not have covered it.trtllm_bf16_moeis deliberately untouched: no call site passesenable_pdltoday, so its signature is unverified from this tree.Threshold value is out of scope
The coredump suggests 8192 may be too high: the finalize kernel's SM footprint is clamped by occupancy at ~740 resident blocks (148 SMs × 5) rather than scaling with token count, so an 8192-token grid floods the machine as thoroughly as the 16384-token one that hangs. That would leave 740–8192 nominally capped but still in the flood regime.
It is not settled enough to move the constant.
tune_max_num_tokens=next_power_of_2(num_tokens)may select a different GEMM tactic at 8192 than at 16384, which would account for the soak result behind the current default without the occupancy model holding.This PR restores the knob's reach. Retuning it belongs in a separate change, after a tactic comparison at both sizes.
Testing
[TODO]
🤖 Generated with Claude Code