Repository navigation
[CUDA] Add state_status output to PackedSparseAttentionIndexer - #33383
Merged
Merged
Conversation
Tianlei Wu (tianleiwu)
force-pushed
the
tianleiwu/packed-qsa-status
branch
from
October 16, 2026 16:26
66e7cc4 to
d2ee6a3
Compare
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Empty-batch CSA reuse can exceed the status output’s extent, and the rejection contract incorrectly promises unchanged state lengths.
2 open issues
What changed in this PR
Adds optional per-request state_status reporting to PackedSparseAttentionIndexer, letting CUDA graph callers detect rejected state updates after replay.
Changes:
- Extends the schema and documentation with status codes and output shape.
- Reuses CUDA rejection flags as the output; rejects unsupported WebGPU requests.
- Adds status-reporting and multi-token QSA regression tests.
| File | Description |
|---|---|
onnxruntime/test/contrib_ops/packed_sparse_attention_indexer_op_test.cc |
Adds status and chained-step tests. |
onnxruntime/core/graph/contrib_ops/bert_defs.cc |
Defines and infers the optional output. |
onnxruntime/contrib_ops/webgpu/bert/packed_sparse_attention_indexer.cc |
Rejects requests for the CUDA-only output. |
onnxruntime/contrib_ops/cuda/sparse/packed_sparse_attention_indexer.cc |
Connects status output to rejection flags. |
onnxruntime/contrib_ops/cuda/sparse/packed_sparse_attention_indexer_impl.h |
Documents the status buffer contract. |
onnxruntime/contrib_ops/cuda/sparse/packed_sparse_attention_indexer_impl.cu |
Writes distinct rejection codes. |
onnxruntime/contrib_ops/cpu/sparse/packed_sparse_attention_indexer_common.h |
Adds output index and status constants. |
docs/OperatorKernels.md |
Lists the new output. |
docs/ContribOperators.md |
Updates the generated operator contract. |
docs/contrib_ops/packed_sparse_attention_indexer.md |
Explains status semantics and provider support. |
Review effort: Balanced
Tianlei Wu (tianleiwu)
force-pushed
the
tianleiwu/packed-qsa-status
branch
from
October 19, 2026 22:10
4a66e9a to
f676394
Compare
Tianlei Wu (tianleiwu)
marked this pull request as ready for review
October 19, 2026 23:12
Add an optional per-request int32 state_status output (output 8) that exposes the device-side rejection flags the state update kernels already compute: 0 applied/held, 1 invalid device metadata, 2 state_capacity overflow (same codes as PackedSparseAttentionIndexerMerge). Without the output nothing changes. The status never leaves the device, so CUDA graph callers can check it after replay. WebGPU rejects the output. Add tests for the status values (QSA, CSA, IndexShare CSA advance) and a test that a two-row QSA step equals two chained single-row steps. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e in reuse validation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… contract - Guard overflow_flags memset on CSA state-only reuse when batch_size == 0 - Clarify that rejected updates leave state payloads unchanged and clamp out-of-range past_state_lengths into present_state_lengths across schema, header, and operator docs - Support state_status in symbolic shape inference and fallback batch dimension inference - Add regression tests for empty-batch CSA advance reuse, QSA hold reuse, and state_status shape inference Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tianlei Wu (tianleiwu)
force-pushed
the
tianleiwu/packed-qsa-status
branch
from
October 21, 2026 00:31
5dd1aaa to
84063d1
Compare
Contributor
|
lgtm |
Akshay Sonawane (apsonawane)
approved these changes
Oct 21, 2026
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
Stacked on #33224 (base
kvaishnavi/index-share; review only the top commit). Adds an optionalstate_statusoutput toPackedSparseAttentionIndexerthat reports, per request, whether this call's state update was applied or rejected, and why.Today a rejected step (inconsistent cursor or
state_capacityoverflow) is a safe no-op on state with an empty selection, but the caller cannot tell it happened: the rejection flags live in a scratch buffer andindexshare_statusis only produced on the IndexShare interface. A CUDA-graph-replayed decode/verify loop cannot synchronize inside the operator, so it needs a device tensor it can read on the host after replay.Summary of Changes
Schema and docs
bert_defs.ccstate_status(int32, shape(batch_size)); declared output range is now 6-9; type/shape inference; one doc sentencepacked_sparse_attention_indexer_common.hkStateStatus = 8,kOutputCount = 9,StateStatusCode{0 ok, 1 invalid device metadata, 2 capacity overflow}docs/ContribOperators.md,docs/contrib_ops/packed_sparse_attention_indexer.mdCUDA / WebGPU
packed_sparse_attention_indexer_impl.cu/.h1into the existingoverflow_flags; all readers still test!= 0, so selection behaviour is unchangedpacked_sparse_attention_indexer.ccoverflow_flagsbuffer (no extra kernel, no copy, no host sync). On the IndexShare reuse path that holds state (QSA, CSAhold) it is zero-filled withcudaMemsetAsyncwebgpu/.../packed_sparse_attention_indexer.ccstate_statusis requested (CUDA only, like IndexShare)Semantics
selected_counts == 0, indices-1), exactly as before.PackedSparseAttentionIndexerMerge(1 invalid device metadata, 2 capacity overflow).state_statusis independent ofindexshare_status(per-query selection status, forwarded on reuse and zero on refresh). On CSA reuse withadvance, both are set when a row is rejected.Testing
Built with CUDA 13.0, sm_90, in-tree CUDA EP, and run on one H200:
177 passed (17 WebGPU tests skipped, no WebGPU in this build);
PackedSparseAttentionIndexerTest.*repeated 20 times, no flake.New tests in
packed_sparse_attention_indexer_op_test.cc(Qsa/CsaStateStatus*,IndexShareCsaAdvanceReportsStateStatus,QsaTwoRowStepEqualsChainedSingleRowSteps):{ok, invalid, overflow}, for QSA and CSA, checked against the host reference (which now also computes the codes);state_statusleaves selections and state bit-identical to not requesting it;indexshare_status = 1andstate_status = 2;compress_ratio2 and 4, all three cursor phases) is bit-identical in selections, block state and pending entries to two chained one-row steps. This passes without any kernel change, i.e. the multi-row verify step is already supported bymain; the test pins that contract.Mutation checks: with the output plumbing removed 7 new tests fail; with code 2 reported as 1, 4 fail; existing tests pass in both.
Not covered: WebGPU compile (not in this build), plugin-EP build, an end-to-end CUDA-graph capture/replay (the kernels are launch-only and the reuse-path zero fill is
cudaMemsetAsync, so nothing in the path synchronizes).Motivation and Context
Needed by decode/verify loops that capture the indexer in a CUDA graph and drive it with device-resident lengths (as in the multi-token verify path of #33328). Reuses the status convention introduced in #33224 so callers see one scheme. Touches different hunks from #33328 (scoring kernels); a trivial merge is expected for the test file.
Checklist