Repository navigation
Reduce native packed decode tile and FC2 loader overhead - #34003
Rui Ren (rui-ren) wants to merge 4 commits into
Conversation
a51424a to
1ca7903
Compare
1ca7903 to
bbac6c0
Compare
Rui Ren (rui-ren)
left a comment
There was a problem hiding this comment.
Stack #33967 review — parent 99f4ab7c63a5 -> head bbac6c023794.
Reviewed all parent-relative changes: full NVFP4 tile guards, narrow eight-row FC1 tiles, aligned FC2 record-window selection, and multi-slot single-row Mamba readout ordering. The Mamba dispatch change preserves the four-part multi-row reduction for multi-slot replay while retaining the single-slot fast path; the added replay regression checks outputs and both snapshot types.
One additional regression-coverage gap, detailed inline: the newly eligible aligned FC2 record loader is exercised with repeated records/scales, so the tests cannot distinguish certain wrong-record selections. Add a nonuniform packed-row reference case for this new loader.
No wrong kernel result or out-of-row read demonstrated. Host checks covered 132,096 record windows across even-block row sizes and confirmed that the eligibility guard keeps the two-byte lookahead inside the row. This is not a fresh CUDA execution, capture/replay run, or throughput remeasurement.
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Reviewed this layer (stack #33967, layer 6, the top) at bbac6c0237.
Kernel review. I extracted this head's IQ2 FC1/FC2 and NVFP4 kernels into a standalone harness and ran them against the #34002 versions on random, non-uniform data. Every specialization is bit-identical across 10 shapes x 5 weight-base offsets (decode and 4-subtile prefill tiles), and compute-sanitizer memcheck is clean with exact-size weight allocations (a deliberately 4-byte-short bank is flagged, so the check is byte-exact). A standalone replica of the new Mamba replay test passes on this head and fails with the previous rows > 1 dispatch. I found no correctness defect.
Requests (inline)
- The FC2 window variant compiles to 79 registers on sm_90 (75 on sm_80), dropping occupancy from 4 to 3 CTAs/SM, and measures 3-8% slower than the plain loader at 2-9 rows on an H200; a min-CTAs
__launch_bounds__hint on that instantiation makes it 3-5% faster. I reproduced both. - The narrow FC1 tile has no measurement for this head and is mixed at prefill-tile route counts.
- The Mamba2Verify dispatch change is unrelated to the PR title, changes numerics of an op owned by #33969, and leaves the doc and the test references stale.
- The new Mamba regression test is not selected by the documented
FusedStateSpaceKernelTest.Mamba*filter. - Nit: redundant guard terms for the FC2 window.
Evidence in the description. The performance numbers pin ORT commit 0357a7df, which is the pre-rebase of 42ebcad5e8 ("Preserve Mamba readout order ...") and predates bbac6c0237 (narrow FC1). The only R8 row in the table is flat (361.46 -> 361.57 tok/s), the +27% ordinary-decode result is attributed to companion runtime/package changes, and the detailed evidence lives on a host path maintainers cannot inspect. The description is upfront that these results are historical, but a PR titled "Reduce ... overhead" should carry per-kernel before/after numbers (nsys/ncu or a microbenchmark) for the narrow FC1 tile, the FC2 window and the NVFP4 full tile on the target GPU, or be retitled as specializations pending measurement. For reference, my standalone H200 numbers: narrow FC1 -2..-8% at 72 routes but +4..+11% at 136 routes for hidden <= 2048; FC2 window +3..+8% slower as compiled; NVFP4 full tile -0..-7% for five of six chunk-128 shapes (+3.2% at n=8192, k=2048) and -11% / -40% at chunk 64.
Minor
- NVFP4 full-tile coverage:
Nvfp4Bf16ProductionProjectionShapesreaches the new specialization only for chunk 128 (its singlek % 128 != 0shape uses n=35), so chunk-64 + full tile has no test; a rows=8 case with n a multiple of 32 and k=192 or 576 would cover it.kFullNvfp4Tilealso silently assumesm_rt == 8andn % (MT*16) == 0(enforced only by the launcher guard); a one-line comment at the template declaration would stop a future caller reading rows pastm_rt. moe_packed_iq2.cuh: nokFc1 = true, kAlignedRecordWindow = trueinstantiation exists any more, yetcode = (kCodesWord || kAlignedRecordWindow) ? ... : ...still carries that combination, and the template's precondition (4-byte-aligned row base plus an even block count, otherwise the 2-byte look-ahead reads past the last row) is only documented in the function body. Considerstatic_assert(kCodesWord || !kAlignedRecordWindow)(or deleting the dead branch) and stating the precondition at the template parameter.- CI:
Kernel Documentation Generationfails here; it is inherited from #33994 (see my comment there).
bbac6c0 to
ed6e6e1
Compare
ed6e6e1 to
4f5f2b0
Compare
4f5f2b0 to
623a725
Compare
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Re-review of 623a725f5c.
Verdict: COMMENT — no defects found in this layer; it is blocked only by #33994's compile errors.
I checked each new guard against the invariant it relies on:
- narrow FC1 tile:
num_rows == 8, 16-byte aligned input withhidden_size % 8 == 0, decode tiling only (!use_prefill_tiles); theMT = 1instantiation derives every index fromMT, so it changes no partition boundary or rounding point; - aligned FC2 record window:
down_row_bytes % 4 == 0⇒ even number of 66-byte blocks ⇒ the last block's records are word-aligned ⇒ the two-byte look-ahead of the misaligned ones always stays inside the row (correct, and confirmed by memcheck below); - full NVFP4 tile:
rows == 8,N % (MT * 16) == 0, 16-byte alignedA,K % 8 == 0.
Independent verification (stack tip = this head; Linux, CUDA 13.0, sm_80;sm_90a, Release; A100-SXM4-80GB)
- Build OK; the stack's 60 provider tests and 5 internal CUDA tests pass (also 3x shuffled).
Iq2NonuniformSingleProductOracleAndEightNineRowEquivalence(rows 8 take the new narrow FC1 tile, rows 9 do not; 42 channels of nonuniform data with one surviving FC1 channel, so the oracle is exact) passes. The pre-existing*Packed*suites (655 tests) show 0 failures. - The aligned IQ2 record-window decoder is bit-exact against the CPU dequantizer (K = 512/1536/2048/2560) with 0
compute-sanitizermemcheck errors on exact-size allocations; synccheck, racecheck and initcheck on the tests are clean. - Not covered by anything I could run: the Hopper-only branches that the NVFP4 specializations extend (my GPUs are A100s).
CI is red
Windows GPU CUDA CI Pipeline,Windows CUDA Plugin EP Build,Windows GPU TensorRT CI Pipeline:moe_group_router_impl.cu(157), C4244 → C2220 — from #33994.wasm_Debug/wasm_Release/wasm_Release_static_library:linear_attention_gates.cc:300,302,-Wshorten-64-to-32— from #33994.build_x64_debug:onnxruntime_provider_testpassed; the only failure isonnxruntime_shared_lib_cpuinfo_dlopen_test, which this stack does not touch.
7b39b3f to
748fee6
Compare
748fee6 to
0abe947
Compare
Use bounded aligned record windows for eligible IQ2 expert projections, retaining the existing unaligned and odd-block fallbacks. Specialize complete aligned NVFP4 R8 tiles without changing their operands or reduction order. Cover the minimum eligible FC2 window width in the existing precision regression. This commit is a local qualification candidate, not an end-to-end performance claim. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: rui-ren <ruiren1225@gmail.com> Copilot-Session: f4d0e1a3-a389-4cc8-9c85-0fd0e3ffce5b # Conflicts: # onnxruntime/contrib_ops/cuda/moe/moe_packed_iq2.cuh
The aligned IQ2 record window is correct, but shared-expert FC1 cases regress in the isolated matrix and every live production FC1 width is slower. Retain the original byte-code FC1 path while keeping the independently eligible FC2 window and complete NVFP4 tile optimization. Qualify this narrower candidate separately before publication. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: rui-ren <ruiren1225@gmail.com> Copilot-Session: f4d0e1a3-a389-4cc8-9c85-0fd0e3ffce5b
Reduce live FC1 accumulators for aligned eight-row inputs by computing sixteen independent output columns per CTA. Preserve the existing four warp K partitions, reconstruction, BF16 casts and FC2 path. Leave one-token decode and offset bindings on their existing dispatch. Exercise the row-count and route-count boundaries at both 1024- and 4096-wide hidden inputs using independent expected values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: rui-ren <ruiren1225@gmail.com> Copilot-Session: f4d0e1a3-a389-4cc8-9c85-0fd0e3ffce5b
Add a minimum-CTA bound only for aligned-window FC2 variants, preserving other specializations. Keep the R8 narrow tile out of four-subtile prefill and simplify the loader guard to its actual even-block row-alignment invariant. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f4d0e1a3-a389-4cc8-9c85-0fd0e3ffce5b Signed-off-by: rui-ren <ruiren1225@gmail.com>
0abe947 to
37b580b
Compare
Description
Reduces CUDA packed decode tile/loader overhead above #34002. Narrows eligible
eight-row IQ2 FC1 tiles, adds aligned record-window reconstruction for eligible
IQ2 FC2 rows, and uses full-tile NVFP4 paths only when their shape/alignment guards
hold. Unsupported geometries retain the existing fallback.
Dependency: #34002 in
native stack #33967.
No schema, packed layout, cache/mask precision workaround, or GenAI source change.
The R8-prefill/R1-ordinary hybrid session/package work is in the companion
microsoft/onnxruntime-genai#2916, not implemented by this native-kernel PR.
Summary of Changes
Packed Decode Specializations
onnxruntime/contrib_ops/cuda/moe/moe_packed.cuonnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuh,onnxruntime/contrib_ops/cuda/moe/moe_packed_iq2.cuhonnxruntime/contrib_ops/cuda/quantization/matmul_packed.cuonnxruntime/test/contrib_ops/moe_packed_routing_test.ccTesting
Review-fix snapshot:
ed6e6e1991fd944f65f1d97472d3f29046d97361.Bound aligned-window FC2 to four resident CTAs, kept the R8-specific narrow FC1 gate decode-only (
!use_prefill_tiles), simplified the FC2 guard to its real row/base alignment invariant, and reused the lower shared decoder. Nonuniform regression protection is introduced in #33963/#34002. Mamba replay changes were moved into their owning PR #33969; this layer no longer changes Mamba numerics or tests.Owning-layer validation: Integrated stack regression run and exact-production-kernel H100 A/B below.
Integrated tip regression: 51 C++ provider/schema tests, 5 actual internal CUDA tests and 2 Python IOBinding tests passed, zero failures/skips. All owning-layer provider cases are retained. The final overlay recompiles the changed CUDA/host/schema/test sources over ABI-matched preserved ORT support; not a clean full-source build, full-CI approval, independent HF parity or new end-to-end qualification. Targeted configured clang-format/Ruff and whitespace checks passed.
Review-requested kernel A/B (H100, CUDA 12.8.93)
Exact production kernel/helper text from the integrated head; random nonuniform IQ2, 512 experts, 16 rotating route sets, R=8. All variant outputs are bit-identical across all route sets. CUDA-event median: 20 warmups, 9 alternating batches x32 launches; no full-model/cold-cache guarantee.
k=9is decode,k=17is four-subtile prefill; the latter remains excluded from the narrow dispatch.The local 12.8 compiler did not reproduce the reported 79-register/3-CTA window allocation: unhinted and hinted window kernels both use 64 registers/4 CTAs here. The selective hint is retained as a portability cap for the reviewer's newer-toolchain result, with its local timing tradeoff shown rather than hidden. These kernel-only measurements do not attribute the older hybrid end-to-end gains below to the later narrow-tile commit.
Historical measurements and qualification evidence (not current-head acceptance)
These previously reported results are retained for provenance. They have not been rerun on the rebased head above; earlier CI/build status and benchmark results do not establish current-head CI, accuracy, or merge readiness.
The following results include the companion GenAI runtime and hybrid package, not just this PR's native kernel changes. They use the original pinned binaries and package hashes below, not the current rebased ORT head.
Unprofiled frozen real30, six H100s, two reversed same-GPU passes, 240 complete measured
generations; original warmups, mode order, EOS/512 cap.
Ordinary TTFT medians: short 357.35→359.00ms, medium 826.97→831.29ms,
long 2153.15→2161.92ms. The earlier static-R1 version's prefill regression is not
the package being qualified here.
Separate same-GPU synthetic-2048 CUDA profiles, 64 captured target passes:
IQ2 expert work 3.259→1.496ms/pass, Mamba 0.824→0.423ms/pass.
These are device-work attribution, not an additional throughput claim.
Correctness: all240 exact same-mode sequences and complete counters match;
388 complete live committed-state boundaries (66.43GB compared), capture off/on,
two resets, prefix through130; original R8 ordinary/k7 retains1782 complete finite
tensor hashes. Three native kernel tests, seven Mamba operator tests, fifteen
GenAI tests execute without skips. The new replay test also passes CUDA memcheck
with zero errors (100 repetitions).
Scope: hybrid is ordinary-only. Both speculative arms use the original R8 package.
The benchmark explicitly keeps two per-mode models resident in each arm; it is not
a unified hybrid-speculative package or a k7 speedup. No precision/cache/mask workaround,
no weight repack, no independent HF rerun, no clean-build/full-CI claim.
Reproduce the exact tested graph/config with:
Requires onnx-ir/numpy/ml-dtypes and both updated runtimes. External-data validation
stays enabled; payloads are hardlinked inside the output package, not copied.
Pins:
0357a7dfe47d3c383bf36be62015162b6a612d5ed73a6e627d6d20a5a1688b9fbd46237069a7be89db6ffd29fc96e319f645ff461efa05c643235f29(converter/docs-only child)fac33c75d0336236736aa96456268057b628d93d0b9901d49598e275bf335275f977660a408bc0a01a31151c7280282ba443fa256785680ae3e841654eec9be7aaf5d6ae06b6740ab5b3af523359581930d2b6c42c38a18529a22737c2cfe53077f2d920d2b04e17884c3d2ee691d9053225b957c047454ebd0a4ea3649dac4406d3d508e8d11235d0b770484b6b59764c2f297c3383b6d0de75648d26c11867Full commands, per-case exact tokens/counters, raw kernel traces, provider maps,
UUID/admission receipts, and rejection evidence remain on the validation host under
/opt/bolt-runtime-fixes-20261108-v1/evidence/ordinary-r1-v1. Sealed manifest SHA256:412b3898f09565557b01e82906358f017f9df3227db2bf330850245a52d32bbc.Root-disk binaries were reloaded and verified with full ordinary/k7 generation;
the large model payload still resides on the existing tmpfs, not reboot-persistent.
Original package/deployment untouched; no merge.
Checklist