Repository navigation
[CUDA] Support right-padded prefill chunks in GroupQueryAttention - #33503
Tianlei Wu (tianleiwu) merged 11 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The padding heuristic misclassifies existing fixed-bound callers, shifting cache offsets and discarding valid tokens.
1 open issue
What changed in this PR
Adds right-padded chunked prefill support to CUDA GroupQueryAttention across FlashAttention, memory-efficient, and unfused backends.
Changes:
- Adjusts sequence lengths, cache eviction, and causal alignment for padding.
- Zeros padded K/V entries.
- Adds padded-prefill coverage, including quantized caches.
| File | Description |
|---|---|
onnxruntime/test/python/transformers/test_gqa.py |
Adds padded-step parity tests across backends. |
onnxruntime/test/contrib_ops/group_query_attention_op_test.cc |
Corrects test lengths and covers padded windowed chunks. |
onnxruntime/contrib_ops/cuda/bert/unfused_attention.h |
Adds optional per-batch past lengths. |
onnxruntime/contrib_ops/cuda/bert/unfused_attention.cu |
Uses explicit past offsets for masking. |
onnxruntime/contrib_ops/cuda/bert/group_query_attention_qkv.cuh |
Zeros padded cache entries and adjusts RoPE assertions. |
onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.cu |
Updates padding-aware lengths and backend wiring. |
Review effort: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical findings include incorrect quantized attention and cache handling, possible out-of-bounds reads, and graph-resolution failures.
10 open issues
Preserve floating-point KV for valid quantized first-chunk rows · New Preserve borrowed-KV length and causal alignment without query_seqlens · New Copy past KV into non-aliased quantized present buffers · New Preserve query_seqlens in GroupQueryAttentionFusion · New Reject query_seqlens GQA nodes during OpenVINO partitioning · New Guard BF16 golden test on Ampere-or-newer CUDA · New Clamp shared-KV padding length to cache capacity Use supported head size in quick-build Flash regression Preserve signed past offset for shared-KV alignment Regenerate OperatorKernels.md for the new GQA input · New
Review effort: Max
40bbbff to
6a2b0e6
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical issues break INT8 padded/unpadded parity, change behavior when query_seqlens is omitted, reject valid growing-cache inputs, and cause backend tests to fail on valid builds lacking optional features.
4 open issues
10 resolved since last review
Guard BF16 golden test on Ampere-or-newer CUDA Reject query_seqlens GQA nodes during OpenVINO partitioning Preserve query_seqlens in GroupQueryAttentionFusion Copy past KV into non-aliased quantized present buffers Preserve borrowed-KV length and causal alignment without query_seqlens Preserve floating-point KV for valid quantized first-chunk rows Clamp shared-KV padding length to cache capacity Use supported head size in quick-build Flash regression Preserve signed past offset for shared-KV alignment Regenerate OperatorKernels.md for the new GQA input
Review effort: Max
Support right-padded query chunks (including subsequent prefill chunks and sliding_window_cache=1) in CUDA GroupQueryAttention across FlashAttention, MemoryEfficientAttention, and Unfused attention paths: - Derive past_len from max_total_sequence_length - sequence_length when a subsequent prefill chunk (sequence_length > 1) is right-padded, and compute windowed KV cache eviction and resident lengths from valid_q_len rather than the padded sequence_length. - Populate padded_seq_lens as past_len + sequence_length (or cache_past_len + sequence_length when windowed) and pass it to causal FlashAttention and MemoryEfficientAttention so valid query rows stay aligned at their true past offset. - Pass past_seq_lens to UnfusedAttentionParams so UnfusedSoftmaxKernel aligns queries at past_seq_lens[batch] + q_in_head instead of seqlens_k[batch] - q_sequence_length. - Zero right-padded KV positions (cache_s >= valid_seq_lens[b]) in UnpackRoPEAppend so padding tokens never pollute the KV cache or leave uninitialized values in a windowed staging buffer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve capacity-valued length callers by making padded prefill interpretation opt-in. Keep ragged decode offsets per batch, exclude cuDNN's unpadded-query path, and verify every forced attention dispatch. Add capacity-bound, padded global-attention, quantized first-prompt, ragged decode, and attribute-validation regressions, and document the contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the right_padded_query attribute with an optional query_seqlens input (index 16) so that a fixed-shape, right-padded query chunk carries its valid length per batch entry instead of deriving it from total_sequence_length - sequence_length. The input is part of the operator contract, so every execution provider can implement it with identical semantics. CUDA: GetSequenceLengths takes the valid query length from the input (clamped to [1, min(S, T)]) and the present-cache capacity, appends only the valid rows at [T - Q, T), and disables cuDNN SDPA for padded chunks. The shared CheckInputs helper validates the input and no longer classifies the step by comparing S with total_sequence_length when the input is present. The CPU kernel and other EPs reject the input until they implement it. Also keep trailing node inputs (such as query_seqlens) when the GroupQueryAttention pre-norm fusion rebuilds the input list, and cover that with a unit test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve borrowed-KV lengths and signed causal offsets. Initialize quantized present buffers from past caches and keep floating-point KV for first-chunk attention when query_seqlens supplies the valid lengths. Retain optional inputs during GQA fusion, apply the OpenVINO rejection to the contrib domain, guard BF16 coverage by device capability, and use quick-build compatible Flash test shapes. Refresh generated GQA kernel documentation. Validation: 137 provider tests and 33 fusion tests passed; 61 Python tests and 36 subtests passed. Reverting the fixes reproduces the new regression failures. CUDA memcheck reports zero errors; lintrunner -a is clean. OpenVINO capability coverage is included but skipped locally because the provider is unavailable.
With query_seqlens, total_sequence_length is only an upper bound, so a cache that grows between steps is no longer tied to past_sequence_length + kv_sequence_length. The legacy dynamic-cache equality rejected valid calls such as past rows 10, S=8, Q=3, T=13 and total_sequence_length=32. Skip it when query_seqlens is given and instead require that the P = T - Q cached tokens of a non-windowed cache are held by past_key and past_value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The forced Flash and memory-efficient assertions in test_gqa.py only hold when the requested kernel is compiled into the CUDA provider, but they were gated on the GPU architecture alone. Probe the dispatch once per kernel with the borrowed-KV model and skip the exact-dispatch assertions when the kernel is unavailable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The quantized-cache fallback re-attends a right-padded first chunk to the float RoPE'd K/V so that it matches an ordinary first prompt. The replay ran for every S > 1 call. Callers that omit query_seqlens therefore changed from reading the quantized cache to reading float K/V, and a chunk with a single valid row read float K/V while the equivalent single-token step reads the quantized cache. Carry has_query_seqlens in GroupQueryAttentionData, gate the replay on it, and skip entries whose valid end is at most one token. Add INT8 regressions for the Q=1 padded chunk and for the input-omitted first chunk. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CodeQL reports the OpenVINO import in the query_seqlens capability test as a potentially uninitialized local, because it does not know that skipTest() never returns. Move the GPU discovery into a helper that returns False when the Python runtime is missing, so the test no longer uses the module after a failed import. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
HasCudaEnvironment comes from cuda_op_test_utils.h, which this test file includes only under USE_CUDA. The BF16 branch of QuerySeqlensRightPaddedChunk_CUDA called it unguarded, so non-CUDA builds of onnxruntime_provider_test failed to compile (gcc: 'not declared in this scope'; MSVC: C3861). The test already returns early via GTEST_SKIP when no CUDA EP is available, so the guard changes only compilation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
b84d577 to
823a83b
Compare
Ti-Tai Wang (titaiwangms)
left a comment
There was a problem hiding this comment.
Full static review of 657cc52 -> 823a83b, including the stacked CPU implementation in #33505.
No concrete core correctness, memory-safety, or integration defect was established. I am withholding approval for the focused JSEP regression-coverage requirement below.
Required before approval
Missing focused JSEP rejection coverage -- onnxruntime/contrib_ops/js/bert/group_query_attention.h:28.
The constructor now rejects an existing query_seqlens input at slot 16. Please add focused JSEP tests showing that supplying the input fails with the intended error, while omitting it or supplying an empty optional slot preserves existing admission. The matching .github/instructions/jsep-deprecated.instructions.md explicitly requires focused regression coverage for accepted correctness fixes.
The native WebGPU rejection test added by #33505 is useful, but it does not exercise JSEP session construction. This is a coverage/policy gap, not an established runtime failure.
Nonblocking follow-ups
- Avoid probing availability with the regression case itself --
onnxruntime/test/python/transformers/test_gqa.py:575.has_sdpa_kernel()probesS=8, T=3, C=9, which is also the negative-diagonal boundary tested bytest_query_longer_than_borrowed_kv(). A regression that makes Flash/MEA ineligible specifically forT < Scan therefore turn the test into a skip. Probe availability with an ordinary supported control, such asS=T=8, C=9, and assert boundary-case dispatch separately. - Clarify the quantized first-chunk reference --
onnxruntime/core/graph/contrib_ops/bert_defs.cc:1510andonnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.cu:1333-1337. ForP=0, Q>1, the new-input path attends to float new K/V. Omitting input 16 while retaining a capacity-valuedtotal_sequence_lengthpreserves the legacy subsequent-chunk classification and quantized reads. Please specify whether the unpadded reference retains input 16 or uses the true total length. The added tests deliberately distinguish these paths; this is a documentation ambiguity, not a proven numerical bug. - Update the padded-length comment --
onnxruntime/contrib_ops/cuda/bert/attention_data.h:144-145.padded_seq_lensis no longer first-prompt-only: it also carriesP+Sfor padded continuations and cache-relative bounded lengths for windowed calls.
One nonblocking hardening question remains at group_query_attention_impl.cu:698: the initial signed-int P+S expression can overflow for an extreme windowed absolute length (T=INT_MAX, Q=1, S=8), before that value is overwritten by cache-relative geometry. No observable failure was established. Consider calculating it only where consumed, with widened arithmetic and clamping before narrowing.
Integration and validation scope
The review found agreement on input 16's type/placement, unsupported-provider rejection, trailing-input preservation in both fusions, and windowed-cache alias/staging admission. The absolute RoPE versus cache-relative causal-mask coordinates are consistent in the reviewed stack.
This was a five-role static review. No local build, CUDA execution, memcheck, performance/concurrency qualification, or exhaustive Flash/MEA-internal proof was performed. The observed CI snapshot was 99 successful and 1 neutral check; CI and author-reported tests are not independent local reproduction. No Major/Critical finding was overruled.
|
Ti-Tai Wang (@titaiwangms) Addressed the feedback from your review summary in 21ff2d096a:
Local validation: CUDA 13.0 build with FlashAttention enabled; 43 focused Python tests passed, 6 non-CUDA variants skipped; 6 existing query_seqlens C++ tests passed; 3 actual JSEP browser tests passed; TypeScript, lint, and whitespace checks passed. |
Ti-Tai Wang (titaiwangms)
left a comment
There was a problem hiding this comment.
Follow-up review of 823a83b -> 21ff2d0, building on the prior five-role full static review.
The blocking JSEP coverage gap is resolved: the new browser suite constructs actual sessions with CPU fallback disabled, tests present/omitted/empty input 16, asserts the JS-specific rejection error, and is wired only into JSEP builds. The production rejection guard is unchanged.
The remaining feedback is also addressed:
- The SDPA availability probe now uses S=T=8 rather than the T<S regression case.
- The schema/generated documentation and CUDA notes explicitly retain query_seqlens and the same scalar bound in the unpadded reference.
- The singleton replay threshold correctly distinguishes the legacy tight-bound first prompt from capacity-bound quantized decode; the new tests cover packed/unpacked and windowed cases.
- The length comments are updated. Absolute P+S is calculated only on the nonwindowed path, in int64_t, with capacity clamping before narrowing for explicit-length calls. The new INT_MAX windowed regression checks valid-row attention and resident cache layout.
No remaining code-review blocker was established in this follow-up. Approving the reviewed head.
Scope and validation limitations: this follow-up was direct static inspection of the complete revision delta and controlling code, not another five-role review or a local build/test run. The author's reported CUDA, C++, JSEP browser and lint results were not independently reproduced.
CI on this new head is not yet an all-green validation snapshot: the current PR check listing contains license/cla SUCCESS and Linux Android Emulator QNN CI Pipeline ACTION_REQUIRED. This approval does not waive required CI or authorize merging before required checks are satisfied.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
) ### Description <!-- Describe your changes. --> Implement the optional `query_seqlens` input (index 16) of `com.microsoft::GroupQueryAttention` in the CPU execution provider. The input carries the number of valid, non-padded rows of a right-padded query/key/value chunk per batch entry, so fixed-shape chunked prefill works on CPU with a full-length or a windowed KV cache (`sliding_window_cache=1`), with float, fp16 and int8-quantized KV, on both the MLAS flash and the unfused paths. This PR is stacked on #33503, which adds the input to the schema, the shared validation and the CUDA implementation, and makes the CPU provider reject the input until this PR lands. The input's semantics are specified there and are only summarized below. This revision supersedes the earlier one of this PR, which inferred the valid length of a chunk from `total_sequence_length` (`ResolveGQAStepLengths`). That heuristic is removed. **Stack:** the base of this PR is the branch of #33503, so "Files changed" shows only the CPU changes. Once #33503 merges, this PR is retargeted to `main` and rebased onto it. ORT's build, test and CodeQL workflows run only for pull requests that target `main` or `rel-*` (the lint workflow runs for any base), so this PR gets them after that retarget. The local results below were produced on the combined branch. #### CPU behavior For batch entry `b`: `S` is the padded `sequence_length`, `T = seqlens_k[b] + 1`, `Q = query_seqlens[b]` and `P = T - Q`. - Only the `Q` valid rows are appended to the cache, for full-length and windowed caches alike. Query row `s` sits at absolute position `P + s` for causal masking, `local_window_size` and the implicit rotary positions. The padded rows of the implicit rotary positions get position 0, which is always a valid rotary-cache index. - Every contract violation is rejected with `INVALID_ARGUMENT` (CUDA clamps device-side values instead): a shape other than `(batch_size)`, `Q` outside `[1, min(S, T)]`, `T > total_sequence_length`, a missing past, key/value that are not a full chunk of `S` rows (including the shared-KV case `kv_sequence_length == 0`), `S > 1` with `batch_size > 1`, `P` above the sequence dimension of `past_key` (a cache may grow between steps, so the past buffers can be shorter than the present buffers), `P + S > C` for a cache that is not windowed (`C` is the sequence dimension of `present_key`), `causal=0`, and missing `present_key`/`present_value` outputs. The outputs are required for every step, also for `S == 1`, because the contract of the input does not depend on the chunk length. - `S == 1` treats the input as absent (it is still validated), so a model can feed it at every step. - With the input, an explicit `position_ids` is honored for every row, also on the first chunk, as on any later chunk. Without it, a first prompt reads only `position_ids[0]`. The entries of padded rows must still be valid rotary-cache indices. - A windowed cache accepts `C >= local_window_size` and `attention_bias` together with padded chunks. CUDA is limited to `C == local_window_size` and no `attention_bias`. - `output_qk`, when requested, keeps its shape `(batch_size, num_heads, S, total_sequence_length)`. The columns `[T, total_sequence_length)` of a batch entry are zero. They used to hold uninitialized scratch memory, which already happened for ragged batches without the new input, because the kernel never writes them. - Without the input the behavior is unchanged except for the `output_qk` columns above: the helper below falls back to the previous per-batch logic, and the one changed constant (the padded-row rotary position) is unreachable then. #### Key changes - **`gqa_attention_base.h`**: the per-batch lengths of a step (total, past rows to copy, causal past, new rows to append) were open-coded at 8 sites. They now come from `ResolveBatchStepLengths`, which takes an optional per-batch past length and reproduces the previous logic when none is given. `ConcatStateChunkGQA` and its quantized variant append `valid_new_rows` instead of `kv_sequence_length`, so padded rows never overwrite valid entries or run past the capacity. The flash paths take their past length per batch entry. `WriteOutputQKHeadChunk` copies only the columns the kernel wrote and zero-fills the rest of the `output_qk` row. - **`group_query_attention.cc`**: reads input 16 and performs the checks above. `PlanWindowedKvCache` sizes eviction and the staging cache with `Q` instead of `S`, and also returns the kept past length per entry, which is passed down as `attention_past_seqlens`. The default rotary positions use `Q`. - **`group_query_attention_helper.h`**: the earlier `ResolveGQAStepLengths` is removed. The file is identical to the #33503 branch, which holds the validation shared by CPU and CUDA. - **Schema and docs**: input 16 is documented as honored by the CPU and CUDA providers (other providers must reject the node). `docs/ContribOperators.md` is regenerated and the "Right-Padded Prefill Chunks" section of `docs/contrib_ops/cpu/gqa.md` is rewritten for `query_seqlens`. Comments in the MIGraphX, OpenVINO and JS providers that said only CUDA implements the input now say CPU and CUDA. - **Tests**: - C++ (`group_query_attention_op_test.cc`): `QuerySeqlensRightPaddedChunk_CPU` and `QuerySeqlensRotaryRightPaddedChunkMatchesUnpadded_CPU` compare a padded chunk with the same call on an unpadded chunk (float and fp16, flash on and off, packed and unpacked QKV, and the appended cache rows). `WindowedCacheRightPaddedChunkMatchesUnpadded_CPU` does the same for a windowed cache over many prefill and valid lengths. Every rejection above has a negative test, including a missing `present_key`/`present_value` for `S == 1` and a growing cache whose past is longer than the bound past buffers. A WebGPU-only test checks that the WebGPU provider rejects a node with the input. It is compiled only with `USE_WEBGPU`, which my build does not enable. - Python (`TestGQAWindowedKvCacheCpu`, shared with the CUDA suite): padded chunks run through `query_seqlens` with a float and an int8 cache, flash and non-flash, `C == W` and `C == W + 8`, a capacity-valued `total_sequence_length`, `head_sink`, `position_ids`, softcap and `attention_bias`, and `S == 1` decode with the input present. `TestQuerySeqlensQkOutputCpu` checks `output_qk` for a padded chunk against the unpadded call, including the zeroed columns. #### Testing H200 host with a CUDA 13.0 Release build, so the gtest filter below also runs the CUDA tests from #33503. The Python classes below run on the CPU provider only. All results are from the head of this branch. - `onnxruntime_provider_test --gtest_filter='*GroupQueryAttention*:*GQA*'`: **149 passed, 18 skipped, 0 failed** (167 run). The skipped tests need an execution provider or hardware that this build does not have. - `test_gqa.py TestGQAWindowedKvCacheCpu`: **25 passed, 1 skipped** (the CUDA-only cuDNN fallback test). - `test_gqa.py TestQuerySeqlensQkOutputCpu` (`output_qk` of padded chunks): **8 passed**. - `test_gqa.py TestBorrowedKVCache` (cache inputs stay unchanged across the refactored copy paths): **46 passed**. - Mutation checks: four bugs were injected one at a time into a scratch copy of the kernel (non-windowed past length taken from `S` instead of `Q`, default rotary positions ignoring `Q`, windowed planning ignoring `Q`, and padded chunk handling disabled). Each is caught by both a C++ test and the Python suite. The first round showed that no C++ test covered the rotary one, which is why `QuerySeqlensRotaryRightPaddedChunkMatchesUnpadded_CPU` exists. Two more were checked for the later fixes: reverting the `output_qk` zero-fill produces 24 failures, and limiting the present-output requirement to `S > 1` fails exactly `QuerySeqlensSingleTokenWithoutPresentOutputsRejected_CPU`. - `lintrunner -m origin/main`: clean. - The CUDA results, including the two unrelated failures that also fail on a `main` build, are in #33503. Notes for reviewers: - `docs/ContribOperators.md` is refreshed the same way as in #33503, with a script that mirrors `gen_contrib_doc.py` because my local build is lite-protobuf. The full-protobuf CI docs check is authoritative. - The new WebGPU rejection test and the three comment edits in the MIGraphX, OpenVINO and JS providers are not compiled locally, because those providers are not part of my build. - Padded output rows are unspecified. A padded row that sees no key (a local window combined with heavy padding) may hold NaN. The contract allows that, but no test exercises it. - This PR gets only the lint workflow while it is stacked (see above). Once #33503 merges, I will retarget it to `main` and rebase. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> Static-shape (compiled or graph-captured) prefill uses a fixed query chunk even when only a few rows are real tokens, for example the last chunk of a prompt padded to `S = 512`. Then `sequence_length` is the padded size while `seqlens_k[b] = P + Q - 1` reflects the real length. On the CPU provider this: - rejected a subsequent step with `seqlens_k + 1 < sequence_length`, - derived the past length and the number of rows to evict from the padded length, which dropped valid cache rows, - appended all `S` rows to the cache, which could overwrite valid entries or write past the capacity when `C > local_window_size`, and - anchored the default rotary positions and the causal mask at `T - S` instead of `P`. Inferring the valid length from `total_sequence_length` cannot work in general, because existing callers pass the cache capacity there. An explicit per-entry valid length removes the ambiguity, needs no heuristic, and gives the CPU and CUDA implementations the same contract. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Resolve conflicts against upstream main in group_query_attention.cc and group_query_attention_helper.h with query_seqlens (input 16) from microsoft#33503 / microsoft#33505. - Preserve explicit CPU-only opt-in (allow_8_aligned_rotary = true) in CPU GQA. - Maintain conservative legacy 16-aligned validation by default (allow_8_aligned_rotary = false) for CUDA GQA, WebGPU GQA, and PagedAttention (CUDA & WebGPU). - Retain head_size / 2 bound to prevent integer truncation for head_size = 8.
…cept MATH - New CudaCudnnSdpaRejectedRaggedBidirectionalPromptMasksPerBatch: when the probe rejects cuDNN for a right-padded causal=0 first prompt, the kernel that runs instead must mask each batch at its valid KV length, as cuDNN does. The test runs the fallback with FlashAttention, memory-efficient attention and the unfused kernel and checks every valid output row against the per-batch mean. On the previous base the Flash fallback failed it (batch 0: 0.5078 instead of 0.2578); main's microsoft#33503 fixed Flash and MEA, and all three pass now. - CudaCudnnSdpaRejectedGraphFallsBack also accepts SdpaKernel=MATH, for builds or settings without Flash and memory-efficient attention. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
## Description Support batched right-padded GQA chunks and populated idle entries (`query_seqlens[b] = 0`) on CPU and CUDA, including single-token steps. Skip padded preprocessing and attention work while preserving physical tensor strides and the sliding-window history needed by the first valid query in each chunk. This follows #33503 and #33505, both already merged. Other execution providers continue to reject `query_seqlens`; the legacy multi-token/past-context batch restriction remains when the input is absent. ## Summary of Changes ### Length semantics and correctness - Accept `0 <= Q[b] <= min(S, T[b])` with `T[b] >= 1`. An idle entry keeps its absolute total and cache unchanged. Initially empty idle entries remain unsupported. - Honor explicit lengths at `S = 1`, rather than treating every entry as active. - Fix CPU flash dispatch for equal resident totals but different past lengths: the causal offset cannot be shared in that case. - Preserve staging/eviction behavior: eviction must not discard the preceding `W - 1` positions needed by the first token of a chunk. - Clarify that `total_sequence_length` bounds absolute totals, not windowed cache capacity. ### CPU - Bound unpack/transpose, RoPE, FP16 conversion, naive QK/softmax/SV and MLAS flash query work by the valid row count. - Keep padded physical strides for head, batch, output and bias addressing. - Skip idle attention while preserving required past-cache copies for separately allocated outputs. - Cover FP32/FP16 inputs and INT8/INT4 caches; retain default MLAS behavior when valid query counts are not supplied. ### CUDA - Guard padding before Q/K/V loads, QK-Norm, RoPE, quantization and cache append. - Skip idle aliased-cache staging seed/copy-back and unused ungroup/dequantization rows. - Bound FlashAttention/MEA query tiles and output stores by device-side valid lengths. - Skip padded unfused softmax/output rows and use masked V scratch to avoid `0 * NaN` contamination from unused cache rows. Include that scratch in runtime and bounded workspace calculations. - Bypass XQA, fast Flash decode and cuDNN SDPA with explicit query lengths because those paths do not represent idle query entries. No host synchronization is added to inspect query lengths. **Remaining work:** unfused CUDA cuBLAS QK/SV GEMMs still use dense physical query dimensions. Partially filled fused tiles retain tile-granular arithmetic. Scratch allocations and upstream Q/K/V projection nodes are not made ragged by this change. ### Regression coverage and documentation - Replay prompts `[513, 1025]` with `S = W = 512`, CPU cache capacity 1023 and CUDA capacity 512: | Chunk | Valid queries | Absolute totals | |---|---|---| | 1 | `[512, 512]` | `[512, 512]` | | 2 | `[1, 512]` | `[513, 1024]` | | 3 | `[0, 1]` | `[513, 1025]` | - Compare valid outputs and resident caches with independent unpadded single-entry full-cache calls. Include all-idle chunks, idle decode, resumed decode, mixed first/continuation entries, additional eviction, and equal-total/different-past cases. - Poison padded Q/K/V and unused floating-cache rows with NaNs. Prebind sentinel outputs and verify padded rows are not written. The sentinel check is an optimization regression, not a new public padding-output guarantee. - Exercise packed/unpacked inputs, RoPE, FP16/BF16 CUDA, FP32/FP16 CPU, and INT8/INT4 caches. - Assert native FlashAttention/MEA/math dispatch without CPU fallback, exercise MEA large-head accumulation, and replay CUDA graphs while changing device query lengths. - Update operator schema, generated operator documentation and CPU/CUDA guides. ## Testing Validated locally on H200 with CUDA 13 using the existing incremental build and feature-source overlays: - Rebuilt Python runtime, CPU/MLAS, CUDA provider and provider-test targets, including dependent FlashAttention/MEA translation units. Verified compiled feature-source and staged-provider parity. - GQA C++ suite: **123 passed, 14 skipped** (137 tests). - Focused MEA/unfused workspace GTests: **23 passed**. Both changed workspace test files compile; additional standalone layout/bounds checks passed. The main build has CUDA EP internal tests disabled, so the complete estimator/internal-test suite was not run. - Targeted Python query-length/windowed suites: **112 passed, 2 skipped**, plus **148 passing subtests**. - Final new optimization suite rerun: **36 passed**, plus **48 passing subtests**, including all three CUDA-graph backends. - Independent NumPy-oracle replay: **96 CPU calls and 156 CUDA calls passed**; CUDA dispatch verified for FlashAttention, MEA, math and automatic selection. - All configured lintrunner checks and `git diff --check` passed. The CPU output-sentinel test was also run before optimization and reproduced padded output writes for both flash settings and both cache-alias modes. ## Checklist - [x] CPU and CUDA changes included - [x] Regression tests added/updated - [x] Existing no-input behavior and other-EP rejection retained - [x] Documentation and backend limitations updated --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…chunks Support (openvinotoolkit#39495) ## Description Implements the optional `query_seqlens` input (index 16) of `com.microsoft.GroupQueryAttention`, added by ONNX Runtime in microsoft/onnxruntime#33505 (CPU) on top of microsoft/onnxruntime#33503 (schema, CUDA). The input gives the number of valid rows of a right-padded query chunk, so static-shape chunked prefill can pad its last chunk to the fixed chunk length. Before this change the ONNX frontend rejected any GroupQueryAttention node with 17 inputs. With `S` the padded chunk length, `T = seqlens_k + 1` and `Q = query_seqlens`, the past length becomes `P = T - Q` instead of `T - S`: query row `s` sits at absolute position `P + s` for the causal mask, the sliding window and the implicit rotary positions, and only the `Q` valid rows are new tokens. Following microsoft/onnxruntime#33832, batched chunks are supported, the input is honored at `sequence_length == 1`, and `Q = 0` marks an idle entry whose cache is unchanged. Models without the input are unaffected. ONNX Runtime references: - **Spec:** https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.GroupQueryAttention - **CPU kernel:** https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/contrib_ops/cpu/bert/group_query_attention.cc - **CPU attention / cache write:** https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/contrib_ops/cpu/bert/gqa_attention_base.h - **Input checks:** https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/contrib_ops/cpu/bert/group_query_attention_helper.h ## Approach - **Op:** `ov::op::internal::GroupQueryAttention` gets a `QUERY_SEQLENS` input with `has_query_seqlens()`. Validation matches ONNX Runtime: rank 1 with `batch_size` elements, past required (a typed-empty rank-4 Constant counts as past layout, matching an empty Parameter), `causal=1`, no shared KV, key/value length equal to the query's. - **ONNX FE:** accepts 17 inputs and forwards `query_seqlens` only when it is wired, so existing models keep a 16-input op and their IR is unchanged. - **Decomposition:** when `has_query_seqlens()`, `P = T - Q` (per batch entry) drives the mask, the KV write offset and the implicit rotary positions. The KV write keeps its static S-row shape at `[P, P + S)`: the cache stays left-aligned with every valid row in `[0, T)`, and the padded tail lands at or beyond `T`, where no valid query reads it and the next step overwrites it (ONNX Runtime requires `P + S <= capacity`). Writing only the `Q` valid rows would make the update shape data-dependent, which static-shape devices cannot compile. The public present buffer is separately sized to ONNX Runtime's `max(past_rows, total_sequence_length)` capacity contract (`group_query_attention_helper.h`), since `total_sequence_length` can pre-allocate headroom past this step's write; attention itself still runs over the tight `[P, P + S)` buffer. The windowed-cache staging path writes back only the valid rows, so eviction follows `T`. An idle entry (`Q = 0`, `P = T`) writes only at or beyond `T`, so its valid cache is unchanged; an idle windowed decode takes the staging path for the same reason. Padded K/V rows are zeroed with one `Select` each, since masking alone lets NaN filler reach valid rows through the scores and `0 * V` (ONNX Runtime CPU/CUDA never read them); single-token steps skip it, as their padded entries are idle. Padded rotary rows are capped at `seqlens_k` with one `Minimum`, which keeps them in range; their outputs are unspecified, as in ONNX Runtime. Graphs without the input lower exactly as before. - **GPU:** `StatelessKV` gets `P + S` as its present length, so the S rows land at `P` and SDPA's lower-right causal alignment gives row `s` the keys `<= P + s`, with no extra mask or copy. A windowed cache with a padded chunk uses the generic staging path, because `StatelessKV` evicts by its present length; decode keeps the `StatelessKV` sliding-window path. ## Scope In scope: CPU (common decomposition) and GPU for full-length, static-capacity and windowed caches, implicit and explicit rotary positions, float and int8-quantized KV, single and batched graphs. Out of scope: NPU compilers, which do not handle the input yet; `StatelessKV` honoring `total_sequence_length` headroom beyond `P + S` on GPU, and keeping a padded windowed chunk on the GPU `StatelessKV` sliding-window path (both planned as a follow-up). ## Validation - type_prop tests for the new input, batched and single-token acceptance, and every rejection. - ONNX FE tests with expected values from the ONNX Runtime CPU kernel: static cache with rotary, growing cache (batched path), windowed cache, single-token step with the input wired, explicit `position_ids`, int8 quantized cache, plus the microsoft/onnxruntime#33832 cases: batched chunk with an idle entry and NaN-poisoned padding, equal totals with different pasts, idle single-token step, windowed idle and active single-token steps. Padded output rows and cache rows at or beyond the valid length are unspecified, so the models compare only the valid region. The GPU run of the static-capacity cases is skipped because a static-capacity present output consumed by a non-Result op fails at runtime on GPU, which also happens without this change. - A growing-cache regression evaluates the unsliced present output directly against `total_sequence_length` (not `P + S`), checking both the resulting shape and that the write window and unwritten past prefix land correctly, matching the ONNX Runtime CPU/CUDA capacity contract (`group_query_attention_helper.h`). - A padded prefill chunk with 32 heads, 8 KV heads, head size 128, `S = 512`, `Q = 300` and `P = 1000` matches the ONNX Runtime CPU kernel on CPU (output max abs diff 1.2e-6, present KV bit-exact) for a static and a windowed cache, and its latency with the input matches the same chunk without it. ### FYI - microsoft/onnxruntime#33832 (merged after this PR was opened) extended the `query_seqlens` contract on CPU/CUDA: batched chunks, `Q = 0` idle entries and honoring the input at `sequence_length == 1`. This PR follows that contract; expected values come from the ONNX Runtime CPU kernel at that commit. ### Tickets: - CVS-199056 ### AI Assistance: - AI assistance used: yes - AI helped analyze, implement, test the optimal changes
Updated [Microsoft.AspNetCore.Mvc.Testing](https://github.com/dotnet/dotnet) from 10.0.14 to 10.0.15. <details> <summary>Release notes</summary> _Sourced from [Microsoft.AspNetCore.Mvc.Testing's releases](https://github.com/dotnet/dotnet/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/dotnet/commits). </details> Updated [Microsoft.Data.Sqlite](https://github.com/dotnet/dotnet) from 10.0.14 to 10.0.15. <details> <summary>Release notes</summary> _Sourced from [Microsoft.Data.Sqlite's releases](https://github.com/dotnet/dotnet/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/dotnet/commits). </details> Updated [Microsoft.ML.OnnxRuntime](https://github.com/Microsoft/onnxruntime) from 1.31.1 to 1.32.0. <details> <summary>Release notes</summary> _Sourced from [Microsoft.ML.OnnxRuntime's releases](https://github.com/Microsoft/onnxruntime/releases)._ ## 1.32.0 ONNX Runtime 1.32.0 reintegrates ONNX 1.23.2 with opset 28 support, introduces CPU/GPU hybrid MoE offloading and shared-layout CPU QMoE kernels, expands device-memory, weightless-compilation, and Python model-package APIs, dramatically accelerates session initialization on large graphs, and strengthens runtime and optimizer reliability. These notes cover changes since ONNX Runtime 1.31.1. CUDA and WebGPU kernel updates are summarized here; detailed provider notes are covered by their separate plugin EP releases. ## Highlights - Reintegrated **ONNX 1.23.2** with **opset 28** operator support (`SpaceToDepth`, `Mod`, signed `BitShift`, and `BFloat16` extensions) and updated **DLPack to v1.3** across all implemented ORT numeric and boolean tensor types ([#33134](microsoft/onnxruntime#33134), [#32362](microsoft/onnxruntime#32362), [#33848](microsoft/onnxruntime#33848)). - Added a session-scoped **CPU/GPU hybrid MoE offload** planner and execution backend for quantized `QMoE` (NVFP4, INT4, INT3, and INT2) and block-packed `MoEPacked` models, backed by shared-layout AVX-512/AVX2 CPU `QMoE` kernels and memory-mapped expert storage ([#33450](microsoft/onnxruntime#33450), [#33451](microsoft/onnxruntime#33451), [#33452](microsoft/onnxruntime#33452), [#33973](microsoft/onnxruntime#33973)). - Expanded core APIs with `OrtApi::EpDevice_GetMemoryCapacity`, explicit multi-mode weightless compilation (`ModelCompilationOptions_SetWeightlessMode` and `ep.enable_weightless_mode`), Python bindings for the Model Package APIs, and zero-copy CPU buffer borrowing in `AddExternalInitializers` ([#33447](microsoft/onnxruntime#33447), [#32899](microsoft/onnxruntime#32899), [#33640](microsoft/onnxruntime#33640), [#33877](microsoft/onnxruntime#33877)). - Eliminated superlinear bottlenecks in allocation planning, constant sharing, graph I/O mapping, and topological sorting—reducing session initialization on 100k-node constant-heavy graphs from minutes to seconds—and added pipelined pinned-memory staging for external GPU weight loading ([#33407](microsoft/onnxruntime#33407), [#33939](microsoft/onnxruntime#33939), [#34009](microsoft/onnxruntime#34009), [#33839](microsoft/onnxruntime#33839)). - Expanded shared generative AI and quantized contrib operators, including Kimi Delta Attention (`GatedDeltaNet` per-key-dimension decay), right-padded chunked prefill in `GroupQueryAttention`, native GGUF/block-packed operators (`GatherPacked`, `MatMulPacked`, `MoEPacked`), and sparse-attention index sharing ([#33817](microsoft/onnxruntime#33817), [#33503](microsoft/onnxruntime#33503), [#33953](microsoft/onnxruntime#33953), [#33224](microsoft/onnxruntime#33224)). ## Announcements & Compatibility - **CUDA Plugin EP v0.4.0** and **WebGPU Plugin EP v0.6.0** are matched with ONNX Runtime 1.32.0 ([#33214](microsoft/onnxruntime#33214)). For **contrib-op compatibility**, core and the plugin must use the same contributed-operator schemas; building both from the **same ONNX Runtime revision** is recommended. Schema mismatches can cause incorrect execution or crashes and may not be detected during plugin registration. - **ACL EP removed:** Following its deprecation in 1.31.0, the Arm Compute Library (`ACLExecutionProvider`) execution provider, its build options, and its standalone C registration API have been removed. Python's `get_all_providers()` no longer lists `ACLExecutionProvider`; applications should remove it from explicit provider lists ([#33851](microsoft/onnxruntime#33851)). - **Legacy provider-bridge `NvTensorRTRTXExecutionProvider` removed:** In-tree provider-bridge `NvTensorRTRTXExecutionProvider` sources have been removed in favor of the standalone NVIDIA TensorRT RTX plugin EP registered via `OrtApi::RegisterExecutionProviderLibrary`. `NvTensorRtRtxProviderOptions` is retained as a deprecated declaration for source compatibility, and legacy `AppendExecutionProvider` calls now report a deprecation error directing callers to the plugin EP ([#32276](microsoft/onnxruntime#32276)). - **ONNX 1.23.2 integration:** ONNX has been upgraded to **1.23.2**, raising supported opset ceilings to **28** and restoring `ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT6E2M3` and `ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT6E3M2` public element-type mappings and `Cast` conversions ([#33134](microsoft/onnxruntime#33134)). - **DLPack v1.3 boolean contract change:** DLPack has been upgraded to **v1.3** with native `kDLBool` metadata and bidirectional support for all implemented ORT numeric and boolean types, including all five `float8` formats, packed `float4`, `int4`/`uint4`, and `int2`/`uint2` (`float6` remains unsupported in DLPack). The low-level `is_bool_tensor` override was removed, and `uint8` DLPack metadata now always imports as `uint8` ([#33848](microsoft/onnxruntime#33848)). - **Weightless compilation API migration:** `OrtCompileApi::ModelCompilationOptions_SetWeightlessEnabled` and the `ep.enable_weightless` / `ep.enable_weightless_ep_context_nodes` session options are deprecated in favor of `ModelCompilationOptions_SetWeightlessMode` and `ep.enable_weightless_mode` (`"0"` = `NONE`, `"1"` = `EXTERNAL_ONLY`, `"2"` = `ALL`). EPs can now advertise multi-mode capability via `OrtWeightlessSupport_ALL_OR_EXTERNAL_ONLY` and `weightless_supported_modes` ([#32899](microsoft/onnxruntime#32899)). - **Training CI retirement:** Training build and test lanes were retired from active GitHub Actions CI workflows while retaining inference build coverage ([#33836](microsoft/onnxruntime#33836)). - This is the last release for [CocoaPods](https://cocoapods.org/), and we will switch to [Swift Package Manager](https://docs.swift.org/latest/documentation/packagemanagerdocs/). - We will use combo onnxruntime-gpu python package to reduce storage size from next release. You can test it [here](https://aiinfra.visualstudio.com/PublicPackages/_artifacts/feed/ORT-Nightly/PyPI/onnxruntime-gpu/overview) ## New Features ### Core APIs & Runtime - Added `OrtApi::EpDevice_GetMemoryCapacity` (C++ `EpDevice::GetMemoryCapacity()`) and `OrtEpFactory::GetDeviceMemoryCapacity` to query device-global total memory and estimated currently available memory (`DEFAULT` or `HOST_ACCESSIBLE`), with built-in and plugin CUDA EP support ([#33447](microsoft/onnxruntime#33447)). - Expanded the app–EP weightless contract so EPs advertise all supported weightless modes (`weightless_supported_modes`), applications request an explicit mode (`ModelCompilationOptions_SetWeightlessMode` / `ep.enable_weightless_mode`), and compiled EPContext models record `weightless_mode` and `external_dependencies` (`source_model`, `external_weights`, `ep_context_binary`) in model metadata ([#32899](microsoft/onnxruntime#32899)). - Extended `session.use_external_initializer_file_buffers_directly="1"` to `AddExternalInitializers` for zero-copy borrowing of naturally aligned CPU buffers larger than 127 bytes on little-endian hosts, and documented the read-only guarantee for external initializers added via `OrtModelEditorApi::AddInitializerToGraph` with `data_is_external=true` ([#33877](microsoft/onnxruntime#33877), [#33717](microsoft/onnxruntime#33717)). - Added lock-free multi-worker pinned-memory staging (`session.external_data_loader.*`) to accelerate external initializer loading into GPU memory across built-in and plugin CUDA EPs ([#33839](microsoft/onnxruntime#33839)). - Added a session-scoped MoE/QMoE CPU/GPU offload planner and memory-budget ledger (`session.moe.offload.*`), generic `session.kernel_dispatch_policy` (`auto`, `latency`, `memory`, `safe`) configuration plumbing, Level-1 workspace/prepack memory accounting fallback for nodes absent from memory-profile CSVs, and internal capability-planning protocol types ([#33451](microsoft/onnxruntime#33451), [#33042](microsoft/onnxruntime#33042), [#33311](microsoft/onnxruntime#33311), [#33841](microsoft/onnxruntime#33841)). - Enabled cross-thread reuse of idle device streams when graph capture is disabled and providers register device-selection callbacks, and enabled compile-session profiling (`<profile_file>_compile`) in `onnxruntime_perf_test` when `-p` is used with `--compile_ep_context` ([#33053](microsoft/onnxruntime#33053), [#33694](microsoft/onnxruntime#33694)). - Made `onnxruntime_DISABLE_EXCEPTIONS` (`--disable_exceptions`) usable without `onnxruntime_MINIMAL_BUILD` and added the `onnxruntime_DISABLE_STREAM=ON` CMake option to disable device-stream support in non-minimal builds ([#33120](microsoft/onnxruntime#33120), [#33482](microsoft/onnxruntime#33482)). ### ONNX Opset 28 & Shared Contrib Operators These updates affect core ONNX and contributed operator schemas and cross-provider behavior, not only the separately released GPU plugins. - Added ONNX opset 28 operator support: native `SpaceToDepth` (`DCR` and `CRD`) on CPU and CUDA with version-split registrations across DML, JS, WebGPU, and QNN; opset-28 floating floor-modulus `Mod` on CPU, CUDA, and DML; opset-28 `BFloat16` support for `Compress`, `OneHot`, `ReverseSequence`, `Unique`, `Celu`, and `Einsum` on CPU (plus `Compress`, `OneHot`, and `ReverseSequence` on CUDA); and `BFloat16` `Pad` (opsets 21–25) on CPU and CUDA ([#32362](microsoft/onnxruntime#32362), [#32369](microsoft/onnxruntime#32369), [#32378](microsoft/onnxruntime#32378), [#34062](microsoft/onnxruntime#34062)). - Extended `GatedDeltaNet` with Kimi Delta Attention (KDA) per-key-dimension decay across CPU, CUDA, and WebGPU, and extended `GatedDeltaNet` and `CausalConvWithState` state/gate handling for multi-token speculative decoding ([#33817](microsoft/onnxruntime#33817), [#33471](microsoft/onnxruntime#33471)). - Added an optional `query_seqlens` input to `GroupQueryAttention` to skip right-padded prefill tokens and idle batch entries (`query_seqlens[b] = 0`) on CPU and CUDA, and added `q_norm_epsilon` / `k_norm_epsilon` attributes to preserve distinct Q and K normalization epsilons during GQA pre-norm fusion ([#33503](microsoft/onnxruntime#33503), [#33505](microsoft/onnxruntime#33505), [#33832](microsoft/onnxruntime#33832), [#33363](microsoft/onnxruntime#33363)). - Defined the INT3 `QMoE` v1 packed-code contract, added opt-in post-SiLU clipping (`swiglu_limit_after_activation`) and tanh-`GEGLU` (`activation_type="geglu"`) support to MoE/QMoE schemas, and added `GatherPacked` (CPU/CUDA), `MatMulPacked` (CUDA, including native Bolt `global_scale`), and `MoEPacked` (CUDA) to consume native GGUF/block-packed quantized weights directly ([#33394](microsoft/onnxruntime#33394), [#33954](microsoft/onnxruntime#33954), [#33633](microsoft/onnxruntime#33633), [#33953](microsoft/onnxruntime#33953), [#33962](microsoft/onnxruntime#33962)). - Added `PackedSparseAttentionIndexerMerge` for multi-token prediction index sharing and optional `state_status` / mid-state outputs on `PackedSparseAttentionIndexer` across CUDA and WebGPU; extended `GatedAdd` with an optional projected `gate_weight` across CPU, CUDA, and WebGPU; and supported empty unpacked weights in CPU and WebGPU `MatMulNBits` ([#33224](microsoft/onnxruntime#33224), [#33383](microsoft/onnxruntime#33383), [#33472](microsoft/onnxruntime#33472), [#33470](microsoft/onnxruntime#33470), [#33559](microsoft/onnxruntime#33559)). - Registered core contrib schemas for provider-targeted LLM and speculative-decoding operators, including `SwiGLU`, `RMSNormRotary`, `HyperConnectionLowRankMix`, `RouterGateUpProj`, `SpeculativePrefixCommit`, `GatedDeltaNetStateReplay`, `ConvStateReplay`, and `MatMulNBitsQLoRA` ([#32126](microsoft/onnxruntime#32126), [#33469](microsoft/onnxruntime#33469), [#33384](microsoft/onnxruntime#33384), [#33650](microsoft/onnxruntime#33650), [#33474](microsoft/onnxruntime#33474), [#33213](microsoft/onnxruntime#33213), [#33493](microsoft/onnxruntime#33493), [#33370](microsoft/onnxruntime#33370)). ### Plugin Execution Provider Infrastructure - Fixed an `OrtMemoryInfo` ABI mismatch across the ORT/plugin EP boundary by converting `OrtMemoryInfo` instances exclusively through the C API ([#33571](microsoft/onnxruntime#33571)). - Zero-initialized `OrtEpFactory` structs in provider-bridge EP factories so unimplemented optional callbacks are null, and prevented double DLL initialization and handle leaks when probing and registering plugin EP libraries ([#33117](microsoft/onnxruntime#33117), [#33701](microsoft/onnxruntime#33701)). - Hardened portable model-package EP recreation, custom-domain preservation, UTF-8 path handling, and `shared_assets` path confinement and symlink validation ([#32790](microsoft/onnxruntime#32790), [#33826](microsoft/onnxruntime#33826)). ... (truncated) Commits viewable in [compare view](microsoft/onnxruntime@v1.31.1...v1.32.0). </details> Updated [Microsoft.ML.OnnxRuntime.Managed](https://github.com/microsoft/onnxruntime) from 1.31.1 to 1.32.0. <details> <summary>Release notes</summary> _Sourced from [Microsoft.ML.OnnxRuntime.Managed's releases](https://github.com/microsoft/onnxruntime/releases)._ ## 1.32.0 ONNX Runtime 1.32.0 reintegrates ONNX 1.23.2 with opset 28 support, introduces CPU/GPU hybrid MoE offloading and shared-layout CPU QMoE kernels, expands device-memory, weightless-compilation, and Python model-package APIs, dramatically accelerates session initialization on large graphs, and strengthens runtime and optimizer reliability. These notes cover changes since ONNX Runtime 1.31.1. CUDA and WebGPU kernel updates are summarized here; detailed provider notes are covered by their separate plugin EP releases. ## Highlights - Reintegrated **ONNX 1.23.2** with **opset 28** operator support (`SpaceToDepth`, `Mod`, signed `BitShift`, and `BFloat16` extensions) and updated **DLPack to v1.3** across all implemented ORT numeric and boolean tensor types ([#33134](microsoft/onnxruntime#33134), [#32362](microsoft/onnxruntime#32362), [#33848](microsoft/onnxruntime#33848)). - Added a session-scoped **CPU/GPU hybrid MoE offload** planner and execution backend for quantized `QMoE` (NVFP4, INT4, INT3, and INT2) and block-packed `MoEPacked` models, backed by shared-layout AVX-512/AVX2 CPU `QMoE` kernels and memory-mapped expert storage ([#33450](microsoft/onnxruntime#33450), [#33451](microsoft/onnxruntime#33451), [#33452](microsoft/onnxruntime#33452), [#33973](microsoft/onnxruntime#33973)). - Expanded core APIs with `OrtApi::EpDevice_GetMemoryCapacity`, explicit multi-mode weightless compilation (`ModelCompilationOptions_SetWeightlessMode` and `ep.enable_weightless_mode`), Python bindings for the Model Package APIs, and zero-copy CPU buffer borrowing in `AddExternalInitializers` ([#33447](microsoft/onnxruntime#33447), [#32899](microsoft/onnxruntime#32899), [#33640](microsoft/onnxruntime#33640), [#33877](microsoft/onnxruntime#33877)). - Eliminated superlinear bottlenecks in allocation planning, constant sharing, graph I/O mapping, and topological sorting—reducing session initialization on 100k-node constant-heavy graphs from minutes to seconds—and added pipelined pinned-memory staging for external GPU weight loading ([#33407](microsoft/onnxruntime#33407), [#33939](microsoft/onnxruntime#33939), [#34009](microsoft/onnxruntime#34009), [#33839](microsoft/onnxruntime#33839)). - Expanded shared generative AI and quantized contrib operators, including Kimi Delta Attention (`GatedDeltaNet` per-key-dimension decay), right-padded chunked prefill in `GroupQueryAttention`, native GGUF/block-packed operators (`GatherPacked`, `MatMulPacked`, `MoEPacked`), and sparse-attention index sharing ([#33817](microsoft/onnxruntime#33817), [#33503](microsoft/onnxruntime#33503), [#33953](microsoft/onnxruntime#33953), [#33224](microsoft/onnxruntime#33224)). ## Announcements & Compatibility - **CUDA Plugin EP v0.4.0** and **WebGPU Plugin EP v0.6.0** are matched with ONNX Runtime 1.32.0 ([#33214](microsoft/onnxruntime#33214)). For **contrib-op compatibility**, core and the plugin must use the same contributed-operator schemas; building both from the **same ONNX Runtime revision** is recommended. Schema mismatches can cause incorrect execution or crashes and may not be detected during plugin registration. - **ACL EP removed:** Following its deprecation in 1.31.0, the Arm Compute Library (`ACLExecutionProvider`) execution provider, its build options, and its standalone C registration API have been removed. Python's `get_all_providers()` no longer lists `ACLExecutionProvider`; applications should remove it from explicit provider lists ([#33851](microsoft/onnxruntime#33851)). - **Legacy provider-bridge `NvTensorRTRTXExecutionProvider` removed:** In-tree provider-bridge `NvTensorRTRTXExecutionProvider` sources have been removed in favor of the standalone NVIDIA TensorRT RTX plugin EP registered via `OrtApi::RegisterExecutionProviderLibrary`. `NvTensorRtRtxProviderOptions` is retained as a deprecated declaration for source compatibility, and legacy `AppendExecutionProvider` calls now report a deprecation error directing callers to the plugin EP ([#32276](microsoft/onnxruntime#32276)). - **ONNX 1.23.2 integration:** ONNX has been upgraded to **1.23.2**, raising supported opset ceilings to **28** and restoring `ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT6E2M3` and `ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT6E3M2` public element-type mappings and `Cast` conversions ([#33134](microsoft/onnxruntime#33134)). - **DLPack v1.3 boolean contract change:** DLPack has been upgraded to **v1.3** with native `kDLBool` metadata and bidirectional support for all implemented ORT numeric and boolean types, including all five `float8` formats, packed `float4`, `int4`/`uint4`, and `int2`/`uint2` (`float6` remains unsupported in DLPack). The low-level `is_bool_tensor` override was removed, and `uint8` DLPack metadata now always imports as `uint8` ([#33848](microsoft/onnxruntime#33848)). - **Weightless compilation API migration:** `OrtCompileApi::ModelCompilationOptions_SetWeightlessEnabled` and the `ep.enable_weightless` / `ep.enable_weightless_ep_context_nodes` session options are deprecated in favor of `ModelCompilationOptions_SetWeightlessMode` and `ep.enable_weightless_mode` (`"0"` = `NONE`, `"1"` = `EXTERNAL_ONLY`, `"2"` = `ALL`). EPs can now advertise multi-mode capability via `OrtWeightlessSupport_ALL_OR_EXTERNAL_ONLY` and `weightless_supported_modes` ([#32899](microsoft/onnxruntime#32899)). - **Training CI retirement:** Training build and test lanes were retired from active GitHub Actions CI workflows while retaining inference build coverage ([#33836](microsoft/onnxruntime#33836)). - This is the last release for [CocoaPods](https://cocoapods.org/), and we will switch to [Swift Package Manager](https://docs.swift.org/latest/documentation/packagemanagerdocs/). - We will use combo onnxruntime-gpu python package to reduce storage size from next release. You can test it [here](https://aiinfra.visualstudio.com/PublicPackages/_artifacts/feed/ORT-Nightly/PyPI/onnxruntime-gpu/overview) ## New Features ### Core APIs & Runtime - Added `OrtApi::EpDevice_GetMemoryCapacity` (C++ `EpDevice::GetMemoryCapacity()`) and `OrtEpFactory::GetDeviceMemoryCapacity` to query device-global total memory and estimated currently available memory (`DEFAULT` or `HOST_ACCESSIBLE`), with built-in and plugin CUDA EP support ([#33447](microsoft/onnxruntime#33447)). - Expanded the app–EP weightless contract so EPs advertise all supported weightless modes (`weightless_supported_modes`), applications request an explicit mode (`ModelCompilationOptions_SetWeightlessMode` / `ep.enable_weightless_mode`), and compiled EPContext models record `weightless_mode` and `external_dependencies` (`source_model`, `external_weights`, `ep_context_binary`) in model metadata ([#32899](microsoft/onnxruntime#32899)). - Extended `session.use_external_initializer_file_buffers_directly="1"` to `AddExternalInitializers` for zero-copy borrowing of naturally aligned CPU buffers larger than 127 bytes on little-endian hosts, and documented the read-only guarantee for external initializers added via `OrtModelEditorApi::AddInitializerToGraph` with `data_is_external=true` ([#33877](microsoft/onnxruntime#33877), [#33717](microsoft/onnxruntime#33717)). - Added lock-free multi-worker pinned-memory staging (`session.external_data_loader.*`) to accelerate external initializer loading into GPU memory across built-in and plugin CUDA EPs ([#33839](microsoft/onnxruntime#33839)). - Added a session-scoped MoE/QMoE CPU/GPU offload planner and memory-budget ledger (`session.moe.offload.*`), generic `session.kernel_dispatch_policy` (`auto`, `latency`, `memory`, `safe`) configuration plumbing, Level-1 workspace/prepack memory accounting fallback for nodes absent from memory-profile CSVs, and internal capability-planning protocol types ([#33451](microsoft/onnxruntime#33451), [#33042](microsoft/onnxruntime#33042), [#33311](microsoft/onnxruntime#33311), [#33841](microsoft/onnxruntime#33841)). - Enabled cross-thread reuse of idle device streams when graph capture is disabled and providers register device-selection callbacks, and enabled compile-session profiling (`<profile_file>_compile`) in `onnxruntime_perf_test` when `-p` is used with `--compile_ep_context` ([#33053](microsoft/onnxruntime#33053), [#33694](microsoft/onnxruntime#33694)). - Made `onnxruntime_DISABLE_EXCEPTIONS` (`--disable_exceptions`) usable without `onnxruntime_MINIMAL_BUILD` and added the `onnxruntime_DISABLE_STREAM=ON` CMake option to disable device-stream support in non-minimal builds ([#33120](microsoft/onnxruntime#33120), [#33482](microsoft/onnxruntime#33482)). ### ONNX Opset 28 & Shared Contrib Operators These updates affect core ONNX and contributed operator schemas and cross-provider behavior, not only the separately released GPU plugins. - Added ONNX opset 28 operator support: native `SpaceToDepth` (`DCR` and `CRD`) on CPU and CUDA with version-split registrations across DML, JS, WebGPU, and QNN; opset-28 floating floor-modulus `Mod` on CPU, CUDA, and DML; opset-28 `BFloat16` support for `Compress`, `OneHot`, `ReverseSequence`, `Unique`, `Celu`, and `Einsum` on CPU (plus `Compress`, `OneHot`, and `ReverseSequence` on CUDA); and `BFloat16` `Pad` (opsets 21–25) on CPU and CUDA ([#32362](microsoft/onnxruntime#32362), [#32369](microsoft/onnxruntime#32369), [#32378](microsoft/onnxruntime#32378), [#34062](microsoft/onnxruntime#34062)). - Extended `GatedDeltaNet` with Kimi Delta Attention (KDA) per-key-dimension decay across CPU, CUDA, and WebGPU, and extended `GatedDeltaNet` and `CausalConvWithState` state/gate handling for multi-token speculative decoding ([#33817](microsoft/onnxruntime#33817), [#33471](microsoft/onnxruntime#33471)). - Added an optional `query_seqlens` input to `GroupQueryAttention` to skip right-padded prefill tokens and idle batch entries (`query_seqlens[b] = 0`) on CPU and CUDA, and added `q_norm_epsilon` / `k_norm_epsilon` attributes to preserve distinct Q and K normalization epsilons during GQA pre-norm fusion ([#33503](microsoft/onnxruntime#33503), [#33505](microsoft/onnxruntime#33505), [#33832](microsoft/onnxruntime#33832), [#33363](microsoft/onnxruntime#33363)). - Defined the INT3 `QMoE` v1 packed-code contract, added opt-in post-SiLU clipping (`swiglu_limit_after_activation`) and tanh-`GEGLU` (`activation_type="geglu"`) support to MoE/QMoE schemas, and added `GatherPacked` (CPU/CUDA), `MatMulPacked` (CUDA, including native Bolt `global_scale`), and `MoEPacked` (CUDA) to consume native GGUF/block-packed quantized weights directly ([#33394](microsoft/onnxruntime#33394), [#33954](microsoft/onnxruntime#33954), [#33633](microsoft/onnxruntime#33633), [#33953](microsoft/onnxruntime#33953), [#33962](microsoft/onnxruntime#33962)). - Added `PackedSparseAttentionIndexerMerge` for multi-token prediction index sharing and optional `state_status` / mid-state outputs on `PackedSparseAttentionIndexer` across CUDA and WebGPU; extended `GatedAdd` with an optional projected `gate_weight` across CPU, CUDA, and WebGPU; and supported empty unpacked weights in CPU and WebGPU `MatMulNBits` ([#33224](microsoft/onnxruntime#33224), [#33383](microsoft/onnxruntime#33383), [#33472](microsoft/onnxruntime#33472), [#33470](microsoft/onnxruntime#33470), [#33559](microsoft/onnxruntime#33559)). - Registered core contrib schemas for provider-targeted LLM and speculative-decoding operators, including `SwiGLU`, `RMSNormRotary`, `HyperConnectionLowRankMix`, `RouterGateUpProj`, `SpeculativePrefixCommit`, `GatedDeltaNetStateReplay`, `ConvStateReplay`, and `MatMulNBitsQLoRA` ([#32126](microsoft/onnxruntime#32126), [#33469](microsoft/onnxruntime#33469), [#33384](microsoft/onnxruntime#33384), [#33650](microsoft/onnxruntime#33650), [#33474](microsoft/onnxruntime#33474), [#33213](microsoft/onnxruntime#33213), [#33493](microsoft/onnxruntime#33493), [#33370](microsoft/onnxruntime#33370)). ### Plugin Execution Provider Infrastructure - Fixed an `OrtMemoryInfo` ABI mismatch across the ORT/plugin EP boundary by converting `OrtMemoryInfo` instances exclusively through the C API ([#33571](microsoft/onnxruntime#33571)). - Zero-initialized `OrtEpFactory` structs in provider-bridge EP factories so unimplemented optional callbacks are null, and prevented double DLL initialization and handle leaks when probing and registering plugin EP libraries ([#33117](microsoft/onnxruntime#33117), [#33701](microsoft/onnxruntime#33701)). - Hardened portable model-package EP recreation, custom-domain preservation, UTF-8 path handling, and `shared_assets` path confinement and symlink validation ([#32790](microsoft/onnxruntime#32790), [#33826](microsoft/onnxruntime#33826)). ... (truncated) Commits viewable in [compare view](microsoft/onnxruntime@v1.31.1...v1.32.0). </details> Updated [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 18.11.0 to 18.12.0. <details> <summary>Release notes</summary> _Sourced from [Microsoft.NET.Test.Sdk's releases](https://github.com/microsoft/vstest/releases)._ ## 18.12.0 ## Security fix This release includes the fix for CVE-2026-105544, an elevation of privilege vulnerability in the VSTest artifact post-processor. The post-processor could consume a forged `executionComplete.json` written by another local user, and then run attacker-controlled output handling. Affected: `Microsoft.TestPlatform.CLI` 18.11.0 and earlier. Every version from 18.11.1 on is fixed, including 18.12.0. `Microsoft.TestPlatform.CLI` is the VSTest build that we ship into the .NET SDK. The recommended way to get this fix is to update your .NET SDK to the latest patched version, see the advisory for the SDK versions. The fix is also released in the `Microsoft.TestPlatform.CLI` package, for completeness. That package is rarely used directly. It is not a dependency of `Microsoft.NET.Test.Sdk` or `Microsoft.TestPlatform`, so those packages do not bring it in. Details: microsoft/vstest#16654 and dotnet/announcements#517 Using custom Docker images or Nano Server? See microsoft/vstest#16652 ## What's Changed * Fix TestCaseStart/Stop events dropped for data-driven tests with shared TestCase.Id by @nohwnd in microsoft/vstest#16033 * Stop the discovery manager factory from shadowing discoveryCriteria by @nohwnd in microsoft/vstest#16391 * Gate the HTTP link checker on a fingerprint of the broken links by @nohwnd in microsoft/vstest#16413 * Quote boolean conditions in shipped Microsoft.TestPlatform.targets by @nohwnd in microsoft/vstest#16404 * Obsolete API hygiene: the compatibility-safe changes by @azat-msft in microsoft/vstest#16420 * Add xxHash128 test ids, available but not default by @azat-msft in microsoft/vstest#16378 * Isolate attachment manager test temporary files by @mmitche in microsoft/vstest#16463 * Test ids report logger by @azat-msft in microsoft/vstest#16443 * Isolate code coverage files in published output by @azat-msft in microsoft/vstest#16483 * Preserve OutputType for Android test projects by @jonathanpeppers in microsoft/vstest#16496 * Fix dotnet host resolution under proot (ARM64/Termux) by @azat-msft in microsoft/vstest#16462 * Mark the xxHash128 test id API as experimental by @azat-msft in microsoft/vstest#16465 * Ship Microsoft.Diagnostics.NETCore.Client in Microsoft.TestPlatform and Portable packages by @nohwnd in microsoft/vstest#16633 * Fix localized resource paths in CLI source-build/non-Windows packages by @nohwnd in microsoft/vstest#16644 **Full Changelog**: microsoft/vstest@v18.11.0...v18.12.0 ## 18.11.1 ## Security fix This release fixes CVE-2026-105544, an elevation of privilege vulnerability in the VSTest artifact post-processor. The post-processor could consume a forged `executionComplete.json` written by another local user, and then run attacker-controlled output handling. Affected: `Microsoft.TestPlatform.CLI` 18.11.0. Fixed in: `Microsoft.TestPlatform.CLI` 18.11.1. `Microsoft.TestPlatform.CLI` is the VSTest build that we ship into the .NET SDK. The recommended way to get this fix is to update your .NET SDK to the latest patched version, see the advisory for the SDK versions. The fix is also released in the `Microsoft.TestPlatform.CLI` package, for completeness. That package is rarely used directly. It is not a dependency of `Microsoft.NET.Test.Sdk` or `Microsoft.TestPlatform`, so those packages do not bring it in. Details: microsoft/vstest#16654 and dotnet/announcements#517 Using custom Docker images or Nano Server? See microsoft/vstest#16652 ## What's Changed * Security fix for CVE-2026-105544, see microsoft/vstest#16654 * Ship Microsoft.Diagnostics.NETCore.Client in Microsoft.TestPlatform and Portable packages by @nohwnd in microsoft/vstest#16632 * Fix localized resource paths in CLI source-build packages by @nohwnd in microsoft/vstest#16643 **Full Changelog**: microsoft/vstest@v18.11.0...v18.11.1 Commits viewable in [compare view](microsoft/vstest@v18.11.0...v18.12.0). </details> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>



Description
Add an optional
query_seqlensinput (index 16) tocom.microsoft::GroupQueryAttentionand implement itin the CUDA execution provider. It carries the number of valid, non-padded tokens of a right-padded
query/key/value chunk per batch entry, so fixed-shape chunked prefill works with FlashAttention,
MemoryEfficientAttention and unfused attention, with a full-length or a windowed KV cache.
This replaces the
right_padded_queryattribute that earlier revisions of this PR introduced. The attributeand the CPU heuristic in #33505 are superseded by one input that is part of the operator contract, so every
execution provider can implement identical semantics. The attribute was never in a release, so no released
schema changes.
Stack: this PR is the base of a two-PR stack. #33505 (draft) adds the CPU implementation. Its base is the branch
of this PR, so it shows only the CPU changes, and it is retargeted to
mainonce this PR merges. ORT's build, testand CodeQL workflows run only for pull requests that target
mainorrel-*(the lint workflow runs for any base),so #33505 gets them after that retarget. This branch is rebased onto the current
main.Contract
For batch entry
b:Sis the paddedsequence_length,T = seqlens_k[b] + 1is the number of tokens inthe cache after the step,
Q = query_seqlens[b]is the number of valid rows, andP = T - Qis the numberof tokens cached before the chunk.
[0, Q)ofquery/key/valueare valid and rows[Q, S)are right padding.[P, T). Query rowssits at absolute positionP + sfor causal masking,
local_window_sizeand implicit rotary positions. Output rows[Q, S)and cache rows ator beyond
Tare unspecified.total_sequence_lengthis only an upper bound ofT(for example the cache capacity). It no longer has to beP + Sand is not used to tell a first prompt from a later chunk.causal=1,kv_sequence_length == S, past present,1 <= Q <= min(S, T),T <= total_sequence_length,S > 1requiresbatch_size == 1, andQ == 1whenS == 1. A cache that is notwindowed also needs
P + S <= C(Cis the sequence dimension ofpresent_key) and itsPcached tokens inpast_key/past_value. Those buffers may be shorter thanpresent_key, so a cache can grow between steps.total_sequence_lengthare unaffected.Key changes
right_padded_queryattribute is removed, and a "Right-padded query chunks"section is added to the operator description.
docs/ContribOperators.mdanddocs/contrib_ops/cuda/gqa.mdare updated.
group_query_attention_helper.h):CheckQuerySeqlensvalidates shape, type and, whenthe tensors are host resident, the per-entry values. With the input present,
CheckInputsno longer classifiesthe step by comparing
Swithtotal_sequence_length, and it skips the legacy check that ties a growing cache topast + S == total_sequence_length, which rejected valid calls such as past rows 10,S = 8,Q = 3,total_sequence_length = 32.GetSequenceLengthstakesQfrom the input, clamped to[1, min(S, T)], and derivesP = T - Qfrom
seqlens_kinstead oftotal_sequence_length - S. Padded rows never enter the cache and the unfusedcausal mask is anchored at
P. cuDNN SDPA is skipped for padded chunks because it assumes unpadded subsequentqueries.
S == 1ignores the input so XQA and flash decode stay enabled.query_seqlenswithcausal=0isrejected. Device-resident values cannot be checked on the host, so out-of-contract values give unspecified but
memory-safe results.
read the quantized cache. With the input the host cannot tell them apart, so a chunk is handled as a later one,
and an entry with no past and more than one valid row is then re-attended to the float K/V to match the unpadded
first prompt. An entry with one valid row behaves like a single-token step and keeps reading the quantized cache,
and a call that omits the input keeps the previous classification.
INVALID_ARGUMENTso it is never silently misinterpreted.[CPU] Support right-padded prefill chunks in GroupQueryAttention #33505 replaces the rejection with the implementation.
edits are small, but they were not compiled locally because those EPs are not part of this build, so CI is
the first compile of them. The OpenVINO check also applies to the
com.microsoftdomain.group_query_attention_pre_norm_fusion.cc,group_query_attention_fusion.cc): both fusionsrebuilt the node input list with a fixed number of slots and dropped any later input, which would have silently
removed
query_seqlens. They now keep all inputs, with unit tests.Testing
CUDA 13.0 and cuDNN 9, H200 (sm_90), Release build, FlashAttention and MemoryEfficientAttention enabled, on the
head of this branch.
onnxruntime_provider_test --gtest_filter='*GroupQueryAttention*:*GQA*': 138 passed, 18 skipped, 0 failed.The skipped tests need WebGPU. New goldens compare padded chunks with the same call on an unpadded chunk for
Flash, MEA and unfused in fp16/bf16, with and without packed QKV, for full-length and windowed caches, and for a
cache that grows between steps. New negative tests cover a bidirectional node, a missing past, a batched chunk
and a wrong shape.
onnxruntime_test_all --gtest_filter='*GroupQueryAttentionPreNormFusion*:*GroupQueryAttentionFusion*':33 passed, 4 skipped (WebGPU). Reverting the input-count fix makes the new test fail.
test_gqa.py, the whole file on this build: 1003 tests, 8 skipped, 2 failures. The failures,TestFlashGQA.test_gqa_decode_bidirectionalandTestGQAAttentionBias.test_windowed_cache_attention_bias_is_rejected, also occur on an independent build ofmainand are not related to this change. The right-padded tests cover fp16 and int8-quantized KV (including achunk with one valid row and a call that omits the input), the cuDNN fallback, capacity-bound caches,
rotary/softcap/head_sink/
attention_bias/packed QKV, andS == 1decode.compute-sanitizer --tool memcheck: 0 errors on the head of this branch for the quantized-KV tests(
TestQuerySeqlensQuantizedCache, 16 tests), the padded windowed-cache tests (7) and the right-padded CUDAgtests. An earlier revision also ran on the Flash, MEA and unfused paths for in-contract and out-of-contract
inputs (
Qof 0, negative, aboveSorT;Tabovetotal_sequence_length; negativeseqlens_k;P + Sabove the cache) with exact-size buffers separated by spacers, and a deliberately shortened cache is flagged by the
same harness. That harness was not repeated after the later review fixes.
lintrunner -m origin/main: clean.Notes for reviewers:
docs/ContribOperators.mdwas refreshed from the schema source with a script that mirrorsgen_contrib_doc.pyfor the GQA entry, because my local build is lite-protobuf and strips operatordescriptions. It matches the generator's output format; the full-protobuf CI docs check is authoritative. The
DML row of
docs/OperatorKernels.mdfollows the generator's format by hand, because DML cannot be built on Linux.Motivation and Context
Static-shape (for example compiled or graph-captured) prefill uses a fixed query chunk even when only a few rows
are real tokens. Previously, subsequent chunks derived the past offset and the eviction count from the padded
length, which corrupted the KV cache and shifted causal and RoPE alignment. Inferring the padding from
total_sequence_lengthcannot work in general, because existing callers pass the cache capacity there. Anexplicit per-entry valid length removes the ambiguity, needs no heuristic, and gives the CPU and CUDA
implementations the same contract.