RDNA3.5 (gfx11 / gfx1151) MMQ prefill optimizations#32
Conversation
| #if defined(GGML_USE_HIP) | ||
| // ROCm/clang WMMA codegen workaround: an unprovable-false branch keeps full unroll/inline | ||
| // on the hot K-loop. blockDim.z is always 1 for mul_mat_q. See docs/backend/HIP-MMQ-compiler-codegen.md. | ||
| #define MMQ_CODEGEN_SPLIT_COLD (threadIdx.z > 0) |
There was a problem hiding this comment.
This approach looks brittle. Let's please investigate further what affects the unroll decision. Can you try with an explicit unroll pragma?
b94c48c to
7483e49
Compare
|
I ran this change with all models. Here is the current result: http://fisweb:8080/wrk/xcohdnobkup2/lichang/regression_comparison.html, will investigate it more. |
|
I suggest to split this PR for improvements across kernels types (e.g. one PR to focus on Q8_0). Important: Benchmarking can be quite hard (dynamic frequency, thermal ramp up, ...) so it's important the the kernel benchmark reproduces the same per-kernel GPU time that the trace of the full model shows in our QoR suite. |
- Add kernel dimension logging for profiling analysis - Reduce mmq_x when LDS limits WGs/CU - Improve LDS layout and activation load pipelining for prefill Co-authored-by: Cursor <cursoragent@cursor.com>
- Add opt-in HIP MMQ phase profiling to split dequant vs MMA time - Refactor Q4_K qs load for WMMA ldmatrix layout - Precompute Q4_K vec_dot scale factors before WMMA accumulate - Gate dimension logs behind GGML_CUDA_MM_LOG - Fix MMQ phase profiler clock64 deltas on HIP Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
- Hoist Q6_K vec_dot scales on RDNA3.5 WMMA - Use mmq_x=128 for Q6_K narrow-N prefill; dual-WG mmq_x=64 where needed - Pipeline Q6_K B-tile loads; batch B loads with load_generic - Remove always-on MMQ profiling overhead on hot path - Limit dual-WG mmq_x downgrade to K-quants Co-authored-by: Cursor <cursoragent@cursor.com>
Add MMQ_HIP_TILE_BARRIER() tile-scope __syncthreads() at K-loop phase boundaries on HIP+RDNA3.5 to restore pp128 throughput after removing dead threadIdx.z cold/hot loop split. Co-authored-by: Cursor <cursoragent@cursor.com>
The pipelined load_ldmatrix for B0 omitted the k01 term, reading the wrong activation slice and corrupting Q6_K matmul results. Restores sanity-check accuracy on Qwen2.5 and Llama-2 while keeping the prefetch. Co-authored-by: Cursor <cursoragent@cursor.com>
Thanks a lot @mgehre-amd, this sounds good to me. I'm aware we have one in vLLM for kernel benchmarking, will learn from it, and integrate with the existing one in llama.cpp. |
|
Looks like rocprofiler-compute (https://rocm.docs.amd.com/projects/rocprofiler-compute/en/latest/) can do a pretty good on profiling kernel but I haven't dig it deep. Fyr. |
Summary
RDNA3.5 (
gfx11/gfx1151) MMQ prefill optimizations and a documented HIP/clang codegen workaround.MMQ optimizations (
mmq.cuh)mmq_xwhen LDS limits workgroups/CU; dual-WGmmq_x=64for narrow-N K-quant prefill (Q6_K FFN-down), gated to K-quants only.vec_dotfor WMMA;ldmatrix-friendly qs layout; precompute scale factors before WMMA accumulate.mmq_x=128for narrow-N prefill; batched B-tile loads (load_generic); pipelined B loads invec_dot; restoreload_ldmatrixpath.Q8_0on RDNA3.5.Benchmarks (gfx1151, ROCm)
Run with
llama-bench(-p 128 -n 0 -ngl 999, flash-attn on). Rebuild MMQ aftermmq.cuhchanges:touch ggml/src/ggml-cuda/mmq.cuh && cmake --build build -j$(nproc).Files changed
ggml/src/ggml-cuda/mmq.cuh— RDNA3.5 MMQ optimizations +MMQ_CODEGEN_SPLIT_COLDdocs/backend/HIP-MMQ-compiler-codegen.md— compiler issue write-up (new)Test plan
GGML_HIP=ON, targetgfx11/gfx1151llama-benchon Q4_K_M and Q6_K models:pp128, narrow-N FFN-down shapesgfx11base; confirm no regression vs pre-strip branch with codegen splittemplate-instances/mmq-instance-q4_k.cuand verify hot-pathds_load_b128≈ 48 (not 24) permmq_x=128kernel body — see docAI usage disclosure
Used Cursor/AI for profiling analysis, ASM comparison, codegen-split investigation, and documentation.