Skip to content

bench: decode-regime GEMV bandwidth vs the read ceiling, with a frozen A/B baseline - #950

Open
terrizoaguimor wants to merge 2 commits into
JustVugg:devfrom
terrizoaguimor:bench/gemv-stream-regime
Open

bench: decode-regime GEMV bandwidth vs the read ceiling, with a frozen A/B baseline#950
terrizoaguimor wants to merge 2 commits into
JustVugg:devfrom
terrizoaguimor:bench/gemv-stream-regime

Conversation

@terrizoaguimor

Copy link
Copy Markdown
Contributor

bench_idot measures the idot kernels at their warm-cache compute ceiling. Decode lives in the
opposite regime: expert weights exceed every cache, each token streams them from RAM at
~1 MAC/byte, and the number that decides any kernel work is how close the real row loops get to
the machine's read bandwidth. This bench measures that β€” the real quant.h row loops, their own
internal OMP, over a working set that defeats the LLC, with a parallel-read ceiling in the same
process so the ratio cancels host noise.

What it measured on the way in

Two AVX2-only cloud hosts (no VNNI), 2/4/8 threads, medians of 5, ratios within one pass:

share of the same-thread read ceiling
idot int8 (dot_i8i8) ~73%, every width
idot int4 (dot_i4i8, the GLM fmt-4 decode kernel) ~47%, every width

So on the most common consumer ISA, int4's halved bytes buy 1.28–1.46Γ— tokens instead of ~2Γ—
β€” the unpack path eats the rest. Three follow-ups, all in the bench:

  • Multi-accumulator restructure of the plain-AVX2 branch (mirroring what the AVX-VNNI and
    NEON siblings already carry): 1.00Γ— cold, exactly nothing. The VNNI branch's own comment
    names its win β€” breaking a ~5-cycle vpdpbusd chain β€” and the plain-AVX2 chain is a 1-cycle
    add the OoO already hides. Discarded; recorded here so nobody re-walks it.
  • Deinterleaved-x candidate: split x even/odd once per call (amortised over every row of
    the projection), so lo/hi nibbles are used straight after and/srli β€” no unpacks, no lane
    insert. Warm ALU ceiling 1.25–1.54Γ—; bit-exact against the live kernel on sampled rows
    plus I=1..200 ragged tails, checked inline every run.
  • Cold, on shared vCPUs: only 1.02–1.09Γ—. And there is the cap on what cloud hardware can
    say: the read ceiling scaled with thread count (30β†’60β†’110 GB/s at 2/4/8 threads) β€” a guest
    never sees the physical RAM roof, so whether the candidate pays at production thread counts
    is a question only physical AVX2-only silicon can answer (Zen 1–3, pre-Ice-Lake Intel β€”
    the Zen3 data: SMT collapse (2.3Γ— at 16 threads), Β±15% run variance, PIN_GB starves LRU β€” HIP/gfx1100 + NVMeΒ #718 5950X is exactly the right machine).

What this PR adds

The bench only β€” no production code changes. It ships a frozen verbatim copy of today's
plain-AVX2 dot_i4i8 (any future kernel change A/Bs against it in one process) and the
deinterleaved candidate, both gated for bit-exactness inline. Build on demand, not in
TEST_BINS, per the bench_idot / bench_topp convention:

make tests/bench_gemv_stream ARCH=native && OMP_NUM_THREADS=N ./tests/bench_gemv_stream

If a physical-silicon run shows the candidate holding its warm-side win in the cold regime, I
will send the quant.h change as its own PR β€” matmul_i4_idot plus the three PIPE call sites
in colibri.c, with test_idot extended to cover the deinterleaved pair. If it collapses to
the cloud numbers, the frozen baseline still leaves the next person a one-command A/B and this
table as the reason nothing was changed.

πŸ€– Generated with Claude Code

terrizoaguimor and others added 2 commits August 11, 2026 10:51
…n A/B baseline

The existing bench_idot measures the idot kernels' warm-cache compute ceiling.
Decode lives in the opposite regime: expert weights exceed every cache, each
token streams them from RAM at ~1 MAC/byte, and the question that decides any
kernel work is how close the real row loops get to the machine's read bandwidth.

Measured on two AVX2-only cloud hosts (no VNNI), 2/4/8 threads, medians of 5,
all ratios within one pass: idot int8 extracts ~73% of the same-thread read
ceiling; idot int4 -- the GLM fmt=4 decode kernel -- extracts ~47% at every
width, so int4's halved bytes buy 1.28-1.46x tokens instead of ~2x. A
multi-accumulator restructure of the plain-AVX2 branch (mirroring the VNNI and
NEON siblings) measured 1.00x cold: the madd->add chain is 1c, there was
nothing to break. A deinterleaved-x candidate (no unpacks, no lane insert;
x split even/odd once per call, amortised over every row) lifts the warm ALU
ceiling 1.25-1.54x but cold only 1.02-1.09x on shared vCPUs -- whose read
ceiling scales with thread count and never shows the physical RAM roof, so
virtualized hardware cannot answer whether that candidate pays at production
thread counts on real silicon.

The bench ships both: a frozen verbatim copy of today's plain-AVX2 dot_i4i8
(any future kernel change A/Bs against it in-process, host noise cancels) and
the deinterleaved candidate, gated inline for bit-exactness against the live
kernel on sampled rows plus I=1..200 ragged tails. Build on demand, not in
TEST_BINS, per the bench_idot / bench_topp convention.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…n A/B baseline

The existing bench_idot measures the idot kernels' warm-cache compute ceiling.
Decode lives in the opposite regime: expert weights exceed every cache, each
token streams them from RAM at ~1 MAC/byte, and the question that decides any
kernel work is how close the real row loops get to the machine's read bandwidth.

Measured on two AVX2-only cloud hosts (no VNNI), 2/4/8 threads, medians of 5,
all ratios within one pass: idot int8 extracts ~73% of the same-thread read
ceiling; idot int4 -- the GLM fmt=4 decode kernel -- extracts ~47% at every
width, so int4's halved bytes buy 1.28-1.46x tokens instead of ~2x. A
multi-accumulator restructure of the plain-AVX2 branch (mirroring the VNNI and
NEON siblings) measured 1.00x cold: the madd->add chain is 1c, there was
nothing to break. A deinterleaved-x candidate (no unpacks, no lane insert;
x split even/odd once per call, amortised over every row) lifts the warm ALU
ceiling 1.25-1.54x but cold only 1.02-1.09x on shared vCPUs -- whose read
ceiling scales with thread count and never shows the physical RAM roof, so
virtualized hardware cannot answer whether that candidate pays at production
thread counts on real silicon.

The bench ships both: a frozen verbatim copy of today's plain-AVX2 dot_i4i8
(any future kernel change A/Bs against it in-process, host noise cancels) and
the deinterleaved candidate, gated inline for bit-exactness against the live
kernel on sampled rows plus I=1..200 ragged tails. Build on demand, not in
TEST_BINS, per the bench_idot / bench_topp convention.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant