Files
rocky-vulkan-llama/docs/shader-tuning.md
T
Claude (noether) 272604b10d Shader iter1: Mali L-warptile (WM=WN=16) -> ub128 4x (5.8->23.4 t/s), spill 5328->96
Confirms the ceiling was the desktop-tuned shader, not the hardware. Per-thread acc = WM*WN/WARP
(matches our tls_size instrument to the byte). Large ubatch now beats the ub64 ceiling + CPU.
~25-30% of roofline; iter2 grows the tile. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 17:29:55 +02:00

1.6 KiB
Raw Blame History

Shader tuning — Mali-tuned mul_mm warptile (the throughput unlock)

After the driver fix (no OOM) revealed the real ceiling was llama.cpp's desktop-tuned matmul shader, we tune it for Mali. Fable implements the tile; hardware-in-the-loop measures on the G610.

The model (Fable, verified against our instrument)

Per-thread matmul accumulators = WM·WN/WARP (mul_mm.comp: sums[WMITER·TM·WNITER·TN/2], WNITER=WM·WN/(WARP·TM·TN·WMITER)). That count IS the register-spill driver, measured directly by our panvk [panvk-tls] tls_size instrument. Stock on G610 (WARP=16):

  • L: 32·64/16 = 128 acc → 5328 B spill (matches measured L exactly)
  • M: 16·32/16 = 32 acc → 544 B spill (matches measured M exactly)

Fix = shrink WM·WN/WARP so the tile fits Mali's register file (no spill → occupancy recovers).

Iteration 1 — L-variant WM=WN=16 (16 acc). Qwen2.5-3B-Q4_K_M, pp512

ubatch shader before after it1 tls_size
64 M (control, untouched) 21.0 20.6 t/s 544 (unchanged)
128 L (new tile) 5.8 23.4 t/s (4.0×) 5328 → 96
256 L (new tile) 7.4 23.8 t/s (3.2×) 5328 → 96

Spill collapsed 55×; large ubatch now beats the ub64/M ceiling AND the CPU. Confirms: the ceiling was the shader, NOT the hardware. ~24 t/s ≈ 2530% of roofline (~80150 t/s ideal) → headroom left. Patch: patches/llama.cpp-0003-mali-warptile-iter1.patch (adds VK_VENDOR_ID_ARM + is_mali warptile branch, L tuples only). Iteration 2: grow the tile toward the register ceiling for arithmetic reuse.