ggml-cpu: 2x2 register-blocked kernel for ggml_vec_dot_f32 (F32 matmul) - #34
Open
codspeed-hq[bot] wants to merge 1 commit into
Conversation
F32 matmul evaluates one output element per ggml_vec_dot_f32() call, so a 2x2 output tile re-reads both operands twice. Add a 2x2 register-blocked path (nrc == 2) that multiplies two src0 rows against two src1 columns in a single pass, and set nrows = 2 for GGML_TYPE_F32 so ggml_compute_forward_mul_mat() picks it up. Every loaded vector now feeds two FMAs, halving the loads and the cache lines touched per tile. The kernel is written with the generic GGML_SIMD mappings, so AVX/AVX2/ AVX512, NEON, VSX, wasm and LoongArch all use it. SVE and RISC-V V keep their hand-written paths and stay at nrows = 1, as do non-SIMD targets.
Author
Merging this PR will improve performance by 20.88%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | ffn_swiglu |
1,067.7 ms | 858.1 ms | +24.42% |
| ⚡ | Simulation | mul_mat[f32] |
346.1 ms | 282.1 ms | +22.7% |
| ⚡ | WallTime | prompt_layer[f32] |
247.1 ms | 213.6 ms | +15.69% |
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-kernel-for-ggml-vec-dot-f32-f-1785295416304 (5a7c570) 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.
Summary
F32 matrix multiplication in
ggml_compute_forward_mul_mat()computes one output element perggml_vec_dot_f32()call. Each call streams a full src0 row and a full src1 column, so evaluating a 2x2 output tile re-reads both operands twice.This PR adds a 2x2 register-blocked kernel (
nrc == 2): two src0 rows against two src1 columns in a single pass.ggml_compute_forward_mul_mat()already supports this throughggml_type_traits_cpu::nrows(it is the path used by the ARMi8mmkernels), so only the kernel and the F32 trait entry change.Why it helps
Every loaded vector feeds two FMAs instead of one, so the four dot products of a tile issue half the loads and touch half the cache lines of four independent calls. Per 4 FMA-vectors the loop costs 2.25 instructions instead of 2.5, and the L1/L2 traffic of the weight matrix is halved.
GGML_SIMDmappings, so AVX/AVX2/AVX512, NEON, VSX, wasm and LoongArch all benefit - not just x86.nrows = 1, so they are strictly unaffected.Measured impact (CodSpeed, CPU simulation)
Base =
master(46819c9), head = this branch, same machine, same build flags (-DCODSPEED_MODE=simulation, AVX2/FMA/F16C):ffn_swiglumul_mat[f32]The 13 other micro benchmarks are unchanged (
mul_mat[q4_0],mul_mat[q4_k],quantize_chunk[*],rope,rms_norm,soft_max, ... all bit-identical), which is expected: only the F32 trait entry changed.Walltime could not be measured locally (the sandbox has no
perf), so the macro suite result comes from this PR'scodspeed-macrojob.decode_*[f32]are expected to be unchanged: with a single tokenne11 == 1, so the 2x2 path is not selected.Correctness
test-backend-opsskips the CPU backend when it is the only device, so the kernel was validated against a double-precision reference over 1440 matmul shapes (K in 1...5632 including odd values, M in 1...64, N in 1...32, 1 and 4 threads), on both the AVX-512 (-march=native) and AVX2 builds. Maximum absolute deviation is 3.6e-5 on outputs of magnitude ~90 (~4e-7 relative) - pure float32 re-association noise, the same class of reordering the existing 4-accumulator SIMD reduction already performs.The
nr0 % 2,ne11 % 2and chunk-parity guards inggml_compute_forward_mul_mat()already prevent the 2-row path from crossing tile or dim-1 boundaries, and thetmp[32]staging buffer is already sized for two columns.ggml_compute_forward_mul_mat_id()always passesnrc == 1and is unaffected.Cross-target compile checks of
vec.cpppassed for SSE3, AVX, AVX2, AVX-512, scalar (noGGML_SIMD), aarch64 (NEON, SVE, SVE2), s390x VXE and riscv64rv64gcv.