Skip to content

vulkan: gfx1151 K-quant int-mmq large tile 128x256 @ 512 threads (~1.8x dense prefill) - #5

Open
aic0d3r wants to merge 2 commits into
Nathanw1014:strix-halo-vulkanfrom
aic0d3r:gfx1151-matmul
Open

vulkan: gfx1151 K-quant int-mmq large tile 128x256 @ 512 threads (~1.8x dense prefill)#5
aic0d3r wants to merge 2 commits into
Nathanw1014:strix-halo-vulkanfrom
aic0d3r:gfx1151-matmul

Conversation

@aic0d3r

@aic0d3r aic0d3r commented Aug 22, 2026

Copy link
Copy Markdown

Dense-model prefill on gfx1151 is int-mmq-K-quant bound, and the stock large tile underfills the 40 CUs at prefill shapes: it re-reads the A weights once per 128-token slab of N. Doubling only BN and the workgroup size (128x256 @ 512 threads, per-thread TM/TN/WMITER unchanged) halves the A re-reads per token. No shader changes; wg_denoms kept in sync. Gated to RDNA3 + iGPU.

Stacked on strix-halo-vulkan @ 2586f6e, Qwen3.8-27B UD-Q5_K_XL-v2, bundled RADV, -fa 1 -b/-ub 2048:

test stock tile 128x256@512 gain
pp512 290.8 ±0.3 588.7 ±2.5 2.02x
pp4096 289.0 ±2.9 527.4 ±3.1 1.82x
pp16384 216.1 ±0.4 * 467.1 ±1.0 2.16x *
tg128 10.76 ±0.02 10.81 ±0.02 unchanged

Deep context at the serving config (-b/-ub 4096, same model/driver; stock arm tile-forced back via the env on the same binary, pp65536 stock is from the v0.6.5 payload — same engine family, corroborated by pp32768: 241.3 here vs 251.5 there):

test stock tile 128x256@512 gain
pp32768 241.3 ±0.02 402.8 ±0.8 1.67x
pp65536 212.2 306.3 ±0.2 1.44x

* pp16384 stock was measured on mainline (b21e4de74), not on the fork — the stock tile value is identical in both trees, but the fork's long-ctx prefill fixes mean fork-stock is likely somewhat higher, so treat 2.16x as an upper bound. Patched numbers are fork, r=5. The pp4096 A/B is same-binary interleaved (3 rounds, tile forced back via GGML_VK_MMQ_INT_K); pp512 stock is r=3 with the same env forcing.

Correctness and gates:

  • Greedy outputs byte-identical (temp 0, diffed).
  • Decode/verify never select the large tile (n ≤ 64): spec-decode serving config (DFlash2 n=4, sharp template) measures 28.7 t/s avg / 38.8 peak decode at 64.2% acceptance, no regression.
  • The coopmat quant family (iq4_xs dequant path) measurably dislikes the doubled tile and stays stock; BM=256 / 1024 threads / TM/TN/WMITER reshapes / wave32 all neutral on this part.
  • Probe envs included in the fork style: GGML_VK_MMQ_INT_K (int K-quants), GGML_VK_MMQ_INT (int non-K, mirrors K when unset), GGML_VK_MMQ_CM (coopmat quant family).

Also upstreamed to ggml-org: ggml-org#27554 (issue ggml-org#27553) — stock and patched both lower on mainline at every length (stock 250 vs 289, patched 437 vs 527 pp4096; patched pp16384 333 vs 467), so the fork's long-ctx prefill work is clearly stacking with this.

One datapoint for the 3ca6f21f2 RADV pad-2 gate, in case it's useful: on system Mesa 26.2.0 (Arch, mesa 3:26.2.0-1), dense pp4096 with pad 2 measures 222 vs 284 with GGML_VK_SHMEM_PAD=4 (−22%). Your table has 26.2.1 winning on the MoE pp512 shape, but 26.2.0 on dense leaks through the >= 25.3.0 version gate. The start-script workaround pins the bundled RADV, so nothing urgent.

The dense integer-dot mmq path picks its large tile when both matmul dims
exceed 64, which is every big GEMM in a dense-model prefill. On gfx1151
(RDNA3 iGPU, e.g. Radeon 8060S) the stock 128x128 tile at 256 threads
underfills the 40 CUs at prefill shapes and re-reads the A weights once
per 128-token slab; doubling only BN (and the thread count, keeping the
per-thread register tiling identical) halves the A re-reads per token.

Measured on Qwen3.8-27B UD-Q5_K_XL-v2, bundled RADV, -fa 1 -b/-ub 2048,
same binary interleaved A/B with the tile forced back via GGML_VK_MMQ_INT_K:

  pp4096  527.4 +-3.1 t/s vs 289.0 +-0.8   (1.82x)
  pp512   588.7 +-2.5 t/s, pp16384 467.1 +-1.0 t/s (r=5)
  tg128   10.81 +-0.02 t/s, unchanged

Decode and spec-verify batches never select the large tile (n<=64), and
greedy outputs are byte-identical. Tile-area probes beyond 128x256
(BM=256, 1024 threads, TM/TN/WMITER reshapings, wave32) were neutral;
the coopmat quant family (iq4_xs dequant path) measurably dislikes the
doubled tile and stays stock.

Gated to RDNA3 + integrated GPU. GGML_VK_MMQ_INT_K / GGML_VK_MMQ_INT /
GGML_VK_MMQ_CM env probes are added for further tuning; wg_denoms are
kept in sync with BM/BN so dispatch and split-k see the real tile.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant