Skip to content

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
masterfrom
codspeed-optim-unroll-ggml-vec-dot-f16-into-four-accumulator-grou-1785215110005
Open

ggml-cpu: unroll ggml_vec_dot_f16 into four accumulator groups to hide FMA latency#28
codspeed-hq[bot] wants to merge 1 commit into
masterfrom
codspeed-optim-unroll-ggml-vec-dot-f16-into-four-accumulator-grou-1785215110005

Conversation

@codspeed-hq

@codspeed-hq codspeed-hq Bot commented Jul 28, 2026

Copy link
Copy Markdown

Summary

Optimizes ggml_vec_dot_f16 (ggml/src/ggml-cpu/vec.cpp), the F16 dot-product kernel that ggml_compute_forward_mul_mat calls 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_SIMD inner loop (the #else branch used by x86 AVX2/F16C and ARM NEON) previously used a single group of GGML_F16_ARR accumulators and advanced only GGML_F16_STEP elements per iteration. With just 4 in-flight FMA chains the reduction is latency-bound and per-iteration loop overhead is paid once every GGML_F16_STEP elements.

This change processes GGML_F16_STEP elements 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 full GGML_F16_STEP block 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 1177 MUL_MAT tests pass on the CPU backend, including every type_a=f16 case that exercises this kernel (built with the AVX2/FMA/F16C baseline).

Performance (CodSpeed, CPU simulation)

Isolated lm_head[f16] comparison, matched build/scope:

Benchmark BASE HEAD Change
lm_head[f16] 481.1 ms 436.7 ms +10.16%

The lm_head[q8_0] and lm_head[q4_k] benchmarks (which use different vec_dot kernels) are unchanged — no regressions.

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.
@github-actions github-actions Bot added the ggml label Jul 28, 2026
@codspeed-hq

codspeed-hq Bot commented Jul 28, 2026

Copy link
Copy Markdown
Author

Merging this PR will not alter performance

✅ 28 untouched benchmarks


Comparing codspeed-optim-unroll-ggml-vec-dot-f16-into-four-accumulator-grou-1785215110005 (64adf7e) with master (46819c9)

Open in CodSpeed

@codspeed-hq
codspeed-hq Bot marked this pull request as ready for review July 28, 2026 05:43
@codspeed-hq
codspeed-hq Bot requested a review from coco-speed July 28, 2026 05:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant