Skip to content

ggml-cpu: enable Q2_0 VNNI kernel on AVX-VNNI-only CPUs#76

Open
gondoi wants to merge 1 commit into
PrismML-Eng:prismfrom
gondoi:cpu-avx-vnni-q2_0
Open

ggml-cpu: enable Q2_0 VNNI kernel on AVX-VNNI-only CPUs#76
gondoi wants to merge 1 commit into
PrismML-Eng:prismfrom
gondoi:cpu-avx-vnni-q2_0

Conversation

@gondoi

@gondoi gondoi commented Jul 15, 2026

Copy link
Copy Markdown

Problem

The Q2_0 ternary fast path in ggml_vec_dot_q2_0_q8_0 (ggml/src/ggml-cpu/arch/x86/quants.c) is gated on #if defined(__AVX512VNNI__) && defined(__AVX512VL__). That gate is stricter than the code requires: CPUs with AVX-VNNI but no AVX512 — notably Intel Alder Lake and Raptor Lake client parts, where AVX512 is fused off — fall through to the scalar loop and leave most of the available throughput on the table.

Change

Extend the gate to (defined(__AVX512VNNI__) && defined(__AVX512VL__)) || defined(__AVXVNNI__) and select the dot-product intrinsic via a local macro:

  • AVX512-VNNI + VL: _mm256_dpbusd_epi32 (unchanged)
  • AVX-VNNI only: _mm256_dpbusd_avx_epi32

Why this is safe

  • The kernel body uses only 256-bit (__m256i) and 128-bit registers — no 512-bit state, no masking, nothing AVX512-specific.
  • The two intrinsics emit the same vpdpbusd operation on ymm registers; the intrinsic name (and VEX vs EVEX encoding) is the only difference. Numeric behavior is bit-identical.
  • The existing AVX512 configuration compiles the exact same code path as before; CPUs without any VNNI still take the scalar fallback.

Measured results

On an i7-12650H (Alder Lake, AVX-VNNI, no AVX512) running Ternary-Bonsai-27B Q2_g64 (7.6 GB): stock scalar path decodes at 0.54 tok/s; with this patch the vectorized path is enabled, giving ~8x decode speedup, approaching the memory-bandwidth limit.

Enabling it

The build system already supports this: -DGGML_AVX_VNNI=ON (which defines __AVXVNNI__, see ggml/src/ggml-cpu/CMakeLists.txt) or the default -march=native on a supporting CPU enables the path automatically.

Compile checks

Both configurations build cleanly (gcc 15.2, -DGGML_NATIVE=OFF -DGGML_AVX=ON -DGGML_AVX2=ON -DGGML_FMA=ON -DGGML_F16C=ON, with and without -DGGML_AVX_VNNI=ON). Disassembly confirms vpdpbusd is emitted in ggml_vec_dot_q2_0_q8_0 for the VNNI build and absent (scalar fallback) in the default build.

🤖 Generated with Claude Code

The fast path in ggml_vec_dot_q2_0_q8_0 was gated on
__AVX512VNNI__ && __AVX512VL__, which is stricter than needed: the
kernel body uses only 256-bit registers, so it runs unchanged on CPUs
that have AVX-VNNI but no AVX512 (e.g. Intel Alder Lake / Raptor Lake).
The only difference is the intrinsic name: _mm256_dpbusd_avx_epi32
instead of _mm256_dpbusd_epi32.

Extend the gate with defined(__AVXVNNI__) and select the intrinsic via
a local macro. Builds with -DGGML_AVX_VNNI=ON (or -march=native on
supporting CPUs) now take the vectorized path.

Measured on i7-12650H (Raptor/Alder Lake, no AVX512) with
Ternary-Bonsai-27B Q2_g64: ~8x decode speedup vs the scalar fallback,
approaching the memory-bandwidth limit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the ggml label Jul 15, 2026
@khosravipasha
khosravipasha requested a review from bri-prism July 18, 2026 19:28
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