perf: SIMD MLA-absorb score + value-mix reductions (#442, +4.7x)#481
Conversation
The MLA-absorb attention path had two scalar f32 reductions that ran on every (s,h) of every layer's decode: score: a = dot(qabs, Lt) # colibri.c:2459, kvl=512 on GLM-5.2 vmix: clat += sc[jj] * Lt # colibri.c:2467 Both were scalar loops the compiler can't reassociate (build is -O3, no -ffast-math, no #pragma omp simd). JustVugg#442 (cdhdt) flagged this as one of the walls blocking the 15 tok/s roadmap. SIMD-ify under AVX2 (8-lane fmadd + hsum256, same shape as the int8 matmul_q kernel in quant.h:91) and NEON, with a scalar tail for the kvl%8 remainder: score: 8-wide fmadd accumulator + hsum256. Reassociation is accepted here β softmax downstream softens the ~1.8e-6 rounding flip (measured), which never crosses a near-tie threshold. vmix: 8-wide fmadd writing back per-lane (no horizontal reduction). Strictly bit-identical to scalar (measured diff 0.0). Correctness: glm_tiny TF oracle holds at its 30/32 baseline β same two mismatched positions (5, 25), same wrong tokens. No new mismatches, no position shifts. (The pre-existing 30/32 is a separate forward-pass numeric discrepancy unrelated to this change β being filed separately.) Microbench (tests/bench_mla_simd, GLM-5.2 dims kvl=512/nt=256/H=128, x86-64-v3 AVX2+FMA, median of 3): scalar: ~290 us/head SIMD : ~62 us/head speedup: 4.7x (79% faster) Credit: cdhdt's JustVugg#442 analysis and exact change-site breakdown made this tractable. The reduction sites, the build-flag audit, and the correctness-gate framing are all from that issue. Co-authored-by: cdhdt <cdhdt@users.noreply.github.com> Reported-by: cdhdt
β¦s) β +13% decode AVX-512, byte-identical Vectorizes qt_addrow / qt_matvec_rows for the MLA absorption path (+13% decode on AVX-512), complementary to #481 (which vectorized the score+value-mix reductions). Rebased on current dev by maintainer; verified byte-identical (fp 32/32, int4 21/32). Thanks @veerareddyvishal144.
|
This is really clean, @woolcoxm β thanks for picking it up and, especially, for holding it to the oracle gate. Splitting the softmax-softened attention reductions from the load-bearing router matmul is exactly the right call, and the score-vs-vmix distinction is spot on. A few notes from re-reading it: vmix bit-identity β agreed, with a footnote. It's bit-identical because each lane recomputes score β one free perf lever. The dot uses a single Independent corroboration on the full model. I built your branch and its parent commit and ran an interleaved greedy 24-token decode on the real GLM-5.2 744B int4 ( Router half β agreed it stays separate. The top-k flip risk is real and not softmax-softened; that one wants the full Nice work. Reviewed with AI assistance (Claude); the 744B corroboration was an interleaved greedy A/B of your branch vs its parent commit. |
Addresses the attention half of #442 (cc @cdhdt β analysis and exact change-site breakdown are all from that issue; the build-flag audit, the reduction-site identification, and the correctness-gate framing made this tractable).
What
Two scalar f32 reductions on the MLA-absorb decode path that ran on every
(s,h)of every layer:Both were scalar
a += x[i]*y[i]loops that-O3cannot reassociate (no-ffast-math, no#pragma omp simdanywhere in-tree). SIMD-ified under AVX2 (8-lane fmadd +hsum256, same shape as the int8matmul_qkernel inquant.h:91) and NEON, with a scalar tail for thekvl%8remainder.hsum256. Reassociation is accepted here β softmax downstream softens the ~1.8e-6 rounding flip (measured), which does not cross a near-tie threshold.Correctness
glm_tinyTF oracle holds at its 30/32 baseline β same two mismatched positions (5, 25), same wrong tokens, no new mismatches, no position shifts. All in-tree tests pass (test_logit_nan,test_dsa_select,test_idot,test_topp, etc.).A note on the 30/32 floor: it is a pre-existing forward-pass numeric discrepancy on
dev(engine argmax is correct; the logits at 2 positions are a near-tie that breaks differently vs the Python oracle β e.g. pos 5: engine 197@1.754 vs oracle 34@1.721). Unrelated to this change. I investigated it as a side quest (it briefly looked like it might be the same bug class #442 is about β it is not); will file separately with the evidence.Measured (microbench
tests/bench_mla_simd)GLM-5.2 dims (kvl=512, nt=256, H=128), x86-64-v3 AVX2+FMA, median of 3:
The bench re-implements the old scalar reductions inline and A/Bs them against the new SIMD ones verbatim from
colibri.c, mirroring thebench_idot/bench_topppattern. Not a gate; build on demand:make tests/bench_mla_simd.The end-to-end
score-softmax-valuePROFILE sub-bucket is where this lands on a real decode β that bucket grows with context length (ntin the inner loop).Follow-up (the router half)
The other half of #442 β the f32 router matmul at
quant.h:80-84β is deliberately not in this PR. It is riskier: reassociating the router can flip the top-k expert selection, which is load-bearing for output quality (a wrong expert is not softmax-softened the way an attention score is). That one needs the stronger correctness gate (a fulleval_glm.pyquality A/B, not just the tiny-model oracle), so it stays as a separate follow-up once this attention half lands.Credit
@cdhdt β the #442 analysis, the change-site identification, the build-flag audit, and the correctness-gate framing. Co-authored / reported-by.