Skip to content

cuda: ROCmFPx tensor types + Q4_0_ROCMFP4_FAST MMQ tiles on HIP (gfx1151) - #40

Open
baraxnaxgaming-commits wants to merge 2 commits into
halo-box:masterfrom
baraxnaxgaming-commits:feat/hip-fp4-mmq
Open

baraxnaxgaming-commits wants to merge 2 commits into
halo-box:masterfrom
baraxnaxgaming-commits:feat/hip-fp4-mmq

Conversation

@baraxnaxgaming-commits

Copy link
Copy Markdown

What

Adds ggml-cuda/HIP support for the ROCmFPx tensor family this tree already ships for CPU+Vulkan:
Q4_0_ROCMFP4, Q4_0_ROCMFP4_FAST, Q2/Q3/Q6/Q8_0_ROCMFPX. Two commits:

  1. Dispatch and support - dequant, convert (f32 and FP-to-FP), get_rows (incl. the CUDA-graph-safe
    variant), MMVQ template instances, backend glue, so these GGUFs load and run on HIP at all. Also
    restores the *_hip_* helper headers (scale LUT + codebooks) that the format import pruned while
    common.cuh still includes them.
  2. MMQ tile path for Q4_0_ROCMFP4_FAST - mirrors the existing MXFP4 tiles: SRAM_LAYOUT_Q8_1
    loads, q8_0_q8_1 dp4a/WMMA vec_dot, D4 y-layout, UE4M3 scale decoder without the e8m0 x0.5
    factor, kvalues_rocmfp4 codebook (max level 10, not NVFP4's 12). Config rows added for
    pascal-dp4a / rdna2 / rdna3 / rdna3-5 / cdna / ampere. Deliberately NOT in Blackwell configs:
    use_native_fp4 is false there, so it falls through to Ampere like NVFP4-generic does.

Why

Without this, HIP builds run FP4 matmuls through dequant+hipBLAS. On Radeon 8060S that fallback is
the prefill bottleneck for the published Strix Halo ROCmFP4 GGUFs; HIP is half the userbase's default
backend. Tile rows mirror this master's current MXFP4 config set (incl. the 128/64/128 row), so the
gain sits on top of today's MXFP4 tuning.

Correctness

  • RTX 4090, CUDA 13.3 / MSVC, test-backend-ops vs CPU reference:
    • default build, -p rocmfp4: 288 OK / 0 FAIL (exit 0)
    • -DGGML_CUDA_FORCE_MMQ=ON, -o MUL_MAT -p rocmfp4: 42 OK / 0 FAIL (exit 0)
  • gfx1151 HIP, build -DGGML_HIP=ON -DGPU_TARGETS=gfx1151 ROCm 7.x:
    test-backend-ops test -o MUL_MAT -b ROCm0 -p rocmfp4: 78 OK / 0 FAIL

Performance (Radeon 8060S / gfx1151, 128 GB)

Baseline rebuilt from the merge-base of this PR in the same session on the same machine
(ab-base-dispatch = master + commit 1 of this PR, without the MMQ tiles), so the delta isolates
exactly the tile path. Method per CONTRIBUTING: warmup discarded; palindrome arm order
base/new/new/base x2 (8 runs per cell); -fa on; ubatch 512.

cell baseline t/s (median of 4, max) +MMQ t/s (median of 4, min) delta separation
pp512 Qwen3.8-27B-ROCmFP4-FAST 350.95 (353.36) 372.36 (368.51) +6.1 % clean, zero overlap
pp2048 same model 349.25 (349.51) 368.25 (368.17) +5.4 % clean, zero overlap
  • Kernel cell MUL_MAT m=4096,n=512 (test-backend-ops perf, ROCm0): 5389.5 -> 3503.0 us (x1.54).
  • Not tested: NVIDIA CUDA runtime perf (correctness only), decode-path changes (none expected; batch
    <=8 stays on MMVQ by design).

Deferred / notes

  • Dual-scale Q4_0_ROCMFP4 (non-FAST) MMQ deferred: needs the NVFP4-style per-16 scale convention.
  • All runs used default env (HIP_LAUNCH_BLOCKING unset), not CI posture; numbers are not
    comparable to blocking-mode runs.
  • Related but intentionally NOT in this PR: a Vulkan MMVQ change (amortise MXFP4 scale decode over
    the whole block, measured x1.67 at n=8 on gfx1151). Happy to split it into its own PR if wanted.

Written by Hermes Agent (Nous Research); benchmarks run on a Ryzen AI Max+ 395.

Loads Q4_0_ROCMFP4, Q4_0_ROCMFP4_FAST and the Q2/Q3/Q6/Q8_0_ROCMFPX GGUF
tensor types on ggml-cuda/HIP (previously CPU+Vulkan only). Adds dequant,
convert, get_rows support and MMVQ dispatch; restores the *_hip_* helper
headers (scale LUT + codebooks) that the format import pruned.

Part 1/2 of the FP4-on-HIP work; part 2 adds the MMQ tile path.
Step 2 of the Strix Halo HIP plan: give the production FP4 format an
MMQ path so prefill batches (>8, incl. spec-verify at wide ubatch and
MoE routing) stop falling through to dequant+hipBLAS purely because
the type was absent from the MMQ switches.

Mirrors MXFP4 exactly - same block size (32), one UE4M3 scale per 32
values, SRAM_LAYOUT_Q8_1 tiles, q8_0_q8_1 vec_dot kernels (dp4a and
MMA data layout), D4 y-side quantizer. Differences from MXFP4:
kvalues_rocmfp4 codebook (Codebook10, max level 10 not 12) and the
UE4M3 scale decoder without the e8m0 *0.5 factor. Tile rows mirror
this master's current MXFP4 config set, incl. the 128/64/128 row.

Not added to Blackwell configs on purpose: use_native_fp4 is false
for this type there, so it falls through to the Ampere config like
NVFP4-generic does. Dual-scale Q4_0_ROCMFP4 (2 scales/block) deferred
to a follow-up slice (NVFP4-style per-16 convention).

Validated: test-backend-ops vs CPU ref on RTX 4090 CUDA (default build
-p rocmfp4: 288 OK / 0 FAIL; GGML_CUDA_FORCE_MMQ=ON -o MUL_MAT -p
rocmfp4: 42 OK / 0 FAIL) and on gfx1151 HIP (-o MUL_MAT -b ROCm0 -p
rocmfp4: 78 OK / 0 FAIL). Measured on Ryzen AI Max+ 395 against a
rebuilt merge-base in the same session: pp512 +6.1%, pp2048 +5.4%
(palindrome x2, zero overlap); MUL_MAT m=4096,n=512 kernel 5389 ->
3503 us (x1.54).

@dzannotti dzannotti left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validation: the HIP gfx1151 build succeeded. Q4_0_ROCMFP4_FAST MUL_MAT passed 45/45 targeted ROCm correctness cases. test-quantize-fns and test-rocmfpx also completed successfully.

Benchmark reproduced for the stated kernel shape: against the dispatch-only parent (ede2bbe), test-backend-ops perf at m=4096, n=512, k=14336 measured 5,540.70 us/run before the MMQ tiles and 2,919.23 us/run with this PR: 1.90x faster. The PR's full-model prefill result remains unverified here because the ROCmFP4 model is not local.

Scope: the stated target is gfx1151, yet the PR changes shared MMQ configuration for Ampere, CDNA, RDNA2/3/4 too. Please split or tightly gate the Strix portion and separately validate every architecture whose policy changes.

comment generated by my clanker Codex

@baraxnaxgaming-commits

Copy link
Copy Markdown
Author

Thanks for the review. Three clarifications on scope, plus where we'll comply:

  1. No existing type's policy changes on any architecture. The PR is 754 insertions / 1 deletion (the single deletion is a string-list line). Every change in mmq-config-{ampere,cdna,pascal*,rdna2,rdna3,rdna3-5,rdna4}.cuh adds CASE(GGML_TYPE_Q4_0_ROCMFP4_FAST, …) rows for a type that exists only in this fork — dispatch of upstream types on those architectures is bit-for-bit unchanged.

  2. We'll tighten the gate as requested. We will keep CASE rows only for RDNA3.5 (gfx1151) and Ampere — validated on RTX 4090 CUDA: default build -p rocmfp4 288 OK / 0 FAIL; GGML_CUDA_FORCE_MMQ=ON -o MUL_MAT -p rocmfp4 42 OK / 0 FAIL — and drop the rows for architectures we cannot measure. Those arches keep today's dequant+BLAS fallback: zero behavior change, no re-validation burden on anyone.

  3. test-rocmfpx does not exist in this PR or on master. If you have it locally, please share it — we'll wire it into CI. Current type-specific coverage is test-backend-ops -o MUL_MAT -p rocmfp4 vs CPU ref (gfx1151 HIP: 78 OK / 0 FAIL); happy to promote that filter into a dedicated CI job as the type-specific regression test requested.

On indexing safety: MMQ entry for this type is gated by the same ne[0] % ggml_blck_size() and alignment checks used for MXFP4, and the tile config mirrors MXFP4's Q8_1 SRAM layout one-for-one — malformed dimensions reach the new loaders no more than they reach MXFP4's today.

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.

2 participants