Repository navigation
[WebGPU] Implement SparseAttentionIndexer operator - #32528
Merged
kunal-vaishnavi merged 68 commits intoOct 3, 2026
Merged
Conversation
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
β¦on-indexer' into copilot/implement-sparse-attention-indexer-again Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Copilot created this pull request from a session on behalf of
kunal-vaishnavi
September 10, 2026 07:02
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
kunal-vaishnavi
changed the base branch from
main
to
copilot/implement-sparse-attention-indexer
September 10, 2026 07:19
kunal-vaishnavi
marked this pull request as ready for review
September 10, 2026 07:19
β¦on-indexer' into copilot/implement-sparse-attention-indexer-again # Conflicts: # onnxruntime/test/contrib_ops/sparse_attention_indexer_op_test.cc Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
π‘ Changes recommended
WebGPU mishandles explicit zero scales and 64-bit positions, an opt-out test is ineffective, and the PR bundles major undocumented features.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Implements WebGPU SparseAttentionIndexer, while also bundling substantial CUDA, filesystem, and device-discovery changes.
Changes:
- Adds WebGPU QSA/CSA kernels, registration, tests, and documentation.
- Adds packed INT4 PagedAttention/XQA support.
- Adds CUDA device mapping and cross-platform random-access files.
File summaries
| File | Description |
|---|---|
onnxruntime/test/python/transformers/test_paged_attention.py |
Extends XQA scale and dispatch tests. |
onnxruntime/test/providers/cuda/plugin/cuda_plugin_arena_test.cc |
Tests runtime CUDA device discovery. |
onnxruntime/test/providers/cuda/plugin/cuda_device_mapping_test.cc |
Tests CUDA identity mapping. |
onnxruntime/test/platform/env_test.cc |
Tests random-access files. |
onnxruntime/test/contrib_ops/sparse_attention_indexer_op_test.cc |
Adds WebGPU QSA/CSA coverage. |
onnxruntime/core/providers/cuda/plugin/cuda_ep_factory.h |
Stores runtime-discovered devices. |
onnxruntime/core/providers/cuda/plugin/cuda_ep_factory.cc |
Maps and creates CUDA devices. |
onnxruntime/core/providers/cuda/plugin/cuda_device_mapping.h |
Adds device-mapping helpers. |
onnxruntime/core/platform/windows/env.h |
Declares Windows random-access support. |
onnxruntime/core/platform/windows/env.cc |
Implements Windows positional reads. |
onnxruntime/core/platform/posix/env.cc |
Implements POSIX positional reads. |
onnxruntime/core/platform/env.h |
Defines the random-access file API. |
onnxruntime/core/graph/contrib_ops/bert_defs.cc |
Extends PagedAttention for packed INT4. |
onnxruntime/contrib_ops/webgpu/webgpu_contrib_kernels.cc |
Registers SparseAttentionIndexer. |
onnxruntime/contrib_ops/webgpu/bert/sparse_attention_indexer.h |
Declares WebGPU programs and kernel. |
onnxruntime/contrib_ops/webgpu/bert/sparse_attention_indexer.cc |
Implements QSA/CSA WGSL execution. |
onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc |
Registers INT4 PagedAttention kernels. |
onnxruntime/contrib_ops/cuda/bert/xqa/xqa_paged_spec_dec_fp16_int4_256.cu |
Instantiates speculative INT4 XQA. |
onnxruntime/contrib_ops/cuda/bert/xqa/xqa_paged_loader.h |
Documents INT4 XQA contracts. |
onnxruntime/contrib_ops/cuda/bert/xqa/xqa_paged_loader.cu |
Dispatches INT4 XQA kernels. |
onnxruntime/contrib_ops/cuda/bert/xqa/xqa_paged_fp16_int4_256.cu |
Instantiates decode INT4 XQA. |
onnxruntime/contrib_ops/cuda/bert/xqa/xqa_loader.h |
Adds the INT4 quantization type. |
onnxruntime/contrib_ops/cuda/bert/xqa/mhaUtils.cuh |
Unpacks INT4 cache grains. |
onnxruntime/contrib_ops/cuda/bert/xqa/mha.h |
Defines packed cache heads. |
onnxruntime/contrib_ops/cuda/bert/xqa/mha_impl.cuh |
Integrates INT4 scaling and synchronization. |
onnxruntime/contrib_ops/cuda/bert/xqa/int4_cache.cuh |
Adds INT4 dequantization. |
onnxruntime/contrib_ops/cuda/bert/paged_attention.h |
Adds per-channel XQA control. |
onnxruntime/contrib_ops/cuda/bert/paged_attention.cc |
Routes INT4 and per-channel execution. |
onnxruntime/contrib_ops/cuda/bert/paged_attention_impl.cu |
Implements INT4 cache reads and writes. |
onnxruntime/contrib_ops/cuda/bert/attention_data.h |
Adds scale-normalizer scratch state. |
onnxruntime/contrib_ops/cpu/bert/paged_attention_helper.h |
Validates packed INT4 caches. |
docs/OperatorKernels.md |
Regenerates kernel type documentation. |
docs/ContribOperators.md |
Documents packed cache shapes and types. |
docs/contrib_ops/webgpu/sparse_attention_indexer.md |
Documents WebGPU support. |
docs/contrib_ops/cuda/sparse_attention_indexer.md |
References the WebGPU implementation. |
docs/contrib_ops/cuda/paged_attention.md |
Documents INT4 PagedAttention. |
docs/contrib_ops/cuda/gqa.md |
Updates the INT4 build default. |
cmake/CMakeLists.txt |
Enables INT4 KV cache by default. |
.github/workflows/android.yml |
Raises the Android size threshold. |
Review details
Suppressed comments (1)
onnxruntime/contrib_ops/webgpu/bert/sparse_attention_indexer.cc:467
- This second read also truncates
position_idsto its low 32 bits. The existingCsaInt64MaxPositioncontract expectsINT64_MAXto make every compressed entry eligible, but it becomes-1here and yields threshold zero, so WebGPU selects nothing. Compute the ceil-division threshold from the two-word int64 storage (also avoidingposition + 1overflow).
<< " let position = " << position_ids.GetByOffset("row") << ";\n"
<< " let threshold = select(0u, u32(position + 1) / uniforms.compress_ratio, position >= 0);\n"
- Files reviewed: 40/40 changed files
- Comments generated: 4
- Review effort level: Balanced
π‘ Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
β¦_infer.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
β¦rse-attention-indexer-again Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
β¦rse-attention-indexer-again Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Sayan Shaw (sayanshaw24)
previously approved these changes
Oct 2, 2026
β¦rse-attention-indexer-again # Conflicts: # onnxruntime/contrib_ops/webgpu/webgpu_contrib_kernels.cc Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Akshay Sonawane (apsonawane)
approved these changes
Oct 3, 2026
kunal-vaishnavi
deleted the
copilot/implement-sparse-attention-indexer-again
branch
October 3, 2026 18:58
kunal-vaishnavi
added a commit
that referenced
this pull request
Oct 5, 2026
β¦ching (#32618) ### Description Adds `com.microsoft.PackedSparseAttentionIndexer` version 1 for packed, variable-length continuous batching, with CUDA and WebGPU implementations. The operator supports both QSA and CSA policies over flattened token inputs and per-request metadata while preserving fixed-capacity state across prefill and decode calls. It is designed to produce selection metadata compatible with `SparsePagedAttention` without changing the existing dense `SparseAttentionIndexer` ABI or behavior. Key changes: - Add the shared operator schema, fixed generic QSA/CSA state slots, strict policy-specific validation, and fixed output shape inference. - Add CUDA and WebGPU kernels and provider registrations for FP32, FP16, and BF16 where supported. - Add device-side packed metadata validation without host synchronization in normal provider paths. - Add deterministic TopK selection and complete per-request overflow handling that preserves prior state and returns empty selections. - Support safe state aliasing where provider semantics permit it while avoiding unsafe CSA buffer aliasing. - Share policy constants and math helpers with the existing sparse attention indexer where practical. - Add symbolic shape inference support and focused Python coverage. - Add C++ shape, QSA/CSA numerical, prefill/decode, zero-token request, malformed metadata, deterministic ordering, and overflow tests. - Add operator and WebGPU implementation documentation and regenerate contrib operator/kernel documentation. Validation performed: - `onnxruntime_provider_test` CPU build completed successfully. - All 12 `PackedSparseAttentionIndexerShapeInferenceTest` tests passed. - Symbolic shape-inference tests passed. - Repository linting, formatting checks, and secret scanning passed. - CUDA/WebGPU numerical tests are included but could not be executed locally because those providers and compatible hardware/toolchains are unavailable in the environment. ### Motivation and Context The existing `SparseAttentionIndexer` contract uses dense `[B, S, ...]` inputs, dense masking, and growing contiguous state. OgaEngine-compatible paged-attention models instead use flattened packed tokens, `cumulative_sequence_lengths`, per-request past lengths, dynamic request scheduling, and fixed-address state. This separate operator bridges that contract mismatch for sparse paged attention while keeping the existing dense operator stable. QSA selections reference request-local positions in the main paged cache; CSA selections reference fixed-capacity auxiliary compressed state suitable for `SparsePagedAttention` local-plus-selected execution. Built on the sparse attention indexer work from #32528. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Kunal Vaishnavi <kvaishnavi@microsoft.com>
Sayan Shaw (sayanshaw24)
added a commit
that referenced
this pull request
Oct 6, 2026
## Summary Follow-up to #32528 (the initial WebGPU `SparseAttentionIndexer` implementation). This PR reduces the QSA recomputation called out in its follow-up list. The sparse-indexer prerequisite #32656 has merged into `main`; this PR now targets `main` directly. The optimization changes only the WebGPU QSA selection path. - Cache visible token positions and block scores per query in bounded workgroup memory. Reuse query/key RMS normalization within each block score. - Reuse cached positions on visibility overflow, scanning only the uncached tail; retain exact visibility and score recomputation fallbacks outside the cache bounds, preserving score-descending/index-ascending TopK semantics and non-prefix masks. - Bound both caches plus the count to 15,364 bytes, below WebGPU's guaranteed 16 KiB workgroup-storage limit. - Add FP32/FP16 non-prefix-mask parity tests and document the optimized/fallback paths. ## Validation - The original Qwen integration run passed 18 focused `SparseAttentionIndexerShapeInferenceTest` cases. On current `main`, a Linux Release WebGPU provider/provider-test build and all 23 focused QSA/CSA and packed-indexer cases passed on NVIDIA H200/Vulkan, including both bounded-cache fallback thresholds. Focused formatting and `git diff --check` passed. - End-to-end NVIDIA H200 Vulkan testing used a non-paged, no-MTP Qwen3.8 raw INT4 RTN/INT8-last-matmul Generator export, with 16-token prefill chunks: | Context | Before | After | | --- | --- | --- | | 16-token prefill | 43.27 s | 1.51 s | | Next decode step after 16 tokens | 42.63 s | 0.70 s | | 1K prefill | Did not complete within 181 s of prefill | 68.33 s (14.99 tok/s) | | 1K decode | No valid rate | 1.29 tok/s over eight tokens | | 2K prefill | No prior completed result | 145.37 s (14.09 tok/s) | | 2K decode | About 30.8 s/step at the old cache boundary | 1.03 tok/s over eight tokens | The eight generated pieces from the four-token smoke prompt were unchanged, as was the first token ID from the 16-token probe. Model-load time (~58β60 s) is excluded from prefill measurements. The H200 static WebGPU build now executes the WebGPU-specific parity tests; all 23 focused QSA/CSA and packed-indexer cases passed on current `main`. The EngramGate and GenAI builder/runtime fixes in the working tree are not part of this PR. The performance table above was measured on the earlier Qwen3.8 integration branch; GPU regression tests, not full-model timing, were rerun on current `main`. ## Current main update (October 6) Kunal's #32656 merged, and this PR is now based on `main` with a three-file QSA-only review diff. Merged current `main` again after that restack. The WebGPU provider-test build and all 23 focused H200 QSA/CSA plus packed-indexer tests passed. The October 6 Windows WebGPU job exposed a long-running visibility-overflow boundary test that lost the D3D12 device. Commit 9499988 avoids redundant prefix rescans; all 22 focused WebGPU QSA/CSA tests pass on H200/Vulkan, with that boundary test taking 241 ms. Android minimal-size CI passed on the preceding head; CI for the fix is pending. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
eserscor
pushed a commit
that referenced
this pull request
Oct 7, 2026
## Summary Follow-up to #32528 (the initial WebGPU `SparseAttentionIndexer` implementation). This PR reduces the QSA recomputation called out in its follow-up list. The sparse-indexer prerequisite #32656 has merged into `main`; this PR now targets `main` directly. The optimization changes only the WebGPU QSA selection path. - Cache visible token positions and block scores per query in bounded workgroup memory. Reuse query/key RMS normalization within each block score. - Reuse cached positions on visibility overflow, scanning only the uncached tail; retain exact visibility and score recomputation fallbacks outside the cache bounds, preserving score-descending/index-ascending TopK semantics and non-prefix masks. - Bound both caches plus the count to 15,364 bytes, below WebGPU's guaranteed 16 KiB workgroup-storage limit. - Add FP32/FP16 non-prefix-mask parity tests and document the optimized/fallback paths. ## Validation - The original Qwen integration run passed 18 focused `SparseAttentionIndexerShapeInferenceTest` cases. On current `main`, a Linux Release WebGPU provider/provider-test build and all 23 focused QSA/CSA and packed-indexer cases passed on NVIDIA H200/Vulkan, including both bounded-cache fallback thresholds. Focused formatting and `git diff --check` passed. - End-to-end NVIDIA H200 Vulkan testing used a non-paged, no-MTP Qwen3.8 raw INT4 RTN/INT8-last-matmul Generator export, with 16-token prefill chunks: | Context | Before | After | | --- | --- | --- | | 16-token prefill | 43.27 s | 1.51 s | | Next decode step after 16 tokens | 42.63 s | 0.70 s | | 1K prefill | Did not complete within 181 s of prefill | 68.33 s (14.99 tok/s) | | 1K decode | No valid rate | 1.29 tok/s over eight tokens | | 2K prefill | No prior completed result | 145.37 s (14.09 tok/s) | | 2K decode | About 30.8 s/step at the old cache boundary | 1.03 tok/s over eight tokens | The eight generated pieces from the four-token smoke prompt were unchanged, as was the first token ID from the 16-token probe. Model-load time (~58β60 s) is excluded from prefill measurements. The H200 static WebGPU build now executes the WebGPU-specific parity tests; all 23 focused QSA/CSA and packed-indexer cases passed on current `main`. The EngramGate and GenAI builder/runtime fixes in the working tree are not part of this PR. The performance table above was measured on the earlier Qwen3.8 integration branch; GPU regression tests, not full-model timing, were rerun on current `main`. ## Current main update (October 6) Kunal's #32656 merged, and this PR is now based on `main` with a three-file QSA-only review diff. Merged current `main` again after that restack. The WebGPU provider-test build and all 23 focused H200 QSA/CSA plus packed-indexer tests passed. The October 6 Windows WebGPU job exposed a long-running visibility-overflow boundary test that lost the D3D12 device. Commit 9499988 avoids redundant prefix rescans; all 22 focused WebGPU QSA/CSA tests pass on H200/Vulkan, with that boundary test taking 241 ms. Android minimal-size CI passed on the preceding head; CI for the fix is pending. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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 WebGPU support for
com.microsoft.SparseAttentionIndexer, covering Qwen4-Exp QSA and DeepSeek V4 CSA policies using the existing provider-neutral schema.policy_mode="qsa"and"csa".Motivation and Context
Sparse attention models need policy-specific candidate selection before downstream attention execution. This change enables QSA and CSA index generation on WebGPU while preserving the shared operator ABI, deterministic selection semantics, and graph-visible state.