Skip to content

ggml-cuda: f32 tall-skinny GEMM kernel for gfx1151 (RDNA3.5) - #74

Draft
roberteg16 wants to merge 1 commit into
gfx11from
rogarcia.gfx1151-f32-tall-skinny-gemm
Draft

ggml-cuda: f32 tall-skinny GEMM kernel for gfx1151 (RDNA3.5)#74
roberteg16 wants to merge 1 commit into
gfx11from
rogarcia.gfx1151-f32-tall-skinny-gemm

Conversation

@roberteg16

@roberteg16 roberteg16 commented Jul 28, 2026

Copy link
Copy Markdown

What this does

Adds a custom HIP path for f32 mul_mat with a tall-skinny weight (K=2048, N=32) on gfx1151 (Strix Halo, RDNA3.5). For this shape ggml_cuda_mul_mat falls through to hipBLAS (mmvf caps at batch 8; f32 mmf needs MFMA/Ampere), which is far below the memory-bound peak. The new kernel is 2x-4x faster than hipBLASLt across the batch range.

The kernel keeps the hot activation resident in LDS and streams the cold weight from global memory with a backedge software pipeline; the K reduction is lane-parallel followed by a wave32 DPP tree reduce. A predicate/dispatch (ggml_cuda_should_use_mul_mat_f32_tall_skinny / ggml_cuda_mul_mat_f32_tall_skinny) routes only the validated shape to the custom path: RDNA3.5, f32xf32->f32, contiguous, single-batch, K=2048, N=32. Everything else keeps its existing behavior. All device code is guarded so the CUDA build and non-RDNA3.5 HIP targets are unaffected.

Benchmarks

Radeon 8060S (gfx1151), decode regime (activation hot in cache, weight cold from DRAM), vs hipBLASLt (ROCBLAS_USE_HIPBLASLT=1). Percentages are the achieved fraction of the ~238 GiB/s DRAM roofline (>100% is legitimate: the hot activation is served from the 32 MB Infinity Cache). The APU throttles, so numbers vary by a couple of points.

M custom (this PR) hipBLASLt
8 23% 5%
64 52% 13%
128 68% 20%
512 89% 44%
1024 101% 56%
2048 106% 74%
4096 105% 73%

For M <= 8 the existing mmvf path handles the batch, so in practice the custom kernel serves M >= ~9.

Testing

test-backend-ops is extended with the new shapes (N=32 across M in {8,64,128,512,2048,4096}) in the eval and perf lists:

cmake --build build --target test-backend-ops -j
./build/bin/test-backend-ops -o MUL_MAT

All added shapes report OK against the CPU f32 reference, with no regressions in the rest of the MUL_MAT suite.

End-to-end

The shape is real: Qwen3.6-35B-A3B (Q4_K_M) issues the f32 K=2048 N=32 mul_mat ~600 times per forward pass (~1.6% of total GPU time), and the kernel runs it ~3-4x faster than hipBLAS (~34 us -> ~8 us per call). End to end this is a small prefill speedup and no change to decode (batch 1, handled by mmvf). Measured with llama-bench: -p 128 is ~1.4% faster on the stable runs; -p 4096 -n 0 -d 0 is ~1652 vs ~1644 t/s (~0.5%), within the +-20-33 t/s run-to-run stddev of this throttling APU. The model's runtime is dominated by its quantized expert GEMMs, so the absolute gain here is modest; workloads that lean more on f32 tall-skinny GEMMs benefit more.

Scope

Deliberately narrow: it only touches the validated gfx1151 shape and falls back to hipBLAS everywhere else, so there is no risk to other backends, GPUs, or shapes.

For f32 mul_mat where the weight is tall-skinny (K=2048, N=32) and the batch is
moderate, ggml_cuda_mul_mat on gfx1151 falls through to the hipBLAS path (mmvf caps at
batch 8, and f32 mmf needs MFMA/Ampere), which is far from bandwidth-bound peak for this
decode shape. This adds a custom HIP kernel that keeps the (hot) activation resident in
LDS and streams the (cold) weight from global memory with a backedge software pipeline,
reducing the K dimension lane-parallel with a wave32 DPP tree. A new predicate/dispatch
(ggml_cuda_should_use_mul_mat_f32_tall_skinny / ggml_cuda_mul_mat_f32_tall_skinny) selects
a per-M configuration and routes only the validated shape to the custom path, leaving all
other shapes on hipBLAS. It fires only on RDNA3.5, only for f32xf32->f32, contiguous,
single-batch, K=2048, N=32. All kernel code is under #if defined(GGML_USE_HIP) so the
CUDA build is unaffected (the predicate returns false there).

Measured on Radeon 8060S (gfx1151) in the mixed decode regime (activation hot in L2,
weight cold), vs hipBLASLt (ROCBLAS_USE_HIPBLASLT=1): N=32 wins across M=8..4096 (about
2-4x, ~68% of DRAM roofline at M=128 rising to ~100%+ at large M). Numerically verified
against the CPU reference: test-backend-ops -o MUL_MAT passes for all added N=32 shapes.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Robert Esclapez Garcia <robert.garcia@amd.com>
@roberteg16
roberteg16 force-pushed the rogarcia.gfx1151-f32-tall-skinny-gemm branch from 3b17350 to f891283 Compare July 29, 2026 17:27
@roberteg16
roberteg16 marked this pull request as ready for review July 29, 2026 17:28
@roberteg16
roberteg16 marked this pull request as draft July 29, 2026 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant