Repository navigation
[CUDA][MoE] Prioritize ready experts in fused cold-expert dispatch - #33699
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The fused-dispatch tests pass even with identity slot mapping in both FC1 and FC2, leaving the ready-first scheduling optimization unprotected against regressions.
1 open issue
What changed in this PR
This PR builds on #33622’s fused QMoE cold-expert loading and execution by scheduling cached, ready experts before demand-loading experts, while preserving slot bindings and reduction order.
Changes:
- Adds stable ready-first ordering for FC1 and FC2, bypassing reordering for all-cache-hit groups.
- Integrates the shared dispatcher into
QMoEOffload::RunColdExperts. - Adds concurrent tests covering mixed hits/misses, all hits, duplicate experts, and load failures.
| File | Description |
|---|---|
onnxruntime/test/contrib_ops/qmoe_shared_layout_test.cc |
Adds fused-dispatch correctness and failure-handling tests. |
onnxruntime/contrib_ops/cuda/moe/qmoe_offload.cc |
Routes fused cold-expert execution through the ready-first helper. |
onnxruntime/contrib_ops/cpu/moe/qmoe_shared_layout.h |
Adds slot partitioning and shared fused-dispatch helpers. |
Review effort: Balanced
5855bd4 to
1e0a391
Compare
|
Hi BBaditi — we just rebased and updated the base branch
|
c79b457 to
d59d6e0
Compare
0e20eea to
98fe15d
Compare
d59d6e0 to
c4b9b5a
Compare
98fe15d to
cd12cd9
Compare
Rebased onto the updated tlwu/20261026/qmoe-offload-s8-int4-opt branch ( iv.scales_are_block_major = false preserved on Int4ExpertView ) and added deterministic slot-order test coverage for RunReadyFirstFusedColdExpertGroup |
2432436 to
eae41c3
Compare
cd12cd9 to
2c503dd
Compare
eae41c3 to
097a1d0
Compare
2c503dd to
23fc7b2
Compare
Order initially ready cached slots ahead of demand-loading slots in QMoEOffload::RunColdExperts fused parallel dispatch via BuildReadyFirstSlotOrder and RunReadyFirstFusedColdExpertGroup, preserving per-slot buffers, lease ownership, and reduction order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
23fc7b2 to
bafcd64
Compare
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Reviewed the ready-first scheduling map, FC1/FC2 slot identity, readiness publication, duplicate leases, failure cleanup, and caller integration. No actionable findings.
The current deterministic serial traces assert the actual FC1 and FC2 (slot, tile) sequence for mixed/all-hit/all-miss groups, addressing the existing thread about an identity-dispatch mutant passing. Threaded and load-failure coverage is retained. Complete current-head CI is green, so I did not repeat local runtime tests. This looks ready for manual approval; no approval submitted.
|
BBaditi, there is still one feedback from Copilot not resolved. Please take a look whether it need fix. |

Mechanism
In bounded host-cache offload mode (#33622), QMoEOffload::RunColdExperts fuses per-expert chunked demand loads (FileExpertStore::LoadExpertChunk and FinishLoadExpert) with FC1 and FC2 tile execution in a single parallel dispatch. Previously, the FC1 and FC2 stages indexed group slots in raw 0 .. group_size - 1 order, so a demand-missing slot (slot_ready == 0) at a lower slot index caused worker threads to spin on its readiness barrier before reaching already-cached ready slots (slot_ready == kReadyDoneVal).
This change adds BuildReadyFirstSlotOrder and RunReadyFirstFusedColdExpertGroup in qmoe_shared_layout.h to stably partition group slots before parallel dispatch so initially ready cached slots execute before demand-loading slots in FC1 and FC2. Each slot retains its original activation input, lease binding, intermediate buffer, output buffer, and reduction order. When miss_load_count == 0 (all cache hits), reordering is bypassed. Pre-dispatch handling of in-flight prefetches (BeginLoadExpert returning -1) and lease cleanup behavior are unchanged.
Base & Tested Configuration
Scoped Benchmark Summary
Autoregressive greedy single-token decode on Qwen3-30B-A3B INT4 (full_benchmark.onnx, 48 layers, 128 experts/layer, top_k=8, hidden=2048, intermediate=768, block_size=32), 1x NVIDIA A100-SXM4-80GB + AMD EPYC 7V12 (8 SpinPool CPU threads), tail_substitution_threshold=0.0, skip_zero_cold_doorbell=0. Evaluated across N = 8 balanced pairs (2 complete 4x4 cyclic Latin squares across 4 prompts x 32 generated tokens = 124 post-first tokens/run, counterbalanced across AB/BA orders = 32 paired requests/condition):
Output Parity & Validation
Limitations