Skip to content

[CUDA] Fix packed-INT QMoE expert-counting capture and consume - #32942

Merged
aciddelgado merged 3 commits into
mainfrom
aciddelgado/qmoe_packed_int_expert_counting
Sep 30, 2026
Merged

aciddelgado merged 3 commits into
mainfrom
aciddelgado/qmoe_packed_int_expert_counting

Conversation

@aciddelgado

Copy link
Copy Markdown
Contributor

Description

Fix the CUDA QMoE packed-INT GEMV path's remaining reference to the removed
routing_record API and add a focused expert-counting regression.

  • Capture selected expert IDs immediately after routing and consume the snapshot
    before the packed-INT path returns, using the same lifecycle as the neighboring
    paths. Preserve the existing non-plugin/non-minimal guards.
  • Add MoeExpertCountingTest.CudaQMoEPackedIntGemv: FP16, INT2, fused SwiGLU,
    three rows, four experts, top-k 1, 512-wide hidden/intermediate dimensions,
    and block size 64.
  • Verify expert-dependent numerical outputs and per-invocation selection counters:
    duplicate routes [0, 0, 2], a repeated invocation, then changed routes
    [1, 1, 1]. Expected counters are [0.1, 0, 0.1, 0],
    [0.19, 0, 0.19, 0], and [0.171, 0.1, 0.171, 0].
  • Disable CPU fallback and cap dense dequantization scratch at one byte, so a
    successful run cannot silently use the dense fallback.

Only moe_quantization.cc and moe_expert_counting_test.cc change. Routing
selection and GEMV arithmetic are unchanged; no WebGPU/PagedAttention changes
are included.

Validation

Built and executed locally on NVIDIA A100-SXM4-80GB (SM80), CUDA 12.8.93,
GCC 11.4, cuDNN 9.10.2.21, Release, warnings-as-errors, QUICK_BUILD=OFF.
The existing CUDA build tree was reconfigured from SM86 to SM80, recompiling
the CUDA targets. This is not a claim of CUDA 13/GCC 14 CI validation.

After configuring with the same options plus --update, the following build
command passed:

source /workspace/venv/bin/activate
python tools/ci_build/build.py \
  --build_dir /workspace/onnxruntime/build/cuda-ci-20260929 \
  --config Release --build --parallel 16 --cmake_generator Ninja \
  --build_shared_lib --build_wheel --enable_onnx_tests --use_cuda \
  --use_binskim_compliant_compile_flags --nvcc_threads 4 --flash_nvcc_threads 4 \
  --cuda_version=12.8 --cuda_home=/usr/local/cuda-12.8 \
  --cudnn_home=/workspace/venv/lib/python3.11/site-packages/nvidia/cudnn \
  --enable_cuda_profiling --skip_tests --allow_running_as_root \
  --targets onnxruntime_test_all onnxruntime_provider_test \
  --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=80 \
  onnxruntime_BUILD_UNIT_TESTS=ON \
  onnxruntime_ENABLE_CUDA_EP_INTERNAL_TESTS=ON \
  onnxruntime_BUILD_CUDA_QUANT_PREPROCESS=ON

Tests were run from the build output directory:

cd /workspace/onnxruntime/build/cuda-ci-20260929/Release
export LD_LIBRARY_PATH=/workspace/venv/lib/python3.11/site-packages/nvidia/cudnn/lib:/usr/local/cuda-12.8/lib64:${LD_LIBRARY_PATH:-}

./onnxruntime_test_all --gtest_filter='MoeExpertCountingTest.CudaQMoE*'
# PASS: 4 tests, no skips.

./onnxruntime_provider_test --gtest_filter='MoETest.QMoETest_Int2CudaPackedDecodeMultiRowExpertParity'
# PASS: 1 test, no skips.

ORT_ENABLE_QMOE_KERNEL_DEBUG_INFO=1 ./onnxruntime_test_all \
  --gtest_filter='MoeExpertCountingTest.CudaQMoEPackedIntGemv'
# PASS: 1 test; all three invocations log Route=packed_int_gemv Rows=3.

Negative control: temporarily omitted both packed-path Capture and
Consume, rebuilt with
cmake --build build/cuda-ci-20260929/Release --target onnxruntime_providers_cuda --parallel 16,
and ran
./onnxruntime_test_all --gtest_filter='MoeExpertCountingTest.CudaQMoEPackedIntGemv'.
It failed as intended: outputs still matched, but seven counter assertions
failed because all counters remained zero (first failure: expert 0 expected
0.1, actual 0). Restored the repair, rebuilt the provider, and reran both
focused suites: all five tests passed. No negative-control edits are committed.

Motivation and Context

The expert-counting migration in #32738 left a stale routing_record->CaptureTile
call in the packed-INT GEMV early-return path. This prevents ordinary built-in
CUDA compilation on current main; simply deleting that call would compile but
silently omit expert counts for this path.

This separates the repair originally included in #32808, following
the scope/coverage review comment.
The production patch is carried unchanged from commit 1f57e92abe; the new
regression verifies the runtime counting behavior as well as compilation.
After this lands, merging main into #32808 will remove the unrelated MoE file
from that PR's diff.

aciddelgado and others added 2 commits September 29, 2026 20:29
(cherry picked from commit 1f57e92)
Exercise INT2 SwiGLU GEMV with a dense-dequantization scratch cap, deterministic expert-dependent outputs, duplicate selections, repeated invocations, and changed routing. Verify counters are lost when packed-path capture and consume are omitted.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings September 29, 2026 21:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟒 Approval recommended

The narrow lifecycle fix matches neighboring paths and is covered by targeted numerical and counter assertions.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes CUDA QMoE packed-INT GEMV expert counting and adds focused regression coverage.

Changes:

  • Captures and consumes routed expert snapshots using the established lifecycle.
  • Tests repeated and changed routing while preventing CPU/dense fallback.
File Description
onnxruntime/​contrib_ops/​cuda/​moe/​moe_quantization.cc Repairs expert snapshot handling.
onnxruntime/​test/​framework/​moe_expert_counting_test.cc Adds packed-INT counting regression.

πŸ’‘ Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

aciddelgado added a commit that referenced this pull request Sep 29, 2026
Revert the MoE-only change from 1f57e92. The repair and focused expert-counting regression are tracked separately in #32942. Leave the WebGPU Q/K-norm implementation and tests unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aciddelgado
aciddelgado enabled auto-merge (squash) September 29, 2026 22:38
@aciddelgado

Copy link
Copy Markdown
Contributor Author

Copilot resolve the merge conflicts in this pull request

…ed_int_expert_counting

# Conflicts:
#	onnxruntime/test/framework/moe_expert_counting_test.cc

Co-authored-by: aciddelgado <139922440+aciddelgado@users.noreply.github.com>

Copilot AI commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Merged main and resolved the test conflict, retaining the PR's more comprehensive packed-INT regression. Merge commit: d2b730f6.

@aciddelgado
aciddelgado merged commit 74810e5 into main Sep 30, 2026
95 of 96 checks passed
@aciddelgado
aciddelgado deleted the aciddelgado/qmoe_packed_int_expert_counting branch September 30, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants