ggml-cpu: unroll ggml_vec_dot_f16 into four accumulator groups to hide FMA latency - #28
Open
codspeed-hq[bot] wants to merge 1 commit into
Conversation
Process 4*GGML_F16_STEP elements per iteration using four independent accumulator groups in the generic GGML_SIMD path of ggml_vec_dot_f16. This cuts loop iterations (and their counter/branch/index arithmetic) by 4x for the same FMA work while keeping more independent FMA chains in flight to hide FMA latency. The groups are combined before the existing horizontal reduce, so the result matches the original accumulation. A tail loop handles the remaining full GGML_F16_STEP block and the scalar leftover loop is unchanged. The SVE and RISC-V paths are untouched.
Author
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
Optimizes
ggml_vec_dot_f16(ggml/src/ggml-cpu/vec.cpp), the F16 dot-product kernel thatggml_compute_forward_mul_matcalls once per output row for every F16 matrix multiply. It dominates the LM-head logits projection — the largest matmul of every decode step — and any F16 weight/activation path.Change
The generic
GGML_SIMDinner loop (the#elsebranch used by x86 AVX2/F16C and ARM NEON) previously used a single group ofGGML_F16_ARRaccumulators and advanced onlyGGML_F16_STEPelements per iteration. With just 4 in-flight FMA chains the reduction is latency-bound and per-iteration loop overhead is paid once everyGGML_F16_STEPelements.This change processes 4×
GGML_F16_STEPelements per iteration using four independent accumulator groups (sum,sum2,sum3,sum4; 16 accumulators on AVX2, matching the 16 YMM registers), then combines the four groups before the existing horizontal reduce. A tail loop handles any remaining fullGGML_F16_STEPblock and the scalar leftover loop is unchanged. The SVE and RISC-V paths are untouched.This cuts the number of loop iterations — and therefore the counter/branch/index arithmetic — by 4x for the same FMA work, and keeps many independent FMA chains in flight to hide FMA latency.
Correctness
Mathematically equivalent: the four groups accumulate the same products, just partitioned, and are combined before the final horizontal reduction — the same accuracy class as the original 4-accumulator SIMD reduction.
Verified with
test-backend-ops: all 1177MUL_MATtests pass on the CPU backend, including everytype_a=f16case that exercises this kernel (built with the AVX2/FMA/F16C baseline).Performance (CodSpeed, CPU simulation)
Isolated
lm_head[f16]comparison, matched build/scope:lm_head[f16]The
lm_head[q8_0]andlm_head[q4_k]benchmarks (which use different vec_dot kernels) are unchanged — no regressions.