Skip to content

[WebGPU] Optimize Qualcomm FP16 prefill attention - #33724

Open
Yang Gu (gyagp) wants to merge 1 commit into
microsoft:mainfrom
gyagp:pr/webgpu-qualcomm-prefill-attention
Open

Yang Gu (gyagp) wants to merge 1 commit into
microsoft:mainfrom
gyagp:pr/webgpu-qualcomm-prefill-attention

Conversation

@gyagp

@gyagp Yang Gu (gyagp) commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Description

Optimize FP16 prefill attention on Qualcomm GPUs with explicit 128-lane subgroup support. Four adjacent subgroup lanes share a query row, reducing per-lane query/output storage. A 256-thread workgroup processes 64 rows and stages 16 keys/values at a time. Softmax and output accumulation use FP32, with normalization at the final store.

The cooperative kernel supports causal and noncausal attention, softcap, broadcast attention bias, head sinks, sliding windows, and per-batch query lengths. Softcap precedes bias addition; the window's left bound stays relative to the query even in noncausal mode. Per-batch past lengths use signed, clamped subtraction. Dispatch requires FP16, head size 128, at least 128 query tokens, unquantized KV caches, subgroup-size control supporting 128 lanes, and the subgroup_id WGSL language feature. Decode retains its existing paths.

The specialization is shared by dense-prefill callers rather than tied to Aion. Existing operator-level limits still apply: WebGPU GroupQueryAttention rejects causal=0, and WebGPU PagedAttention rejects nonzero softcap. Noncausal kernel coverage comes from MHA and PagedAttention; softcap coverage comes from GQA.

Motivation and Context

Adreno X1-85 has wide subgroups. Sharing a row across four lanes reduces register storage per lane and fills 128-lane subgroups; FP32 accumulation avoids repeated FP16 rounding while processing key tiles.

On Surface Laptop 7 / Snapdragon X Elite X1E80100 / Adreno X1-85 (driver 31.0.170.0), a fresh source-built ORT GenAI native benchmark comparison on 2026-11-02 measured Aion-1.1-Instruct base-model prefill:

Measurement Main baseline Revised PR
Mean prefill latency 4.04888 s 3.46377 s
Prompt throughput 252.91 TPS 295.63 TPS

This is 14.45% less latency / 16.89% more TPS. All 28 attention layers are now eligible, including the 21 sliding-window layers.

Both ORT variants use identical build settings and base c666fd413e (ORT 1.32.0), which includes merged #33560. GenAI is source-built 6b7ff3ca3efa15da219050fdb4ecf8bed67875af (0.18.0-dev). Tests use native benchmark/c/model_benchmark.exe, batch 1, exactly 1,024 prompt tokens, KV capacity 8,192, one generated token, generator reuse, D3D12, graph capture disabled, and validation disabled for timing. Four processes per variant each ran two warmups and five measured iterations, in baseline/PR/PR/baseline/PR/baseline/baseline/PR order: 20 measured samples per variant. Model loading and first-token sampling are outside the prompt-processing scope. Loaded ORT DLL paths and hashes were verified.

Model: https://huggingface.co/webai-community/ai-models/tree/c9697d1b476a9dbcf86771dfbd2abdaa8122c78a/aion/onnx-webgpu . No adapter was loaded. The prompt repeats hello 1,024 times. The local GenAI integration patch adjusts external-QNN registration and teardown output flushing; benchmark timing logic is unchanged.

Validation

  • Windows ARM64 Release runtime and provider tests rebuilt from source; lintrunner and whitespace checks passed.

  • 101 distinct attention tests passed on this device without skips, including cooperative-prefill dispatch and FP16 graph-capture replay.

  • Tests ran with shader-cache validation enabled. Generated shaders confirm cooperative dispatch for the new feature combinations and the Aion sliding-window path.

  • New provider-specific tests use 129-token FP16 queries, batch 1, two query heads, one KV head, head size 128, and KV capacity 208. Global attention and a 17-token window are checked against an independent FP64 reference and complete KV-cache contents. The capture test performs two direct graph replays with updated device-resident sequence lengths and total lengths 146/170/132, while retaining fixed buffer addresses.

  • Both new tests inspect executed dispatch metadata for subgroup IDs, a 256-thread workgroup, and explicit 128-lane subgroups. Deliberately disabling cooperative dispatch makes the selection test fail; retaining stale replay lengths makes the reference comparison fail. Faults were restored before the successful 101-test run.

  • The shared WebGPU GQA reference runner disables CPU fallback, including the cooperative and high-magnitude cases. The new tests also disable fallback.

  • New feature tests use independent CPU calculations with FP64 accumulation. Coverage includes softcap, four bias broadcast layouts, sinks, window sizes 1/17/2048, combined features, noncausal cross-attention with shorter/longer KV lengths, and BSNH/BNSH query paths.

  • Ragged PagedAttention tests exercise per-batch query lengths 129/101, past lengths 17/7, noncontiguous pages, partial tiles, causal/noncausal mode, and sliding windows through dense fallback.

  • Existing PR coverage includes sequence lengths 128/129/257, batch sizes 1/2, GQA ratio 3, rotary, high-magnitude FP16 inputs, past caches, and right-padded key lengths.

  • Fresh GenAI validation on the fixed 1,024-token prompt produced finite, bit-identical logits (top token 357) and bit-identical sampled KV entries from layers 0 and 27. This is a fixed-prompt smoke check; FP32 accumulation can change results on other inputs.

  • MHA query/key data vary by row, head, and dimension; an independent FP64 reference exercises QK reduction and BNSH indexing.

  • WebGPU-only MHA and ragged PagedAttention cooperative-prefill cases live in test/providers/webgpu/contrib_ops, with ShaderF16 capability checks retained. PagedAttention reuses a shared CPU reference runner. Both relocated cases passed in a fresh 101-test run with no skips and shader-cache validation enabled.

  • Query ownership uses subgroup_id and subgroup_invocation_id, independently of workgroup-local invocation ordering. Shader dumps confirm the new mapping.

  • The three affected test translation units compiled successfully in ARM64 adapter mode with ORT_USE_EP_API_ADAPTERS. A standalone capability probe linked and ran without provider libraries; both helpers return false in adapter mode, and test objects have no undefined WebGPU-context symbols. This is targeted compilation coverage, rather than a full shared-provider build.

  • Performance testing is limited to this device and workload. Browser WASM and other Qualcomm adapters were not benchmarked.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@gyagp

Copy link
Copy Markdown
Contributor Author

/run bots

@gyagp

Copy link
Copy Markdown
Contributor Author

Jiajia Qin (@qjia7) this is an optimization specific for QC, though the overall speedup is modest. Please take a look.

@qjia7

Copy link
Copy Markdown
Contributor

The request was received. Approve workflow runs. Thanks.

Yang Gu (gyagp) added a commit to gyagp/onnxruntime that referenced this pull request Nov 2, 2026
Remove the causal-only, zero-softcap, no-bias, no-sink, no-window, and
uniform-query-length restrictions from the cooperative FP16 kernel.
Apply softcap before bias, include sinks in online softmax, and preserve
query-relative window bounds and per-batch past offsets.

Add independent-reference feature tests, noncausal MHA cross-attention,
and ragged PagedAttention coverage with past caches and sliding windows.
The focused and regression selections cover 99 passing attention tests
on Windows ARM64 with shader-cache validation enabled.

A fresh source-built GenAI benchmark on Adreno X1-85 measures Aion
1024-token prefill at 4.05361s -> 3.47874s versus main c666fd4:
14.18% less latency and 16.53% higher throughput
(252.61 -> 294.36 TPS). All 28 layers now qualify, including 21
sliding-window layers. Batch 1, KV capacity 8192, D3D12, capture off;
four processes per variant, two warmups and five measured runs each.
Fixed-prompt logits and sampled KV entries are bit-identical.

Addresses review discussion_r4438482429 in microsoft#33724.
Copilot AI balanced review requested due to automatic review settings November 2, 2026 09:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The WebGPU shared-library test build can fail, and the shader can mix query rows by assuming workgroup and subgroup lane ordering match; tests also lack FP16 capability checks and meaningful Q/K coverage.

4 open issues
What changed in this PR

Adds a Qualcomm-specific FP16 prefill attention path to ONNX Runtime’s WebGPU provider, using cooperative query processing and FP32 accumulation while retaining existing decode paths.

Changes:

  • Dispatches eligible workloads to a 256-thread kernel with explicitly requested 128-lane subgroups.
  • Supports attention bias, softcap, sinks, sliding windows, and per-batch sequence lengths.
  • Adds regression coverage for numerical accuracy, cross-attention, query layouts, caches, padding, and ragged sequences.
File Description
onnxruntime/​test/​contrib_ops/​paged_attention_op_test.cc Adds ragged dense-fallback cases and sliding-window reference calculations.
onnxruntime/​test/​contrib_ops/​multihead_attention_op_test.cc Adds noncausal cross-attention cases covering two query layouts.
onnxruntime/​test/​contrib_ops/​group_query_attention_op_test.cc Adds capability-gated cooperative prefill and feature tests.
onnxruntime/​contrib_ops/​webgpu/​bert/​flash_attention.wgsl.template Implements cooperative attention with FP32 accumulation.
onnxruntime/​contrib_ops/​webgpu/​bert/​flash_attention.h Adds softcap configuration and uniform declarations.
onnxruntime/​contrib_ops/​webgpu/​bert/​flash_attention.cc Adds dispatch eligibility, subgroup sizing, and softcap wiring.

Review effort: Balanced

Yang Gu (gyagp) added a commit to gyagp/onnxruntime that referenced this pull request Nov 2, 2026
Derive query-row and dimension ownership from subgroup ID and subgroup
lane ID so XOR reductions never depend on workgroup-local lane ordering.
Require the subgroup_id WGSL feature and enable its shader builtin.

Share capability probes across attention tests. Guard internal context
access in adapter builds and skip new FP16 tests when ShaderF16 cannot be
confirmed. Use nonzero, row/head/dimension-dependent Q/K data and an FP64
reference to exercise cross-attention reduction and BNSH query indexing.

Windows ARM64 runtime/provider-test builds and all 99 selected attention
tests pass with shader-cache validation, without skips. The three changed
test translation units also compile with ORT_USE_EP_API_ADAPTERS; a
standalone probe links/runs without provider libraries or context symbols.
Lintrunner and whitespace checks pass.

Remeasured Aion 1024-token prefill versus main c666fd4:
4.04888s -> 3.46377s, 252.91 -> 295.63 TPS.
14.45% lower latency / 16.89% higher throughput.
Batch 1, KV capacity 8192, D3D12, graph capture off; four processes per
variant, two warmups and five measured runs each. Fixed-prompt logits
remain finite and bit-identical, with top token 357.

Addresses Copilot discussions 4440615600, 4440615680, 4440615743, and
4440615806 in microsoft#33724.
@gyagp
Yang Gu (gyagp) force-pushed the pr/webgpu-qualcomm-prefill-attention branch 2 times, most recently from 388e84d to 777fb6d Compare November 3, 2026 01:53
@gyagp
Yang Gu (gyagp) requested a balanced review from Copilot November 3, 2026 01:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The tests can silently fall back to CPU, do not verify selection of the optimized WebGPU path, and omit FP16 graph-capture replay coverage with live sequence lengths.

3 open issues
4 resolved since last review

Review effort: Balanced

Share each query row across four lanes in 128-lane subgroups to reduce
register pressure. Use FP32 accumulation and support bias, softcap, sinks,
sliding windows, and variable query lengths.

Aion 1024-token prefill on Adreno X1-85 improves from 4.04888 to 3.46377 s
and 252.91 to 295.63 tokens/s: 14.45% lower latency, 16.89% more throughput.
Batch 1, KV capacity 8192, D3D12, graph capture off; 20 samples per build.

Validated with a Windows ARM64 Release build, 101 attention tests without
skips (including graph capture/replay and dispatch checks), adapter-mode
compile checks, and lint.
@gyagp

Copy link
Copy Markdown
Contributor Author

/run bots

@gyagp

Copy link
Copy Markdown
Contributor Author

Jiajia Qin (@qjia7) please review again

@qjia7

Copy link
Copy Markdown
Contributor

The request was received. Approve workflow runs. Thanks.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

FP16 query scaling can erase valid attention scores, and key MHA, ragged PagedAttention, and GQA feature tests do not verify cooperative dispatch.

2 open issues
3 resolved since last review

Review effort: Balanced

Comment on lines +1042 to +1044
const bool qc_cooperative = is_qualcomm && is_fp16 && has_subgroups &&
parameters.head_size_ == 128 && parameters.sequence_length_ >= 128 &&
!kv_cache_quantization_enabled &&
#endif
if (valid) {
for (var d = 0u; d < 8u; d++) {
qv[d] = q[q_base + d * 4u + d_lane] * q_element_t(uniforms.alpha);

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants