qwen4exp : enable sparse flash attention in build_attn_qsa - #28349
Conversation
Pass the indexer top-k width as n_kv_max so backends with a sparse FA path (Metal, CUDA) gather the selected KV rows instead of masking the full cache.
|
You need to measure it on way more devices before enabling this change, that was the definition to "when we're ready" |
|
M2 Ultra results for this change. Setup: Apple M2 Ultra (192 GB), Metal. Qwen3.8-Flash-Next Q5_K_M (DevQuasar), F16 KV, GGUF note: DevQuasar's Q5_K_M has Method: three fixed prompts (about 2k, 32k and 128k tokens),
On this device the change is a prefill win and a small decode loss. Prefill: +20% over masked at 128k (cold 128k TTFT 382 s to 319 s), -2% at 32k, -7% at 2k where the top-k list covers every cell. Decode: -2.4% at 2k, -3.7% at 32k, -4.3% at 128k. No decode gain at any depth, unlike the M5 Max numbers above. Separately: all three QSA variants decode within 4% of each other and about 31% below the dense reference at 128k on Metal, so the per-token cost at depth is in |
Overview
Pass the indexer top-k width as
n_kv_maxinbuild_attn_qsa, so backends with a sparse FA path (#27970 CUDA, #28098 Metal) gather the selected KV rows instead of masking the full cache. Same call as the MLA sparse path inllama-graph.cpp.The mask is
set_rowsover the top-k indices plus the causal mask, so each row has at mosttop_k->ne[0]finite entries, which is the boundggml_flash_attn_ext_set_n_kv_maxrequires.M5 Max, Qwen3.8-Flash-Next IQ4_XS, q8_0 KV,
-ub 2048 -b 2048,llama-bench -fa 1 -r 2:llama-server cold prefill, three ~33k prompts: 664 -> 760 t/s. Greedy output over a 36k prompt matched master.
Measured on master + #27836 (MTP), which does not touch this path. CUDA not tested here. Its gate falls back to dense below 4096 KV, and CPU and Vulkan ignore the hint.
Additional information
Removes the TODO from #28098. The change is the one @am17an suggested in #27970 (comment), with the Metal numbers in #28098 (comment).
Requirements