Change sets 6-7: CDNA MMQ tile retune + SSD chunk size (pp16384 1775 → 2590, +45.9%) - #2
Merged
Conversation
…45.9% total) Continues the prefill work. pp16384 now 2590 t/s vs 1775 upstream (+45.9%); gap to vLLM+AITER narrows from 2.29x to 1.57x. 5 (widened). The K-quant-only scope was wrong. The three hottest MMQ kernels are Q4_K, Q5_0 and Q8_0 -- the latter two 27.4% of prefill on their own, because llama-quant.cpp downgrades Q4_K->Q5_0 and Q6_K->Q8_0 for any tensor whose column count is not divisible by 256, which Nemotron's Mamba-2 projections frequently are not. Now covers every type: +13.0% / +12.3%. 6. mmq-config-cdna.cuh has never been tuned on CDNA hardware -- PR #24127 transcribed blanket-AMD constants and benchmarked only MI100, RX 6800 and a Radeon 8060S. nthreads 512->256 with I 128->64 gives +6.8% / +6.5% and halves LDS per workgroup. 7. SSM_SSD_CHUNK_SIZE 256->128. The upstream value was tuned against cuBLAS; rocBLAS on gfx90a prefers half of it. +2.5%. Documents two invariants that make change set 6 dangerous to tune. On CDNA I == nthreads/4 (rows_per_warp is hardcoded 16 on the MFMA path with no loop over the row index), and I must additionally divide 128 (the out-of-bounds fallback is selected from a hardcoded nrows_x % 128, not from config.I). Violating either does not error -- it computes a partial tile, and benchmarks faster for exactly that reason. Four configurations measured faster while computing wrong results, including the fastest number seen in the whole session (I=64 with nthreads=512: +29%, 362 MUL_MAT and 637 MUL_MAT_ID failures). README records all four, plus the grep pattern needed to actually see harness failures. Also rejected: J=128/96 (-26%/-22%, correct but slower, so CDNA's J<=64 cap is right), MMQ_ITER_K=512 (wrong), occupancy (clamped by LLVM, no-op), forcing MMQ for the dense FP16 GEMMs retested after the stream-k fix (still -10.5%), and -ub/-b/-ctk sweeps (2048/any/q8_0 all already optimal). All change sets verified with test-backend-ops MUL_MAT 1134/1134, MUL_MAT_ID 790/790, SSM_SCAN 7/7 per device, plus generated tokens at temperature 0. Patches verified to apply in sequence to upstream 67b9b0e and reproduce modified-files/ byte-for-byte.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Continues the CDNA2 prefill work. pp16384 2590 t/s vs 1775 upstream (+45.9%); gap to vLLM+AITER narrows from 2.29× to 1.57×.
67b9b0eTotal GPU kernel time at pp4096: 7703 ms → 5331 ms (−31%).
5 widened — the K-quant scope was wrong
The three hottest MMQ kernels are types 12, 6, 8 = Q4_K, Q5_0, Q8_0, and the latter two are 27.4% of prefill on their own. They appear in a
Q4_K_Mmodel becausellama-quant.cppdowngradesQ4_K→Q5_0andQ6_K→Q8_0for any tensor whose column count isn't divisible by 256 — which Nemotron's Mamba-2 projection widths frequently aren't. Covering all types: +13.0% / +12.3%.6. MMQ tile retune (+6.5%)
mmq-config-cdna.cuhhas never been tuned on CDNA hardware. PR #24127 transcribed pre-refactor blanket-AMD constants (nthreads=512was tuned for gfx942;I=128was the catch-all AMD value) and benchmarked only MI100, RX 6800 and a Radeon 8060S — no MI210/MI250/MI300.nthreads 512→256,I 128→64: 1962 / 2529 t/s, and halves LDS per workgroup (48.2 → 28.2 KiB).Two invariants that make this dangerous
I == nthreads/4on CDNA.rows_per_warpis hardcoded to 16 on the MFMA path with no loop over the row index.Imust also divide 128 — the out-of-bounds fallback comes from a hardcodedargs.nrows_x % 128 == 0, not fromconfig.I. So384/I=96satisfies the first rule and still fails every quant type.Violating either doesn't error. It computes a partial tile — and benchmarks faster for exactly that reason.
Four configs were faster and wrong
I=64alonenthreads=256alone384 / I=96MMQ_ITER_K=512The fastest number measured in the entire session was wrong. README documents all four, plus the detail that the harness prints failures as
[MUL_MAT] ERR = ... : FAIL— a grep anchored to leading whitespace reports a clean run for a broken build.7. SSD chunk size 256 → 128 (+2.5%)
Upstream value was tuned against cuBLAS. rocBLAS on gfx90a prefers half: 64→1932, 128→2013, 192→2005, 256→1964, 512→1867 (pp4096). All numerically correct; pure throughput choice.
Also rejected
J=128/J=96: −26%/−22%, correct but slower — CDNA'sJ≤64cap is right for gfx90a (LDS was never the constraint; J=128 fits in 37.5 KiB)occupancy: no-op — LLVM clamps a waves-per-EU request below the workgroup-derived default-ub512/1024/4096,-b2048/8192,-ctk f16: all already optimal or neutralVerification
test-backend-opsMUL_MAT 1134/1134, MUL_MAT_ID 790/790, SSM_SCAN 7/7 per device, plus generated tokens attemperature 0. Patches verified to apply in sequence to upstream67b9b0eand reproducemodified-files/byte-for-byte.