Skip to content

Commit 3a97902

Browse files
committed
[gemma4_31b][cuda][tq4] split-K decode: size BLOCK_M to num_groups (not fixed 64)
The split-K decode launcher hardcoded BLOCK_M=64 for the pack-GQA path, but only L_q*num_groups rows are valid (=8 for Gemma4 global, H_Q=32/H_KV=4). That left 56/64 M-rows idle while the QK/PV tensor-core MMAs still computed all 64, and made acc[64, HEAD_DIM=512] fp32 = 128 KB/CTA, spilling registers to local memory. Size BLOCK_M = max(16, next_pow2(L_q*num_groups)) instead (16 for Gemma4 global), removing the wasted MMA rows and the spills. Decode-only; prefill path unchanged.
1 parent 14d4810 commit 3a97902

1 file changed

Lines changed: 9 additions & 1 deletion

File tree

backends/cuda/triton/kernels/tq4_sdpa.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,15 @@ def _launch_tq4_decode_splitk(
12011201

12021202
if pack_gqa:
12031203
H_grid = H_KV
1204-
BLOCK_M = 64 # Pack GQA uses larger BLOCK_M for efficiency
1204+
# Size BLOCK_M to the actually-packed rows (L_q * num_groups; for decode
1205+
# L_q=1 so == num_groups), rounded up to the bf16 tensor-core MMA minimum
1206+
# of 16 -- instead of a fixed 64. Gemma4 global has num_groups=8, so the
1207+
# old BLOCK_M=64 left 56/64 M-rows idle (the QK/PV MMAs still computed all
1208+
# 64 rows) AND made acc[BLOCK_M, HEAD_DIM] fp32 = 64*512*4 = 128 KB/CTA,
1209+
# which blows past the register file and spills to local memory. Matching
1210+
# BLOCK_M to num_groups removes both the wasted MMA rows and the spills.
1211+
_packed_m = L_Q * num_groups
1212+
BLOCK_M = max(16, 1 << (_packed_m - 1).bit_length())
12051213
else:
12061214
H_grid = H_Q
12071215
BLOCK_M = 32

0 commit comments

Comments
 (0)