Repository navigation
ggml-cpu(repack): AVX-VNNI Kernel B for Q1_0_g128 4×4 repack (SDE-validated, no real-hardware perf) - #17
Merged
Conversation
Adds AVX-VNNI variants of the 4-row GEMV and true 4x4 GEMM kernels that PR #13 introduced for AVX2-only hosts. Same `block_q1_0_g128x4` repack format (no on-disk format change); the dispatcher in `ggml_gemv_q1_0_g128_4x4_q8_0` and `ggml_gemm_q1_0_g128_4x4_q8_0` prefers Kernel B over Kernel A whenever `__AVXVNNI__` is defined. Per (r_a, r_w) per sub-block, the inner body collapses masked = blendv(zero, qy, mask_w[r_w]) partial = madd(maddubs(ones, masked), ones) row_dot = 2*partial - sum_qy_v (5 ops + 2 shared per qy load) into a single signed-byte dot signed_qy = blendv(neg_qy, qy, mask_w[r_w]) int_acc = dpbusd(zero, ones_b, signed_qy) (2 ops + 1 shared per qy load). Per-sub-block hot-path op count drops from 22 to 9 for the GEMM kernel; same 16-accumulator register pressure profile as the AVX2 path. Validation: * Default Zen 3 / AVX2-only build (`-march=native`): unchanged. Kernel B is excluded at compile time; Kernel A from PR #13 remains the fast path. ctest 50/50 pass. * `-DGGML_AVX_VNNI=ON` build under Intel SDE 9.48 `-adl` (Alder Lake): GEMV (nr=1) + GEMM (nr=4) + GEMM (nr=8) all match the single-row `vec_dot` reference with diff = 0.000000e+00 on every element. End-to-end smoke (`llama-cli` with Bonsai-1.7B) under SDE generates "Paris" correctly for "The capital of France is". Disassembly: 506 `vpdpbusd` instructions in libggml-cpu.so. * No real-hardware perf measurement -- demo VM is AMD EPYC 7763 (Zen 3, no native AVX-VNNI). SDE timing is meaningless. Whoever has Alder Lake / Sapphire Rapids / Zen 4 can bench against the PR #13 Zen 3 baseline of 30.87 t/s pp512 and commit the result next to phase3-end-to-end-zen3-epyc-7763.txt. This change: * docs/avx2-repack-design/06-avx-vnni-kernel-b.md (design + bench recipe + projected uplift discussion) * docs/avx2-repack-design/parity-alderlake-sde-kernel-b.txt (SDE output verbatim with build/run recipe in header) * ggml/src/ggml-cpu/arch/x86/repack.cpp (kernels + dispatcher) AI authorship disclosure: AI-assisted port from PR #11's Phase 2 microbench draft into the repack file, under explicit authorisation from @kennguy3n on the prism private fork (per AGENTS.md / CONTRIBUTING.md preamble added in PR #16). Not intended for upstream `ggml-org/llama.cpp`.
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
3 tasks
kennguy3n
added a commit
that referenced
this pull request
May 1, 2026
…ispatcher * docs(avx2-repack-design): Phase 4 dispatcher closeout (no new code) Phase 4 was originally scoped to add three pieces: 1. Full dispatcher (runtime ISA selection) 2. On-disk repack converter (--repack-q1-g128-avx2 flag in llama-quantize, new GGML_TYPE_Q1_0_G128_AVX2 enum) 3. Cross-arch fallback testing Item (3) was completed in PR #14. This doc closes out (1) and (2). (1) is already infrastructure-complete via GGML_CPU_ALL_VARIANTS=ON + GGML_BACKEND_DL=ON. The build produces per-ISA shared libraries (ggml-cpu-haswell.so, ggml-cpu-alderlake.so, ggml-cpu-skylakex.so, etc.) and the runtime backend loader picks the most capable variant the host CPU supports. Verified via disassembly: $ objdump -d build-variants/bin/libggml-cpu-haswell.so | grep -c vpdpbusd 0 $ objdump -d build-variants/bin/libggml-cpu-alderlake.so | grep -c vpdpbusd 506 Kernel A from PR #13 lands in the haswell variant (no vpdpbusd); Kernel B from PR #17 lands in the alderlake variant (506 vpdpbusd inlined into the public dispatchers). The runtime gate at repack.cpp:3702 (avx2 && !avx512) routes correctly per variant. (2) is intentionally not implemented. The equivalent upstream pattern (GGML_TYPE_Q4_0_4_4 / _4_8 / _8_8) was deprecated and removed upstream because: (a) on-disk size is identical to the unrepacked format -- no storage win; (b) the runtime repack is ~1 ms per tensor, negligible vs model load; (c) each enum entry forces every backend (cuda, metal, vk, ...) to add a code path for a CPU-only optimisation. Adopting the deprecated pattern on prism purely to mirror the original Phase 4 plan would re-introduce the costs upstream already paid down. Decision #1 of 03-design-brief.md ("no on-disk GGUF format changes") was right at the start. This closes the AVX2 repack project. Status table at the bottom of the doc summarises all 7+1 phases / PRs. Note: a full GGML_CPU_ALL_VARIANTS build hits a pre-existing GCC 11.4 break in arch/x86/quants.c:682 (_mm512_setr_epi8 not declared in <immintrin.h> for GCC < 12) that blocks the AVX-512 variants (skylakex / cascadelake / icelake / cannonlake / cooperlake / zen4 / sapphirerapids). This is unrelated to the repack work and already tracked in 04-cross-arch-validation.md. The verification above was constrained to the haswell + alderlake variants (where my work lands); the rest of the dispatcher infrastructure is upstream code that has been in production for years. * docs(avx2-repack-design): fix variant→kernel mapping in recommended-build paragraph Devin Review caught that lines 201-205 of 07-phase4-dispatcher.md contradicted the routing table earlier in the same doc (lines 58-65 and 86-94). Skylake-X has AVX-512, so it routes to the existing single-row AVX-512 vec_dot, not Kernel A. Zen 4 also has AVX-512, so it also routes to vec_dot, not Kernel B. Corrected mapping: Kernel A → Zen 3 (haswell variant) Kernel B → Alder Lake (alderlake variant) vec_dot → Skylake-X / Cascade Lake / Zen 4 / Sapphire Rapids This matches the per-variant routing table at the top of the doc and the analysis at lines 86-94. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
kennguy3n
added a commit
that referenced
this pull request
May 2, 2026
…vx512-vnni-kernel-c
Adds an experimental AVX-512BW+VL+VNNI variant of the Q1_0_g128 4x4
GEMV ("Kernel C") to the microbench harness. Same outer skeleton
as Kernel B (in PR #17), but exploits two AVX-512BW+VL features
that AVX-VNNI alone does not have:
1. _mm256_mask_blend_epi8 consumes the 32-bit qbits register
directly as a __mmask32, eliminating the 5-instruction
shuffle/and/cmpeq sequence Kernel B needs to expand qbits to a
byte mask. Net: -4 ops per (sub-block, weight-row) for the mask
path.
2. EVEX-encoded _mm256_dpbusd_epi32 replaces Kernel B's VEX
_mm256_dpbusd_avx_epi32. Same throughput where both are
available; the new path is reachable on Cascade Lake / Ice Lake
which have AVX-512+VNNI but not AVX-VNNI.
Validated under Intel SDE 9.48 in two configs:
* SDE -icx (Ice Lake): five-way parity. Scalar reference =
single-row AVX2 vec_dot = single-row AVX-512 VNNI vec_dot =
Kernel A 4x4 GEMV = Kernel C 4x4 GEMV (bit-identical FP32 across
all four AVX paths).
* SDE -clx (Cascade Lake): same parity. Cascade Lake is the
canonical host class for Kernel C since it has AVX-512+VNNI but
not AVX-VNNI -- Kernel B cannot compile here.
Structural-perf measurement via SDE -mix (dynamic instruction count
for the same workload, both functions process bit-identical input):
vec_dot_avx512_vnni (single-row, in-tree floor) 4587920 ICOUNT
gemv_4x4_avx512_vnni (Kernel C, microbench) 3768655 ICOUNT
-> Kernel C executes 17.9% fewer instructions for the same work,
a 1.22x structural speedup over the existing AVX-512 path.
gemv_4x4_avx2 (Kernel A, in-tree on AVX2 hosts) 5898600 ICOUNT
-> Kernel C is 1.56x ahead of the AVX2 4x4 GEMM that PR #13 ships,
entirely from the two AVX-512 features above.
Decision: doc-only landing. The dispatcher gate at
ggml/src/ggml-cpu/repack.cpp:3702-3712 is intentionally unchanged.
Reasons documented in 08-avx512-vnni-kernel-c.md:
* Decode-side memory amplification: once the tensor is repacked to
block_q1_0_g128x4, single-row vec_dot is no longer reachable, so
decode (nrows=1) reads 4x more weight bytes than necessary. For
Bonsai-1.7B-Q1_0_g128 the decode rate is the user-perceived
latency, so a regression there would be felt directly.
* No real-hardware data: the demo VM is Zen 3 / AVX2-only. Wiring
the dispatcher to enable repack on AVX-512 hosts should be backed
by a prefill-vs-decode wall-clock comparison on at least one of
{Cascade Lake, Ice Lake, Sapphire Rapids, Zen 4}.
The kernel and its evidence are preserved here so whoever next has
hardware access can pick up the experiment without re-deriving the
design. The doc spells out the workflow for them.
AI authorship disclosed (per AGENTS.md / CONTRIBUTING.md private-fork
preamble, PR #16). Authorised by @kennguy3n in this session.
Co-authored-by: ken <kennguy3n@gmail.com>
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.
Make sure to read the contributing guidelines before submitting a PR
Summary
Adds AVX-VNNI variants of the 4-row GEMV and true 4×4 GEMM kernels that PR #13 introduced for AVX2-only hosts. Same
block_q1_0_g128x4repack format (no on-disk format change); the dispatcher inggml_gemv_q1_0_g128_4x4_q8_0andggml_gemm_q1_0_g128_4x4_q8_0prefers Kernel B over Kernel A whenever__AVXVNNI__is defined.This is Phase 7 of the multi-phase Q1_0_g128 AVX2 repack project (Phase 1 = PR #10, Phase 2 = PR #11, Phase 3 = PR #12 + #13, Phase 5 = PR #14, drop-unpack experiment = PR #15). It lands the AVX-VNNI Kernel B that was drafted in the Phase 2 microbench (PR #11) and deferred at the end of the Phase 3 follow-up plan.
Inner-loop op-count change
Per
(r_a, r_w)per sub-block, the inner body collapses from:(5 vector ops + 2 shared per
qyload forsum_qy_v) into:(2 vector ops + 1 shared per
qyload forneg_qy).Per-sub-block GEMM inner-loop op count: 22 → 9 ops (Kernel A → Kernel B). Register-pressure profile (16
__m256accumulators) and memory-traffic profile (oneblock_q1_0_g128x4load per y-group, oneblock_q8_0x4unpack) are both unchanged.Validation
Default Zen 3 / AVX2-only build (host)
No code change for AVX2-only callers: Kernel B is omitted at compile time when
__AVXVNNI__is undefined, and the dispatcher falls back to Kernel A from PR #13.tests/test-q1-g128-repack-paritypasses nr=1 / nr=4 / nr=8 withdiff = 0.000000e+00on every element — same as before this PR.-DGGML_AVX_VNNI=ONbuild under Intel SDE 9.48-adlFull SDE output committed at
docs/avx2-repack-design/parity-alderlake-sde-kernel-b.txtwith the build/run recipe in the file header.End-to-end smoke under SDE
Token output is correct under SDE. The 1.3 t/s is SDE's dynamic-translation overhead, not a real measurement (SDE translates
vpdpbusd_avxinto host-native sequences and timing under emulation is meaningless).Disassembly cross-check
Both GEMV + GEMM 4-rows variants are inlined into the public dispatchers by GCC 11.4 at
-O3. Novpdpbusdinstructions in the default Zen 3 build (kernel correctly excluded at compile time).What this change does NOT include
phase3-end-to-end-zen3-epyc-7763.txt. The PR description for the Phase-2 microbench (PR tools/microbench: Phase 2 harness for Q1_0_g128 AVX2/AVX-VNNI repack #11) projected ~70 t/s pp512 on Alder Lake; that number is unverified on real hardware and may overstate. The doc atdocs/avx2-repack-design/06-avx-vnni-kernel-b.mdcovers the methodology.__AVX512VNNI__rather than__AVXVNNI__. AVX-512 hosts already use the existing single-rowvec_dotAVX-512 path; a 4×4 AVX-512-VNNI kernel would be a follow-up. Note the cross-arch validation (PR docs(avx2-repack-design): Phase 5 cross-arch validation of PR #13 #14) flagged a pre-existing GCC 11.4 build break inQ2_0AVX-512 unrelated to this work.__AVXVNNI__. Phase 4 (the on-disk repack converter +--repack-q1-g128-avx2flag) will likely add runtime detection alongside.Files changed (this PR's net diff)
ggml/src/ggml-cpu/arch/x86/repack.cpp— Kernel B GEMV + GEMM 4-rows + dispatcher branch (+234 LOC, gated#if defined(__AVXVNNI__)).docs/avx2-repack-design/06-avx-vnni-kernel-b.md— design + op-count table + bench recipe + projected uplift discussion (+204 LOC, new).docs/avx2-repack-design/parity-alderlake-sde-kernel-b.txt— verbatim SDE Alder Lake parity output (+42 LOC, new).Review & Testing Checklist for Human
docs/avx2-repack-design/06-avx-vnni-kernel-b.md. Sanity-check the inner-loop op-count diff (5 ops → 2 ops per (r_a, r_w) per sub-block).cmake --build build && ./build/bin/test-q1-g128-repack-parityshould still produce diff = 0 on every element.objdump -d build/bin/libggml-cpu.so | grep -c vpdpbusdshould be 0.-DGGML_AVX_VNNI=ONand re-runsde64 -adl -- ./build-vnni/bin/test-q1-g128-repack-parityto reproduce the parity output committed in this PR.llama-bench -t 4 -p 256,512,1024 -n 32 -r 3and commit the numbers asphase7-end-to-end-<host>.txtnext to the Phase 3 numbers.Notes
AGENTS.md/CONTRIBUTING.md(with the prism private-fork preamble added in PR docs: clarify AI policy for prism private fork (preamble note in AGENTS.md / CONTRIBUTING.md) #16), this is the prism private fork. The kernel port from PR tools/microbench: Phase 2 harness for Q1_0_g128 AVX2/AVX-VNNI repack #11's Phase 2 microbench draft intoarch/x86/repack.cpp, the dispatcher wiring, and the design doc are AI-assisted under explicit authorisation from @kennguy3n. Parity validation under SDE was run on the live build artefact; the captured output is committed verbatim. Not intended for upstreamggml-org/llama.cpp.--repack-q1-g128-avx2flag inllama-quantize).Link to Devin session: https://uney.devinenterprise.com/sessions/576d78b01f9b4389b375033162f7b7b4