Repository navigation
HRX: vectorise the decode-split multipass output pass (engine#124) - #30
Conversation
The multipass reducer's final pass gave each workitem one output channel and walked every KV block serially, recomputing expf(partial_max - maximum) per (block, element). Only 128 of 256 workitems are live at value_head_size=128, so that pass was the whole residual >2048 decode gap. Compute the per-block scale once in the lane-strided sum pass into a per-row LDS stage (also publish each row's sum), then run one vectorised output pass over all query rows at once: each workitem owns a 4-channel quad and accumulates vector<4xf32> over blocks. The per-channel block order is unchanged, so the reduce output is bit-identical. Measured (gfx1151, Qwen3-Coder-30B-A3B-Instruct-Q4_K_M, -dev HRX0, median of 6 interleaved llama-bench -p 0 -n 8 -r 5 runs): d2100 +15.4%, d3000 +19.8%, d4800 +22.0%; d2100/d2000 0.881 -> 0.976. Untouched <=2048 controls +1.1%/+4.2%. 1.24 GB decode-path logits byte-identical to the previous build; code word ZX-4718-QQ exact at 4700 tokens; 0 GPU faults. benchmarks/NOTE-hrx-124-multipass-output-2026-09-27.md has the full table, method and repro.
…orised (engine#124) Brings 1bit-MONSTER/llama.cpp#30. The multipass reducer's output pass gave each workitem one channel and walked every KV block serially, recomputing expf(partial_max - maximum) per (block, element); only half the workgroup is live at value_head_size=128, which was the whole residual >2048 decode gap. The per-block scale is now computed once in the lane-strided sum pass into a per-row LDS stage, and one vectorised all-rows pass (4 channels per workitem) does the output. Per-channel block order is unchanged, so the reduce is bit-identical (1.24 GB of decode-path logits compare equal to the previous pin). d2100 +15.4%, d3000 +19.8%, d4800 +22.0%; d2100/d2000 0.881 -> 0.976, so the boundary cliff is gone. Nothing changes at or below capacity 2048. Details and repro in benchmarks/NOTE-hrx-124-multipass-output-2026-09-27.md.
|
Review: the change looks right for the measured range: expf once per (row, block), a vectorised output pass, the #123 pack barriers untouched, and it builds on 00adc2b. One blocker before merge: LDS scales with context length.
gfx1151 has 64 KB of LDS per workgroup, and this is the fused Please either:
Smaller: |
fcd83eb
into
1bit/hrx-vulkan-patched
…orised (engine#124) (#180) * Pin llama.cpp a34a6b7: HRX decode-split multipass output pass is vectorised (engine#124) Brings 1bit-MONSTER/llama.cpp#30. The multipass reducer's output pass gave each workitem one channel and walked every KV block serially, recomputing expf(partial_max - maximum) per (block, element); only half the workgroup is live at value_head_size=128, which was the whole residual >2048 decode gap. The per-block scale is now computed once in the lane-strided sum pass into a per-row LDS stage, and one vectorised all-rows pass (4 channels per workitem) does the output. Per-channel block order is unchanged, so the reduce is bit-identical (1.24 GB of decode-path logits compare equal to the previous pin). d2100 +15.4%, d3000 +19.8%, d4800 +22.0%; d2100/d2000 0.881 -> 0.976, so the boundary cliff is gone. Nothing changes at or below capacity 2048. Details and repro in benchmarks/NOTE-hrx-124-multipass-output-2026-09-27.md. * Pin llama.cpp fcd83eb (llama.cpp #30 merged; same tree as a34a6b7) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: agent-872bf5 <agent-872bf5@localhost> Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Long-context check after merge (Qwen3-Coder-30B-A3B Q4_K_M, GQA 8 rows, HRX0,
So up to 65K tokens at 8 rows (scale stage ~32 KB) it runs and is faster. The speed only; correctness at long context was not checked here. The LDS bound concern remains for >=128K at 8 rows and >=64K at 16 rows; a guard in the matcher (or a chunked stage) is still worth adding. Also: agent-872bf5's ZAYA1-8B bench on this build (bin180-new, -d up to 16384) has been stuck for over 1.5 h with the GPU idle and the HRX queue thread spinning. It is unexplained so far and might not be this change; see the owner's thread. |
|
Follow-up on the ZAYA hang I mentioned: it does not reproduce. The identical |
What
Closes the residual decode gap above
key_value_token_capacity2048 that #13 left behind (1bit-MONSTER/engine#124).@ggml.flash_attention.decode_split.reduce_completed.multipassended with a scalar output pass:workitem -> one output channel, then a serialscf.for %block = [0 to active_block_count]over every KV block, executed by all 256 workitems. Only 128 are live atvalue_head_size = 128, and each one recomputedscale = expf(partial_max[block] - maximum)for every block —expfonce per(block, element)instead of once per block, with every element walking the block dimension alone. That pass was the entire ~16% gap.Changes
flash_attention_decode_split_f32_f16_wmma.loom): the lane-strided sum pass already computes the per-block scale; store it into a per-row workgroup stage (scale_stage_view[row, block]) and publish each row'ssum(sum_stage_view[row]). The output pass reloads the exact f32 value, removing ~128x redundantexpfand the redundantpartial_maxreloads.wowns a 4-channel quad (row = quad / quads_per_row,channel = (quad % quads_per_row) * 4), loadsvector<4xf16>, and accumulatesvector<4xf32>over blocks withunroll(%c4) schedule(interleaved). At the production GQA shape (8 query heads per KV head,value_head_size = 128) there are exactly 256 quads, so all four subgroups stay busy.The per-channel accumulation order over blocks is unchanged and the vector ops are elementwise, so the reduce output is bit-identical to the previous reducer.
Verification (gfx1151 Strix Halo,
Qwen3-Coder-30B-A3B-Instruct-Q4_K_M,-dev HRX0)llama-bench -p 0 -n 8 -r 5 -d 1900,2000,2100,3000,4800, median of 6 interleaved A/B rounds:The cliff is gone:
d2100/d20000.881 -> 0.976 (d4800/d20000.633 -> 0.741). The two untouched depths moved +1.1% / +4.2% (run-to-run noise).llama-perplexity -c 2049 -b 1 --save-all-logits(token-by-token decode;GGML_HRX_LOG_DISPATCH=1confirmsflash_attention_decode_split); the 1,244,725,284-byte logits dumps are byte-identical (cmp), PPL 21.9760 +/- 0.81813 on both.ZX-4718-QQat 4700 prompt tokens (capacity 4864, multipass),llama-server, temperature 0, seed 42,cache_prompt:false-> exact PASS.HSA_STATUS_ERROR_MEMORY_FAULT, 0res = -3.Full method, table and repro commands:
benchmarks/NOTE-hrx-124-multipass-output-2026-09-27.md.A throwaway diagnostic that deleted the output block loop (keeping max/sum) measured +21.6% / +50.0% / +30.5% at d2100 / d3000 / d4800 — the basis for attributing the gap to the output pass rather than the reduction math.