ggml-cpu: 2x2 register-blocked AVX2 kernel for ggml_vec_dot_q4_0_q8_0 - #39
Open
codspeed-hq[bot] wants to merge 1 commit into
Conversation
Add an nrc == 2 path that computes a 2x2 output tile (two src0 rows x two src1 columns), unpacking each row's nibbles and loading each column's q8_0 block once instead of four times, and enable nrows = 2 for Q4_0 under AVX2. Also replace the load + vpsrlw + vinserti128 sequence in bytes_from_nibbles_32() with vbroadcasti128 + a per-qword vpsrlvq, saving one instruction per 32 weights in every AVX2 4-bit kernel. Results are bit-identical to the previous 1x1 path.
Author
Merging this PR will improve performance by 55.13%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | mul_mat[q4_0] |
102 ms | 65.7 ms | +55.13% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing codspeed-optim-2-2-register-blocked-avx2-kernel-for-ggml-vec-dot-1785326413536 (418d842) with master (46819c9)
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.
What
Prompt processing multiplies each Q4_0 weight row against many activation columns, but the x86 kernel handled one
(row, column)pair per call, so for every output element it re-unpacked the 4-bit weights, re-converted the two FP16 block scales and re-loaded the Q8_0 activation block.Two changes to the AVX2 path:
nrc == 2path inggml_vec_dot_q4_0_q8_0computing a 2x2 output tile (twosrc0rows x twosrc1columns). Each row's nibbles are unpacked once and each column's Q8_0 block is loaded once, then reused by all four dot products.Q4_0getsnrows = 2under AVX2, which is whatggml_compute_forward_mul_matalready does on aarch64 with i8mm.bytes_from_nibbles_32()helper:vbroadcasti128+ a per-qwordvpsrlvqreplaces load +vpsrlw+vinserti128, removing one instruction per 32 weights in every AVX2 4-bit kernel.The inner loop drops from ~21 instructions per 32 weights per dot product to ~13, and the weight/activation traffic through L1 is halved.
Measured impact
CodSpeed CPU simulation, micro benchmark suite (
ggml-benchmarks), base46819c9vs this commit:mul_mat[q4_0]The other 14 benchmarks are unchanged, no regressions (
mul_mat[f32],mul_mat[q4_k],quantize_chunk[*],ffn_swiglu,rope,rms_norm,soft_max, fp16/fp32 conversions).Walltime could not be measured locally (the sandbox has no
perf), so the macro job in CI is the first walltime data point. The aarch64 macro runners already select a 2-row kernel for Q4_0 via i8mm, so the walltime job is expected to be neutral there.Correctness
Results are bit-identical, not just close:
bytes_from_nibbles_32()was compared against the old sequence exhaustively (every byte value in every one of the 16 positions) plus 2M random inputs - output vectors identical, and the low/high-nibble semantics verified directly.ggml_mul_mat: a Q4_0 matmul computed with the 2x2 kernel is bitwise equal to dedicated single-column matmuls (which take the 1x1 kernel), across several shapes at 1, 2 and 4 threads, including odd shapes that fall back to 1x1. The same matmul built against the base commit produces byte-identical output. The per-block accumulation order is deliberately kept identical to the 1x1 path.arch/x86/quants.cstill compiles for SSSE3-only and AVX-only targets (the new path is inside the existing__AVX2__guard).Scope
x86/AVX2 only; the non-AVX2 paths and the
assert(nrc == 1)they rely on are untouched.