Repository navigation
Conversation
Adds the session config entry ep.cuda.mamba2verify_compact_replay, default "0". With "1", in-place Mamba2Verify calls with at most 8 rows keep the committed SSM state in slot 0 and the step inputs in slot 1, and replay the accepted rows on the next call instead of writing every per-row FP32 snapshot. Other in-place calls first fold any pending window into the selected slot and then run the existing kernels. With "0" the existing kernels and outputs are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
A critical metadata race can send warps down inconsistent barrier paths and hang the kernel; it needs an unconditional block barrier after metadata reads and a regression test for the compact-path rejection case.
1 open issue
What changed in this PR
Adds opt-in compact speculative replay to ONNX Runtime’s CUDA Mamba2Verify operator, reducing recurrent-state writes while preserving the default mode and supporting large-prefill handoffs.
Changes:
- Adds a validated session option and compact replay kernels with a pre-pass for fallback calls.
- Adds parity, reset, invalid-selector, and CUDA Graph tests.
- Documents compact-state layout and caller restrictions.
| File | Description |
|---|---|
onnxruntime/test/contrib_ops/fused_state_space_op_test.cc |
Adds session-level parity, option validation, and graph-capture tests. |
onnxruntime/test/contrib_ops/cuda_kernels/fused_state_space_test.cc |
Tests replay, prefill handoffs, resets, and invalid selectors. |
onnxruntime/contrib_ops/cuda/sequence/fused_state_space.cc |
Validates the session option and selects the write mode. |
onnxruntime/contrib_ops/cuda/sequence/fused_state_space_impl.h |
Defines replay modes and extends the launch interface. |
onnxruntime/contrib_ops/cuda/sequence/fused_state_space_impl.cu |
Implements compact replay storage, kernels, and fallback resolution. |
docs/contrib_ops/cuda/mamba2_verify.md |
Documents configuration, state semantics, and usage restrictions. |
Review effort: Balanced
| const int prev_rows = pending ? meta->last_rows : 0; | ||
| const int sel_val = *sel; | ||
|
|
||
| if (sel_val < 0 || static_cast<int64_t>(sel_val) >= slots || (pending && sel_val >= prev_rows)) { |
This branch has not been deployed
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.

Description
Adds an opt-in compact speculative replay mode to the
com.microsoft::Mamba2VerifyCUDA kernel (#33969), selected by the session config entryep.cuda.mamba2verify_compact_replay(default"0"; only"0"and"1"are accepted).With
"1", in-place calls (ssm_snapshotsaliasesssm_state,slots >= 2) with1 <= R <= min(8, slots)keep the committed FP32 state in slot 0 and the window's(x, B, dt)in a per-head 32 KiB slice of slot 1, then replay the accepted rows in registers on the next call instead of writingRfull FP32 snapshots every verify step (8 x 4 MiB x 40 layers = 1.25 GiB per step on Nemotron-3.5-Bolt).Other in-place calls in this mode, including the large-
Rprefill from #34164, run the unchanged default kernels after a small per-head pre-pass. The pre-pass replays any pending window into slotstate_rowand clears the slot 1 header, so those kernels start from the same snapshot"0"would have left there. Callers that read or snapshot/restore intermediate or committed recurrent slots (for example prefix-cache recurrent-state capture/restore) must keep"0", because"1"keeps the committed base SSM state in slot 0 and pending step inputs in slot 1 rather than materializing slotstate_row. A reset must rewrite the whole state tensors, not only slot 0 (onnxruntime-genai'sNemotronBoltState::Reset()zeroes them). Nonaliased calls run the default kernels and do not read slot 1.With
"0"nothing changes: the 9 existing kernel instantiations compile to identical PTX under both the plugin and non-plugin build flags, and there is no schema change. The compact kernels pin the FMA pairing nvcc emits for the default recurrence,fma(st, dA, dtx * B), so"0"and"1"produce bitwise-identical outputs.Testing
This branch is rebased onto
mainf4cd337911c2; none of its 6 files changed sinced2f77cd96dfd. On the pushed commit (plugin build),onnxruntime_provider_test --gtest_filter=*FusedStateSpace*:*Mamba*passes 18/18. The gates below ran onmaind2f77cd96dfd+ this PR, NVIDIA A100-SXM4-80GB, driver 580.159.04, CUDA 13.0, cuDNN 9.12,-DCMAKE_CUDA_ARCHITECTURES=80, plugin and non-plugin CUDA EP builds.onnxruntime_provider_test --gtest_filter=*FusedStateSpace*:*Mamba*: 18/18 in both builds. New:MambaCompactReplayMultiRoundAndPrefillHandoffParity("0"vs"1"bitwise at 4 and 64 heads: multi-roundR=8partial acceptance,R=37prefill into the 8-slot bank handing off throughstate_row=7, a laterR=37chunk resuming from a pending window, nonaliased fallback, invalid selectors),MambaCompactReplayCudaGraphCaptureAndReplay,MambaInvalidCompactReplayPolicyRejected.FusedStateSpaceKernelTest: 7/7 throughCUDA_EP_Unittest.All(onnxruntime_ENABLE_CUDA_EP_INTERNAL_TESTS=ON) and standalone. New:MambaCompactReplayMatchesDefaultAcrossPrefillHandoffAndResets(64 heads, 8 and 16 slots,Rin {1, 5, 7, 8, 9, 12, 16, 37} including a fold into slot 1, two passes with a full state reset in between;Y,xbc,readoutand conv snapshots compared bitwise after every call, the full SSM state after every default-kernel call).R > 8call after a pending window (8 slots:R=37,state_row=2; 16 slots:R=12,state_row=6). Earlier steps, includingR=37prefill followed byR=8verify atstate_row=7, pass either way.compute-sanitizer: memcheck 0 errors (18 provider tests, 7 kernel tests); racecheck 0 hazards, synccheck 0 errors, initcheck 0 errors on the compact tests.ptxas: 0 spill bytes for every kernel; compact kernels 64-66 registers, pre-pass 60.pytest onnxruntime/test/python/transformers/test_gguf_packed_ops.py(plugin build): 50 passed.git diff --checkclean.Performance
Kernel microbenchmark, A100-SXM4-80GB, Nemotron-3.5-Bolt geometry (128 heads, 8 groups, 8 slots), 8 rotating state banks (cold L2), 200 interleaved AB/BA pairs, per layer (medians; ratio of means with bootstrap 95% CI):
"0""1"R=8verify, CUDA Graph,state_row0R=8verify, CUDA Graph,state_row3R=8verify, CUDA Graph,state_row7R=8verify, eager,state_row3R=37/512/4096chunk, no pending windowThe same binary checks Bolt-geometry parity: 13/13 calls bitwise identical over an
R = 4096, 8, 37, 1, 512sequence.End-to-end on this branch (
mainf4cd337911c2+ this PR, plugin CUDA EP) with onnxruntime-genai75fa2250c9af: fixed[1, 8]74B package with compact replay set only throughgenai_config.json, 100 MMLU-Pro prompts (greedy, up to 1024 new tokens) in interleaved ABBA blocks on one A100. 100/100 identical token sequences and speculative counters, decode 193.42 -> 198.60 tok/s (+2.73%, 95% CI [+2.68%, +2.77%]), mean verify plus draft round latency -2.65%. Setting"2"the same way fails model creation with this kernel's error, so the entry reaches the kernel.Not covered
B > 1, GPUs other than A100, multi-turn continuation through onnxruntime-genai, and banks with fewer slots than rows (R <= 8butR > slots), which take the pre-pass plus default path and are not separately tested.