Commit f2c8a09
authored
webgpu: Fuse FlashAttention decode kernels and extend to any sequence length (#28389)
## Summary
- Extend the FlashAttention decode path to work with any sequence length
(not just seq_len=1), with causal masking and `use_seqlen_k` support for
static KV cache
- Add m_tile optimization to process multiple Q rows per workgroup
(m_tile=1/2/4), amortizing K/V loads
- Fuse the separate QKT and SplitVx shaders into a single QKV kernel
using online softmax, eliminating the intermediate `qk` tensor
(`B×H×seq×present_seq`) and reducing dispatch count from 3 to 2
- Route between prefill (FlashAttentionProgram) and split-reduce (fused
QKV + VxReduce) paths based on sequence length
## Resolved Issues
**Whisper decoding prefill improved from 4.68ms to 1.09ms.** Whisper's
decoder attention has a small sequence length but large total sequence
length (seq_len=4, total_seq_len=1500). The default prefill shader
(FlashAttentionProgram) has low parallelism in this case because each
workgroup iterates serially over the full KV cache. The split-reduce
path tiles the KV dimension across workgroups, achieving much higher GPU
occupancy for this workload shape.
## Details
**Fused QKV kernel**: Each workgroup computes QK^T dot products, applies
attention bias and causal mask, computes local softmax (per-tile max and
sum), normalizes, and multiplies by V — all in one kernel. Per-tile
metadata (max, sum) is written for the VxReduce shader to rescale
partial outputs using online softmax: `output = Σ(partial_i ×
local_sum_i × exp(local_max_i - global_max)) / global_sum`.
**Path routing** (`use_split_reduce`): The split-reduce path is used
when `sequence_length_ < 32`; otherwise the single-kernel
FlashAttentionProgram prefill path is used. Microbenchmarks on Phi-4 (32
heads, head_size 128, GQA group 3) show split-reduce is 1.13×-2.07×
faster than the fused prefill kernel across `sequence_length ∈ {16, 30,
31}` × `total_sequence_length ∈ {128, 500, 2000}`. The previous
heuristic additionally gated on `total_sequence_length_ > 1000`, but
that signal is 0 under graph capture (seqlen_k lives on the GPU) and the
carve-out is unnecessary because split-reduce is uniformly faster for
short Q.
## Test plan
- [x] 30/30 MHA unit tests pass
- [x] phi4-graph-prune produces correct output
- [x] whisper-tiny-int4 produces correct transcription
- [x] clang-format clean1 parent 2cf6c6c commit f2c8a09
7 files changed
Lines changed: 426 additions & 426 deletions
File tree
- onnxruntime/contrib_ops/webgpu/bert
Lines changed: 135 additions & 132 deletions
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
39 | 41 | | |
40 | 42 | | |
41 | 43 | | |
| |||
56 | 58 | | |
57 | 59 | | |
58 | 60 | | |
59 | | - | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
60 | 64 | | |
61 | 65 | | |
62 | 66 | | |
| |||
138 | 142 | | |
139 | 143 | | |
140 | 144 | | |
141 | | - | |
| 145 | + | |
142 | 146 | | |
143 | | - | |
144 | | - | |
145 | | - | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
146 | 153 | | |
147 | 154 | | |
148 | 155 | | |
| |||
156 | 163 | | |
157 | 164 | | |
158 | 165 | | |
159 | | - | |
| 166 | + | |
| 167 | + | |
160 | 168 | | |
161 | 169 | | |
162 | 170 | | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
177 | | - | |
178 | | - | |
179 | | - | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | 171 | | |
185 | 172 | | |
186 | 173 | | |
187 | | - | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
188 | 177 | | |
189 | 178 | | |
190 | 179 | | |
191 | 180 | | |
192 | | - | |
193 | | - | |
| 181 | + | |
| 182 | + | |
194 | 183 | | |
195 | 184 | | |
196 | 185 | | |
| |||
199 | 188 | | |
200 | 189 | | |
201 | 190 | | |
202 | | - | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
203 | 194 | | |
204 | 195 | | |
205 | 196 | | |
206 | 197 | | |
207 | 198 | | |
| 199 | + | |
| 200 | + | |
208 | 201 | | |
209 | 202 | | |
210 | 203 | | |
| |||
225 | 218 | | |
226 | 219 | | |
227 | 220 | | |
228 | | - | |
| 221 | + | |
229 | 222 | | |
230 | 223 | | |
231 | 224 | | |
Lines changed: 0 additions & 118 deletions
This file was deleted.
0 commit comments