Skip to content

ggml-cpu: x86 AVX512-VNNI repack GEMV/GEMM for Q1_0 and Q2_0 - #86

Merged
khosravipasha merged 2 commits into
prismfrom
feat/cpu-repack-q1q2-x86
Jul 18, 2026
Merged

ggml-cpu: x86 AVX512-VNNI repack GEMV/GEMM for Q1_0 and Q2_0#86
khosravipasha merged 2 commits into
prismfrom
feat/cpu-repack-q1q2-x86

Conversation

@bri-prism

Copy link
Copy Markdown

x86 (AVX512-VNNI) repack GEMV/GEMM for Q1_0 and Q2_0

Adds CPU repack (interleaved multi-row GEMM) support for the low-bit formats on x86. Until now the repack path existed only for Q1_0 on NEON; Q2_0 had none anywhere, so both formats ran batch-flat on x86 — the same GFLOPS at n=1 and n=512 — while q4-family formats gained 2-2.5x from their repack GEMMs.

What's included

  • repack.h / repack.cpp: new block_q2_0x4 layout (4-row interleave, 8-byte chunks so each column's 32 codes stay contiguous), repack function, generic gemv/gemm fallbacks, template instantiations, and selection-table entries routing Q1_0 and Q2_0 to *_4x8_q8_0 on avx512 && avx512_vnni (NEON entries untouched).
  • arch/x86/repack.cpp: AVX512-VNNI gemv+gemm for q1_0_4x8 (existing NEON layout; pshufb + maskz_set1 bit-expand) and q2_0_4x8 (carry-free 2-bit unpack). Both share the structural wins the profiling pointed at: one sum(qy) dpbusd per activation sub-block reused across all 4 columns, per-lane fp32 partials with a single horizontal reduction per output tile.
  • arch-fallback.h: q2_0 generic defines for all non-x86 arches (ARM/riscv builds verified locally).

Measured (EPYC Zen 4, two independent boxes agree within 2%)

Kernel (single-thread, m=4096 k=14336):

n=1 n=8 n=512
q2_0 vec_dot 17.7 GF 17.7 GF 17.7 GF
q2_0 repack 52.6 GF (2.97x) 87.4 GF (4.94x) 87.5 GF (4.94x)
q1_0 vec_dot 68.7 GF 68.8 GF 68.4 GF
q1_0 repack 71.1 GF (1.04x) 88.8 GF (1.29x) 89.0 GF (1.30x)

End-to-end (llama-bench, t=8, r=3):

model pp512 pp8 tg128
27B Q2_0 2.86 -> 13.3 t/s (4.7x) 2.80 -> 12.3 (4.4x) 2.42 -> 5.85 (2.4x)
8B Q2_0 10.3 -> 48.6 (4.7x) 10.1 -> 45.1 (4.5x) 8.7 -> 20.6 (2.4x)
27B Q1_0 10.5 -> 13.5 (1.29x) 9.8 -> 12.5 (1.27x) 6.75 -> 7.01 (1.04x)

Numerics (stated openly)

  • 8B Q2_0 and 27B Q1_0 greedy 64-token outputs are byte-identical to the non-repack build.
  • 27B Q2_0 diverges at ~token 50 due to fp32 accumulation-order differences (lane-parallel partials vs serial vec_dot). Quantified with llama-perplexity KLD on wikitext-2 (4096 tokens): mean KLD 2.08e-4 — below the ~4.3e-4 measurement noise floor of the KLD harness itself — max 1.07e-2, top-token agreement 99.17%, PPL ratio 1.0013 +/- 0.0011. Same-build control: max 5.1e-5. Bit-exactness is structurally unattainable with a lane-parallel reduction; by the measured-KLD gate this passes.

Known limits / follow-ups

  • Both formats saturate ~88 GF/thread — the shared dpbusd + row-permute inner loop is the next ceiling; a wider tile (8-col interleave or 2-block unroll) is the identified next lever, and is what holds Q1_0 to 1.29x.
  • test-backend-ops does not allocate repack buffers in this tree, so repack kernels have no unit coverage — validated here end-to-end instead (engagement confirmed via verbose load: ~500 tensors repacked, plus the e2e/KLD gates above). Making test-backend-ops exercise extra buffer types is a follow-up worth its own change.
  • Repro logs (bench tables, KLD runs, microbench) archived on the two test boxes under ~/repack-logs/.

Q2_0 previously had no repack path at all and Q1_0 only a NEON one, so
batched CPU mul_mat for both formats fell back to per-row vec_dot on
x86. Add:

- block_q2_0x4 (4-row, 8-byte-chunk interleave) with generic repack,
  gemv and gemm implementations
- AVX512-VNNI gemv/gemm kernels for the existing q1_0 4x8 layout and
  the new q2_0 4x8 layout; sum(qy) is computed once per activation
  sub-block and the horizontal reduction happens once per output tile
- repack type selection on AVX512-VNNI CPUs for both formats
@bri-prism
bri-prism requested a review from khosravipasha July 18, 2026 05:03
@github-actions github-actions Bot added the ggml label Jul 18, 2026
Comment thread ggml/src/ggml-cpu/repack.cpp Fixed
Comment thread ggml/src/ggml-cpu/repack.cpp Fixed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds x86 AVX512-VNNI repacked GEMV/GEMM support for Q1_0 and Q2_0.

Changes:

  • Adds Q2_0 4-row repacking and generic fallbacks.
  • Implements optimized Q1_0/Q2_0 x86 kernels.
  • Adds architecture fallbacks and runtime dispatch.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
ggml/src/ggml-cpu/repack.h Declares Q2_0 layouts and kernels.
ggml/src/ggml-cpu/repack.cpp Implements repacking, fallbacks, templates, and dispatch.
ggml/src/ggml-cpu/arch/x86/repack.cpp Adds AVX512-VNNI kernels.
ggml/src/ggml-cpu/arch-fallback.h Maps generic fallbacks across architectures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Cast to size_t/int64_t before the nrow*nblocks and i*nblocks
multiplications so they cannot overflow int before widening.
Resolves CodeQL alerts 630/631.

@khosravipasha khosravipasha left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM,

We can polish later and upstream the groups size 64 version in llama.cpp.

Doing another prebuilt release so merging this now.

@khosravipasha
khosravipasha merged commit 9fcaed7 into prism Jul 18, 2026
14 of 30 checks passed
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.

4 participants