Repository navigation
[MoE] Optimize multi-token (M=4, 8) MoEPacked CPU hybrid cold routes and GPU FC2 decode - #34067
Merged
Merged
Conversation
BBaditi
force-pushed
the
qmoe-packed-gguf-moe-m8-verify-opt
branch
2 times, most recently
from
November 10, 2026 18:26
0612610 to
feb3aac
Compare
3 tasks done
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical defects can cause out-of-bounds bias reads, incorrect CUDA results, execution hangs, and violations of configured offload memory limits.
20 open issues
The optional biases are passed to a helper that indexes them by expert and channel without… · New The task count is packed into 20 bits without checking that it fits. A supported batch covering 512… · New This function-local static joins its worker threads from its destructor, so unloading the CUDA… · New The pinned slabs and retained scratch bypasspinned_bytesandhost_working_bytes, so admission… · New The hybrid path caches these bias pointers without validating their dimensions; the offload… · New This flag lets admission accept a host-expert budget smaller than the cold-expert complement, but… · New Partial-residency plans execute every cold expert on CPU even when… · New Withenable_cuda_graph=1, partially resident execution synchronizes an event recorded on the… · New The full-size cold-output buffer is allocated even for ordinary GPU-only execution, where it is… · New This changes an explicitly configuredsession.moe.offload.mode=disabledback toautowhenever… · New The MoEPacked-specific expert-count setting becomes an unrestricted wildcard, so it also changes… · New Malformed values such asabcor-1are silently ignored for this expert-count option, unlike… · New The new biases are silently ignored by GPU-resident experts, so a biased model produces different… · New USE_CUDA only establishes that CUDA was built, not that the current GPU supports this test. All… · New The pool ignoressession.moe.offload.cpu_threads: even an explicit value of 1 starts at least 15… · New Adaptive admission reserves spare slots and requests background promotion, but this backend… · New The new shared-LUT FC2 decode branches for IQ2_XS, IQ2_S and IQ3_XXS are not exercised by the C++… · New The new alias and the canonical device-expert-budget key can both be supplied with different… · New An explicitsession.moe.offload.reserve_device_bytes=0is treated as an automatic reserve, so… · New The per-format test checks only single-route helpers; batch-2 is covered indirectly at K=256/64… · New
What changed in this PR
This PR extends com.microsoft::MoEPacked CPU and hybrid GPU/CPU execution while optimizing CUDA multi-token decode. It builds on the stacked CPU-kernel and expert-offload work.
Changes:
- Adds CPU kernels and GGUF numerical/parity tests.
- Connects packed experts to offload admission, staging, and hot/cold routing.
- Reduces BF16 FC2 decode overhead and updates the schema and operator documentation.
| File | Description |
|---|---|
onnxruntime/test/contrib_ops/gguf_quant_packed_test.cc |
Adds GGUF dot-product and CPU/CUDA/hybrid parity tests. |
onnxruntime/core/providers/cuda/qmoe_session_controller.h |
Updates override matching and device-budget reserves. |
onnxruntime/core/graph/contrib_ops/contrib_defs.cc |
Adds optional biases and float activation support. |
onnxruntime/core/framework/session_state.cc |
Adds MoEPacked eligibility and initializer placement for offload. |
onnxruntime/core/framework/moe_offload_plan.h |
Adds budget alias and GPU-expert-count configuration handling. |
onnxruntime/contrib_ops/cuda/moe/moe_packed.h |
Declares hybrid dispatch interfaces and persistent offload state. |
onnxruntime/contrib_ops/cuda/moe/moe_packed.cu |
Optimizes FC2 decode and separates routing, hot execution, and finalization. |
onnxruntime/contrib_ops/cuda/moe/moe_packed.cc |
Implements resident expert uploads, staging, and CPU-cold execution. |
onnxruntime/contrib_ops/cpu/moe/moe_packed_cpu.h |
Declares the CPU kernel. |
onnxruntime/contrib_ops/cpu/moe/moe_packed_cpu.cc |
Implements CPU routing, expert projections, and output accumulation. |
onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc |
Registers float, FP16, and BF16 CPU kernels. |
docs/OperatorKernels.md |
Updates CPU availability and bias-input listings. |
docs/ContribOperators.md |
Documents optional biases and expanded activation types. |
Review effort: Max
BBaditi
force-pushed
the
qmoe-packed-gguf-moe-m8-verify-opt
branch
from
November 12, 2026 01:07
feb3aac to
cee418b
Compare
Tianlei Wu (tianleiwu)
marked this pull request as ready for review
November 12, 2026 02:28
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
AVX2-enabled test builds fail because a void-returning helper is used as a condition and another helper is called despite being unavailable on native MSVC.
4 open issues
20 resolved since last review
USE_CUDA only establishes that CUDA was built, not that the current GPU supports this test. All… The new biases are silently ignored by GPU-resident experts, so a biased model produces different… Malformed values such asabcor-1are silently ignored for this expert-count option, unlike… The MoEPacked-specific expert-count setting becomes an unrestricted wildcard, so it also changes… This changes an explicitly configuredsession.moe.offload.mode=disabledback toautowhenever… The full-size cold-output buffer is allocated even for ordinary GPU-only execution, where it is… Withenable_cuda_graph=1, partially resident execution synchronizes an event recorded on the… Partial-residency plans execute every cold expert on CPU even when… This flag lets admission accept a host-expert budget smaller than the cold-expert complement, but… The hybrid path caches these bias pointers without validating their dimensions; the offload… The pinned slabs and retained scratch bypasspinned_bytesandhost_working_bytes, so admission… This function-local static joins its worker threads from its destructor, so unloading the CUDA… The task count is packed into 20 bits without checking that it fits. A supported batch covering 512… The optional biases are passed to a helper that indexes them by expert and channel without… The per-format test checks only single-route helpers; batch-2 is covered indirectly at K=256/64… An explicitsession.moe.offload.reserve_device_bytes=0is treated as an automatic reserve, so… The new alias and the canonical device-expert-budget key can both be supplied with different… The new shared-LUT FC2 decode branches for IQ2_XS, IQ2_S and IQ3_XXS are not exercised by the C++… Adaptive admission reserves spare slots and requests background promotion, but this backend… The pool ignoressession.moe.offload.cpu_threads: even an explicit value of 1 starts at least 15…
Review effort: Max
Tianlei Wu (tianleiwu)
force-pushed
the
qmoe-packed-gguf-moe-m8-verify-opt
branch
from
November 12, 2026 03:31
cee418b to
b5c7fb9
Compare
BBaditi
force-pushed
the
qmoe-packed-gguf-moe-m8-verify-opt
branch
from
November 12, 2026 04:19
b5c7fb9 to
14b0c81
Compare
Tianlei Wu (tianleiwu)
previously approved these changes
Nov 12, 2026
Tianlei Wu (tianleiwu)
enabled stacked auto-merge (squash)
November 12, 2026 05:30
…U FC2 decode - Add AVX2 INT8 GGUF dot-product kernels and 2-route fused grouped dot products (VecDotGgufRow4xQ8Batch2Avx2) in gguf_vec_dot_cpu.h - Optimize GPU MoEPackedFc2Bf16TcKernel<1> (moe_packed.cu) with 4 warps (64 output channels/CTA), shared-memory GGUF lookup tables (s_lut), and direct __ldg(fc1_row) activation reads Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
BBaditi
force-pushed
the
qmoe-packed-gguf-moe-m8-verify-opt
branch
from
November 12, 2026 07:13
14b0c81 to
214a4d7
Compare
Tianlei Wu (tianleiwu)
approved these changes
Nov 12, 2026
Tianlei Wu (tianleiwu)
deleted the
qmoe-packed-gguf-moe-m8-verify-opt
branch
November 12, 2026 09:16
Tianlei Wu (tianleiwu)
added a commit
that referenced
this pull request
Nov 13, 2026
This cherry-picks the following commits for the release: | Commit ID | PR Number | Commit Title | |-----------|-----------|-------------| | 85dcb54 | #32475 | Update Eigen to 5.0.1 + SSE2 fix (broken Clip & Sign) | | 1ea552d | #33976 | [CUDA/CPU] Add hybrid GPU/CPU expert offload for MoEPacked block-packed weights | | 3a8b8f2 | #34066 | [CUDA] Optimize multi-token MatMulPacked GGUF GEMV (M=2..8) and eliminate ReadU32Dev warp divergence | | 64506ea | #34098 | [CUDA] Guard tests requiring SM80 on older GPUs | | 74f861c | #34067 | [MoE] Optimize multi-token (M=4, 8) MoEPacked CPU hybrid cold routes and GPU FC2 decode | | 6aa9b27 | #33963 | [CUDA] Extend MoEPacked for top-k, dispatch and fused MoE calculation | | 8fb1b27 | #33969 | [CUDA] Add Mamba2Verify CUDA Kernel | | cedae42 | #33994 | [CUDA] Update `MoEGroupRouter` for routing to `MoEPacked` | | 158d0c0 | #34002 | [CUDA] Speed up native Bolt packed projections and IQ2 experts | | 38c6dce | #34003 | [CUDA] Reduce native packed decode tile and FC2 loader overhead | | d5704db | #34147 | [CUDA] Optimize MoEPacked, MoEGroupRouter, and MatMulPacked for Nemotron Bolt | | 7cca0e5 | #34126 | Fix Windows junction detection in model_package for non-MSVC standard libraries | | 2bf400a | #34099 | Fix external data validation for Hugging Face Hub shared blob store | | d2f77cd | #34164 | [CUDA] Accelerate Nemotron Bolt large-chunk prefill across contrib ops | | ca7ea48 | #28457 | Add set_default_logger_callback Python API for custom ORT logging | | fca9447 | #34117 | [CUDA] Optimize CUDA prefill and quantized paged attention | | 1804c6f | #34114| [CUDA] Optimize MoEPacked GGUF offload 3-stage prefill pipeline and F16C/Batch4/40-core cold decode | --------- Signed-off-by: Christian Bourjau <christian.bourjau@quantco.com> Signed-off-by: rui-ren <ruiren1225@gmail.com> Co-authored-by: Christian Bourjau <cbourjau@users.noreply.github.com> Co-authored-by: BBaditi <bbaditi@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Rui Ren <ruiren1225@gmail.com> Co-authored-by: Mustapha Jaber <mustjab@users.noreply.github.com> Co-authored-by: Mustapha Jaber <mustjab+microsoft@microsoft.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com> Copilot-Session: f4d0e1a3-a389-4cc8-9c85-0fd0e3ffce5b Copilot-Session: c8741c5a-3e9e-4860-b846-7d6fb0025040
Baiju Meswani (baijumeswani)
pushed a commit
that referenced
this pull request
Nov 13, 2026
…16C/Batch4/40-core cold decode (#34114) ## Description Stacks on #33976 (and integrates #34066 and #34067). Optimizes `com.microsoft::MoEPacked` CPU/GPU hybrid expert offload and `com.microsoft::MatMulPacked` multi-token (`M=2..8`) MTP verification for block-packed GGUF MoE models (`Qwen3.8-Flash-Next` `UD-IQ3_XXS`) based on Nsight Systems (`nsys --cuda-graph-trace=node`) timeline profiling on NVIDIA H200: 1. **Prefill**: Eliminates cross-stream H2D Copy-Engine head-of-line blocking by double-buffering per-wave route/tile metadata (`d_wave_sorted_routes[2]`, `d_wave_tiles[2]`, `d_wave_num_tiles[2]`) on `wave_staging.copy_stream` and decoupling host `std::memcpy` (`h2d_done[b]`) from device compute (`compute_done[b]`), increasing true 2-stream compute/H2D overlap **3.77x** (`6.6% -> 24.9%`, `154.4 ms -> 478.8 ms` at `8K`) and cutting `2K–128K` TTFT by **`-14.7% to -25.9%`** (`+17.3% to +35.0%` prefill tok/s, saving `8.67s–9.72s` at `128K`). 2. **Decode**: Replaces 129 software `MLFloat16::ToFloat()` scale conversions in `gguf_vec_dot_cpu.h` AVX2 loops with hardware F16C `_mm_cvtph_ps`, adds 4-route (`Batch-4`) fused AVX2 INT8 (`vpmaddubsw`) dot-product kernels (`AccumIq2S32Q8Batch4Avx2`, `AccumIq3Xxs32Q8Batch4Avx2`, `AccumIq4Nl32Q8Batch4Avx2`, `VecDotGgufRow4xQ8Batch4Avx2`, `VecDotGgufGateUpRow2xQ8Batch4Cpu`), scales `MoEPackedParallelPool` to `40` physical cores, and dispatches `MatMulPackedBf16TcWarpKSplit<4, 1>` for `N <= 2560`, cutting `MoEPackedDoorbellWaitKernel` by **`-49.6%`** (`53.40 -> 26.91 ms/cycle` exact; **`-81.9%`** to `9.66 ms/cycle` with `tail_sub=0.02`) and accelerating decode throughput by **`+60.1% to +79.4%`** (exact routing) and **`+102.8% to +152.5%` (`2.03x–2.53x`)** with tail expert substitution. ## Summary of Changes ### 1. `MoEPacked` 3-Stage Prefill Pipeline & Cold-Expert Decode (`onnxruntime/contrib_ops/cuda/moe/moe_packed.cc`) | File | Change | |------|--------| | `onnxruntime/contrib_ops/cuda/moe/moe_packed.cc` | Double-buffer `d_wave_sorted_routes[2]`, `d_wave_tiles[2]`, and `d_wave_num_tiles[2]` in `MoEPackedSharedPrefillWaveStaging` and copy them on `wave_staging.copy_stream` prior to recording `h2d_done[b]`; synchronize host `std::memcpy` only on `h2d_done[b]` while `copy_stream` waits on `compute_done[b]` on the device timeline; parallelize host expert staging across `w_cnt * 3` tasks; raise `MoEPackedParallelPool::ResolveThreads()` default cap from `24` to `40` cores; integrate `Batch-4` + `Batch-2` Q8 cold-expert execution in `RunColdDecodeStep()` (opt-in via `ep.cuda.moe_packed_cpu_q8_dot=1` or `ORT_MOE_PACKED_CPU_Q8_DOT=1` so existing FP16/BF16 models retain full FP32 cold-expert dot precision by default). | ### 2. Hardware F16C & 4-Route (`Batch-4`) AVX2 INT8 GGUF Kernels (`onnxruntime/contrib_ops/cpu/quantization/gguf_vec_dot_cpu.h`) | File | Change | |------|--------| | `onnxruntime/contrib_ops/cpu/quantization/gguf_vec_dot_cpu.h` | Add `Fp16ToFloatF16c` (`_mm_cvtph_ps`) under `ORT_GGUF_CPU_HAS_AVX2_TARGET` and replace 129 software `Fp16BitsToFloatCpu` calls inside AVX2 loops; add 4-route fused AVX2 INT8 dot-product kernels (`AccumIq2S32Q8Batch4Avx2`, `AccumIq3Xxs32Q8Batch4Avx2`, `AccumIq4Nl32Q8Batch4Avx2`, `VecDotGgufRow4xQ8Batch4Avx2`, `VecDotGgufRow4xQ8Batch4Cpu`, `VecDotGgufGateUpRow2xQ8Batch4Cpu`) plus 2-route `Batch-2` kernels from #34067. | ### 3. `MoEPacked` Decode FC2 & `MatMulPacked` Multi-Token GEMV (`moe_packed.cu`, `matmul_packed.cu`, `gguf_quant_cuda.cuh`) | File | Change | |------|--------| | `onnxruntime/contrib_ops/cuda/moe/moe_packed.cu` | Integrate #34067 4-warp (`64` output channels/CTA) `MoEPackedFc2Bf16TcKernel<1>` decode geometry with shared-memory `s_lut` GGUF lookup tables and direct `__ldg(fc1_row)` activation loads. | | `onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cu` | Integrate #34066 `(NR=2, KW=2)` multi-token GEMV and dispatch `MatMulPackedBf16TcWarpKSplit<4, 1>` when `N <= 2560` (`M in 2..8`) to double CTA grid occupancy (`1,280 -> 2,560` CTAs across 132 H200 SMs, `-45.4%` per-call latency on 72 GDN projection calls/cycle). | | `onnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuh` | Integrate #34066 uniform `uint16x2` `__ldg` loads in `ReadU32Dev` to eliminate 50% warp divergence on 2-byte-aligned GGUF blocks (`Q8_0`, `Q6_K`, `IQ4_NL`, `IQ4_XS`). | --- ## Performance & Accuracy Evaluation (`Qwen3.8-Flash-Next` `UD-IQ3_XXS` + `dflash2` `S=8` MTP on H200) ### 1. Setting 1: `30 GiB VRAM + 50 GiB RAM` (`device_expert_bytes = 12.50 GiB`, `6,463` GPU Resident Slots, Peak VRAM = `29.82 GiB`, Peak `VmRSS` = `35.44–36.09 GiB`) | Configuration | `2K` TTFT / Decode | `8K` TTFT / Decode | `32K` TTFT / Decode | `128K` TTFT / Decode | MMLU-Pro Smoke (`20`) Acc | MMLU Tok-Wtd / Med TPS | CPU `ms/step` (`us/exp`) | |---|---|---|---|---|---:|---|---:| | **1. Baseline (`origin/main` `6cc3c09506`)** | `1.061s` (`1,931 t/s`) / `39.18 t/s` | `2.433s` (`3,367 t/s`) / `38.87 t/s` | `9.156s` (`3,579 t/s`) / `39.28 t/s` | `38.790s` (`3,379 t/s`) / `38.31 t/s` | `100.0%` (`20/20`) | `41.36` / `43.84 t/s` | `61.58 ms` (`43.72 us`) | | **2. Merged PRs (#33975+#33976+#34066+#34067, FP32 CPU)** | `1.052s` (`1,947 t/s`) / `43.48 t/s` | `2.432s` (`3,369 t/s`) / `44.26 t/s` | `8.961s` (`3,657 t/s`) / `43.09 t/s` | `38.357s` (`3,417 t/s`) / `38.55 t/s` | `100.0%` (`20/20`) | `42.57` / `48.49 t/s` | `61.65 ms` (`43.52 us`) | | **3. Merged PRs (#33975+#33976+#34066+#34067, Q8 Batch-2 CPU)** | `1.035s` (`1,978 t/s`) / `50.17 t/s` | `2.395s` (`3,420 t/s`) / `50.37 t/s` | `8.942s` (`3,665 t/s`) / `49.13 t/s` | `38.318s` (`3,421 t/s`) / `47.88 t/s` | `100.0%` (`20/20`) | `49.50` / `57.69 t/s` | `47.85 ms` (`33.35 us`) | | **4. This PR (Exact Routing)** | **`0.786s` (`2,607 t/s`, `+35.0%`) / `62.73 t/s` (`+60.1%`)** | **`1.807s` (`4,534 t/s`, `+34.6%`) / `69.30 t/s` (`+78.3%`)** | **`6.813s` (`4,809 t/s`, `+34.4%`) / `69.45 t/s` (`+76.8%`)** | **`30.124s` (`4,351 t/s`, `+28.8%`) / `61.87 t/s` (`+61.5%`)** | `95.0%` (`19/20`) | **`67.12` / `79.32 t/s` (`+80.9%`)** | **`32.80 ms` (`22.89 us`)** | | **5. This PR + TailSub (`thr=0.02, min_rank=2`)** | **`0.853s` (`2,400 t/s`, `+24.3%`) / `97.11 t/s` (`+147.9%`)** | **`1.969s` (`4,160 t/s`, `+23.5%`) / `88.70 t/s` (`+128.2%`)** | **`7.495s` (`4,372 t/s`, `+22.2%`) / `81.71 t/s` (`+108.0%`)** | **`32.830s` (`3,993 t/s`, `+18.2%`) / `77.68 t/s` (`+102.8%`)** | **`100.0%` (`20/20`)** | **`97.76` / `108.06 t/s` (`+146.5%`)** | **`14.13 ms` (`25.95 us`)** | ### 2. Setting 2: `22 GiB VRAM + 24 GiB RAM` (`device_expert_bytes = 5.60 GiB`, `2,843` GPU Resident Slots, Peak VRAM = `21.71 GiB`, Peak `RssAnon` = `0.91–0.95 GiB`) | Configuration | `2K` TTFT / Decode | `8K` TTFT / Decode | `32K` TTFT / Decode | `128K` TTFT / Decode | MMLU-Pro Smoke (`20`) Acc | MMLU Tok-Wtd / Med TPS | CPU `ms/step` (`us/exp`) | |---|---|---|---|---|---:|---|---:| | **1. Baseline (`origin/main` `6cc3c09506`)** | `1.216s` (`1,684 t/s`) / `29.39 t/s` | `4.125s` (`1,986 t/s`) / `31.86 t/s` | `15.739s` (`2,082 t/s`) / `31.76 t/s` | `66.065s` (`1,984 t/s`) / `30.32 t/s` | `95.0%` (`19/20`) | `34.00` / `39.65 t/s` | `74.14 ms` (`42.04 us`) | | **2. Merged PRs (#33975+#33976+#34066+#34067, FP32 CPU)** | `1.197s` (`1,712 t/s`) / `34.54 t/s` | `4.042s` (`2,027 t/s`) / `35.58 t/s` | `15.762s` (`2,079 t/s`) / `33.70 t/s` | `66.006s` (`1,986 t/s`) / `34.26 t/s` | `95.0%` (`19/20`) | `37.03` / `42.90 t/s` | `73.66 ms` (`42.24 us`) | | **3. Merged PRs (#33975+#33976+#34066+#34067, Q8 Batch-2 CPU)** | `1.230s` (`1,665 t/s`) / `37.75 t/s` | `4.028s` (`2,034 t/s`) / `41.31 t/s` | `15.600s` (`2,101 t/s`) / `36.93 t/s` | `66.186s` (`1,980 t/s`) / `41.27 t/s` | `95.0%` (`19/20`) | `43.87` / `49.14 t/s` | `57.36 ms` (`32.47 us`) | | **4. This PR (Exact Routing)** | **`0.980s` (`2,090 t/s`, `+24.1%`) / `52.61 t/s` (`+79.0%`)** | **`3.345s` (`2,449 t/s`, `+23.3%`) / `52.73 t/s` (`+65.5%`)** | **`13.205s` (`2,482 t/s`, `+19.2%`) / `56.98 t/s` (`+79.4%`)** | **`56.343s` (`2,326 t/s`, `+17.3%`) / `50.16 t/s` (`+65.4%`)** | `95.0%` (`19/20`) | **`62.68` / `70.61 t/s` (`+78.1%`)** | **`38.21 ms` (`21.71 us`)** | | **5. This PR + TailSub (`thr=0.02, min_rank=2`)** | **`0.962s` (`2,130 t/s`, `+26.5%`) / `74.21 t/s` (`+152.5%`)** | **`3.321s` (`2,467 t/s`, `+24.2%`) / `74.47 t/s` (`+133.7%`)** | **`13.191s` (`2,484 t/s`, `+19.3%`) / `68.41 t/s` (`+115.4%`)** | **`56.890s` (`2,304 t/s`, `+16.1%`) / `72.87 t/s` (`+140.3%`)** | `95.0%` (`19/20`) | **`89.00` / `100.57 t/s` (`+153.6%`)** | **`17.55 ms` (`23.32 us`)** | ### 3. Nsight Systems (`nsys --cuda-graph-trace=node`) Before-vs-After Verification (`30g_50g`, `8192` Context) | Nsight Systems Metric (`8192` Context, `17` `S=8` MTP Cycles) | Pre-Optimization | Post-Opt (Exact) | Post-Opt (`tail-sub=0.02`) | Delta (Post Exact / Tail-Sub vs. Pre) | |---|---:|---:|---:|---| | **8K Prefill GPU Window (`Chunk 0 + Chunk 1`)** | `2,354.70 ms` | **`1,922.92 ms`** | **`1,919.95 ms`** | **`-431.78 ms` (`-18.3%`) / `-434.75 ms` (`-18.5%`)** | | **True 2-Stream Compute/H2D Overlap (`stream` & `copy_stream` both active)** | `154.43 ms` (`6.6%`) | **`478.83 ms` (`24.9%`)** | **`480.18 ms` (`25.0%`)** | **`+324.40 ms` (`3.10x` time / `3.77x` share)** | | **Both GPU Streams Idle in Prefill** | `293.64 ms` (`12.5%`) | **`84.03 ms` (`4.4%`)** | **`83.47 ms` (`4.3%`)** | **`-209.61 ms` (`-71.4%` idle bubble)** | | **48-Layer Target Verify CUDA Graph Duration (`ms/pass`)** | `84.11 ms/pass` | **`53.36 ms/pass`** | **`38.91 ms/pass`** | **`-30.75 ms` (`-36.6%`) / `-45.20 ms` (`-53.7%`)** | | **`MoEPackedDoorbellWaitKernel` (`48` calls/cycle)** | `53.40 ms/cyc` (`60.6%`) | **`26.91 ms/cyc` (`47.2%`)** | **`9.66 ms/cyc` (`22.7%`)** | **`-49.6%` (`1.98x` shorter) / `-81.9%` (`5.53x` shorter)** | | **`MatMulPackedBf16TcWarpKSplit<4, 1>` (`72` GDN calls/cycle, `N <= 2560`)** | `9.44 ms/cyc` (`131.1 us/call` on `<4,2>`) | **`5.15 ms/cyc` (`71.6 us/call`)** | **`5.17 ms/cyc` (`71.8 us/call`)** | **`-4.29 ms/cyc` (`-45.4%` per-call speedup)** | ## Testing - `pytest onnxruntime/test/python/transformers/test_gguf_packed_ops.py`: passes CPU/CUDA/hybrid offload numerical parity and tail-substitution tests on H200 (`sm_90`). - End-to-end `2K / 8K / 32K / 128K` context benchmarks and 20-item MMLU-Pro smoke evaluation under both `30 GiB VRAM + 50 GiB RAM` and `22 GiB VRAM + 24 GiB RAM` settings. ## Checklist - [x] Tests verified (`test_gguf_packed_ops.py` and MMLU-Pro smoke evaluation) - [x] No breaking changes - [x] Documentation updated --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.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.


Summary
This PR optimizes
com.microsoft::MoEPackedmulti-token (M = 4, 8) speculative decoding verification across both the CPU hybrid cold-route path (gguf_vec_dot_cpu.h) and the GPU Tensor Core FC2 decode path (moe_packed.cu):CPU Multi-Token Cold-Route Execution (
ExecuteMoEPackedColdRoutesCpuWithScratchingguf_vec_dot_cpu.h):std::vector<int> sorted_candstd::vector<ColdExpertGroup> groupsallocations with stack buffers (sorted_c_stack[128],groups_stack[128]) fornum_cold_routes <= 128, eliminating96heap allocations/frees per 48-layer verify step.BF16 -> FP32 + QuantizeRowQ8Cpuacrossnum_unique_tokswhennum_unique_toks >= 2.VecDotGgufRow4xQ8Batch2Avx2&VecDotGgufGateUpRow2xQ8Batch2Cpu): WhenM = 4orM = 8verification batch route to the same cold expert (ColdExpertGroupwithgrp.count >= 2, where measured cold-route reuse1.39x-1.48xatM=4and1.86x-2.07xatM=8), each GGUF weight sub-block (IQ2_XXS,IQ2_XS,IQ2_S,IQ3_XXS,IQ4_NL,IQ4_XS,Q2_0) is unpacked once in AVX2 registers and multiplied against two routes' Q8 activations simultaneously with0ULP difference.GPU Tensor Core FC2 Decode/Verify (
MoEPackedFc2Bf16TcKernel<1>inmoe_packed.cu):10.75 KBs_act_u4shared-memory activation staging buffer, integer-division staging loop, and K-loop__syncthreads()barrier whenkMaxSubTiles == 1(total_routes <= 128), loadingfc1_outdirectly via 128-bit__ldg.iq2xxs_grid,iq2xs_grid,iq2s_grid,iq3xxs_grid) in shared memory (s_lut,DecodeGgufSubBlock8SmemLutTpl<kDownType>) and switches decode CTA geometry from8warps (128output channels/CTA) to4warps (64output channels/CTA) in bothDispatchMoEPackedHotExpertsCudaandLaunchMoEPackedFc2Bf16TcDispatch<1>, doubling CTA grid parallelism across SMs.Measured Performance Impact (48-Layer
Qwen3.8-Flash-Next+dflash2.onnxon NVIDIA A100-SXM4-80GB)Table A: 48-Layer Verify Step Latency Progression (
UD-IQ2_XS)UD-IQ2_XS)MoEPackedFC2 + CPU Batch-2)MatMulPacked&ReadU32Dev)100% GPUMoEPacked(48 nodes,M=1 / M=4 / M=8)10.74 / 15.82 / 20.29 ms10.23 / 15.05 / 18.81 ms10.28 / 15.32 / 19.24 ms-0.5 to -1.5 ms50/50 HybridMoEPacked(48 nodes,M=1 / M=4 / M=8)17.40 / 27.02 / 37.81 ms18.31 / 24.69 / 33.91 ms16.98 / 24.83 / 34.33 ms-2.3 to -3.9 ms100% GPUT_verify(M=4)34.48-35.10 ms29.02-29.73 ms26.46-27.32 ms-7.9 ms/step(-22.8%)100% GPUT_verify(M=8)50.32-51.68 ms35.76-38.05 ms32.90-35.27 ms-16.9 ms/step(-33.2%)50/50 HybridT_verify(M=4)38.68-52.97 ms31.73-41.84 ms29.64-39.80 ms-11.1 ms/step(-24.2%)50/50 HybridT_verify(M=8)56.08-80.69 ms41.46-56.03 ms38.69-53.59 ms-22.2 ms/step(-32.5%)Table B: End-to-End
dflash2.onnxSpeculative Decoding (64Generated Tokens / Prompt, Combined Stage 2)M=1Decode (ms/tok/tok/s)Fixed M=8Peak (P1_structured)Adaptive M={4,8}3-Prompt Mean (tok/s/Speedup)UD-IQ1_S100% GPU21.16 ms(47.3 tok/s)185.3 tok/s(3.93x)106.0 tok/s(86.2harm.,2.24x)64/64(100.0%)UD-IQ1_S50/50 Hybrid(-5.21 GB)24.27 ms(41.2 tok/s)129.6 tok/s(3.43x)90.2 tok/s(84.9harm.,2.23x)64/64(100.0%)UD-IQ2_XS100% GPU19.91 ms(50.2 tok/s)197.4 tok/s(3.93x)123.7 tok/s(111.3harm.,2.46x)64/64(100.0%)UD-IQ2_XS50/50 Hybrid(-5.78 GB)23.77 ms(42.1 tok/s)126.8 tok/s(3.32x)89.8 tok/s(82.7harm.,2.17x)64/64(100.0%)UD-IQ3_XXS100% GPU22.27 ms(44.9 tok/s)177.5 tok/s(3.96x)109.3 tok/s(98.1harm.,2.44x)64/64(100.0%)UD-IQ3_XXS50/50 Hybrid(-7.04 GB)27.77 ms(36.0 tok/s)115.7 tok/s(3.30x)80.1 tok/s(74.1harm.,2.22x)64/64(100.0%)Validation
/usr/bin/clang-format --dry-run --Werrorandgit diff --check: 0 issuesctest --output-on-failure -V -R "GgufQuantPackedTest": 2/2 passed (100%)pytest onnxruntime/test/python/transformers/test_gguf_packed_ops.py -v: 33 passed, 811 subtests passed (100%)