Conversation
Kernel benchmarks (M4, ZP_BF16_gs64, criterion median µs)(4096, 4096) — 8 MB, fits SLC
(14336, 4096) M=1 — 28 MB, 5-rep verification
LUT 2.7% faster, within noise. No regression at this shape/M. (Earlier sweep reported +275% for this case — turned out to be a E2E LFM2.5 4-bit (n=15, M4)
Decode regresses 1.8–3.5% across both formats — small but consistent. |
|
AWQ + LUT[256]
|
|
⏺ ## QMM (BM-matched: BM=8 for M<48, BM=64 for M≥48) — Apple M4 Baseline is AWQ-LUT[256]...
QMV (M ∈ {1, 2, 4}, 6 shapes) — Apple M4
|
|
⏺ ## QMV vs scalar-AWQ (M ∈ {1, 2, 4}, 6 shapes) — Apple M4
QMM vs scalar-AWQ (M ∈ {5..128}, 2 shapes) — Apple M4
|
…102;102;102m4�[39m�[38;2;102;102;102m-�[39mbit�[38;2;187;187;187m �[39mLUT�[38;2;187;187;187m �[39mzero�[38;2;102;102;102m-�[39mpoint�[38;2;187;187;187m �[39mvariant�[38;2;187;187;187m �[39malongside�[38;2;187;187;187m �[39mE4M3 Co�[38;2;102;102;102m-�[39mAuthored�[38;2;102;102;102m-�[39mBy:�[38;2;187;187;187m �[39mClaude�[38;2;187;187;187m �[39mOpus�[38;2;187;187;187m �[39m�[38;2;102;102;102m4.7�[39m�[38;2;187;187;187m �[39m(�[38;2;102;102;102m1�[39mM�[38;2;187;187;187m �[39mcontext)�[38;2;187;187;187m �[39m�[38;2;102;102;102m<�[39mnoreply@anthropic�[38;2;102;102;102m.�[39mcom�[38;2;102;102;102m>�[39m
…102;102;102m/�[39mZp�[38;2;187;187;187m �[39mvariants�[38;2;187;187;187m �[39mvs�[38;2;187;187;187m �[39mQmvFast�[38;2;102;102;102m/�[39mAWQ�[38;2;187;187;187m �[39macross�[38;2;187;187;187m �[39mM Extend�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39mcommitted�[38;2;187;187;187m �[39mqmm_lut�[38;2;102;102;102m/�[39mqmv_lut�[38;2;187;187;187m �[39mharness�[38;2;187;187;187m �[39mto�[38;2;187;187;187m �[39mmeasure�[38;2;187;187;187m �[39mall�[38;2;187;187;187m �[39mfour�[38;2;187;187;187m �[39mNF4 variants�[38;2;187;187;187m �[39m(Constant,�[38;2;187;187;187m �[39mTg,�[38;2;187;187;187m �[39mE4M3,�[38;2;187;187;187m �[39mZp)�[38;2;187;187;187m �[39mper�[38;2;187;187;187m �[39mcell�[38;2;187;187;187m �[39magainst�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39mproduction baselines:�[38;2;187;187;187m �[39mQmvFast�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mfor�[39;00m�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39mdecode�[38;2;187;187;187m �[39mQMV�[38;2;187;187;187m �[39msweep�[38;2;187;187;187m �[39m(M�[38;2;102;102;102m=�[39m�[38;2;102;102;102m1.�[39m�[38;2;102;102;102m.�[39m�[38;2;102;102;102m4�[39m)�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mand�[39;00m�[38;2;187;187;187m �[39mAWQ�[38;2;102;102;102m-�[39mint4 QmmTransposed�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mfor�[39;00m�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39mprefill�[38;2;187;187;187m �[39mQMM�[38;2;187;187;187m �[39msweep�[38;2;187;187;187m �[39m(M�[38;2;102;102;102m=�[39m�[38;2;102;102;102m5�[39m�[38;2;102;102;102m/�[39m�[38;2;102;102;102m16�[39m�[38;2;102;102;102m/�[39m�[38;2;102;102;102m32�[39m�[38;2;102;102;102m/�[39m�[38;2;102;102;102m64�[39m�[38;2;102;102;102m/�[39m�[38;2;102;102;102m128�[39m),�[38;2;187;187;187m �[39mon�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39mtwo existing�[38;2;187;187;187m �[39mreal�[38;2;187;187;187m �[39mshapes�[38;2;187;187;187m �[39m(�[38;2;102;102;102m2048�[39mx2048,�[38;2;187;187;187m �[39m�[38;2;102;102;102m2560�[39mx6912)�[38;2;102;102;102m.�[39m�[38;2;187;187;187m �[39mE4M3�[38;2;187;187;187m �[39mscales�[38;2;187;187;187m �[39mare�[38;2;187;187;187m �[39mbuilt�[38;2;187;187;187m �[39mby �[38;2;170;34;255mround�[39m�[38;2;102;102;102m-�[39mtripping�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39msame�[38;2;187;187;187m �[39mf32�[38;2;187;187;187m �[39mscales�[38;2;187;187;187m �[39mthrough�[38;2;187;187;187m �[39mf32_to_e4m3;�[38;2;187;187;187m �[39mZp�[38;2;187;187;187m �[39muses�[38;2;187;187;187m �[39mrealistic packed�[38;2;187;187;187m �[39m�[38;2;102;102;102m4�[39m�[38;2;102;102;102m-�[39mbit�[38;2;187;187;187m �[39mzero�[38;2;102;102;102m-�[39mpoint�[38;2;187;187;187m �[39mindices�[38;2;102;102;102m.�[39m�[38;2;187;187;187m �[39mSame�[38;2;187;187;187m �[39mpick_tile()�[38;2;187;187;187m �[39mtiling�[38;2;187;187;187m �[39mapplied�[38;2;187;187;187m �[39mto�[38;2;187;187;187m �[39mevery NF4�[38;2;187;187;187m �[39mvariant�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mfor�[39;00m�[38;2;187;187;187m �[39mapples�[38;2;102;102;102m-�[39mto�[38;2;102;102;102m-�[39mapples�[38;2;187;187;187m �[39mQMM�[38;2;102;102;102m.�[39m�[38;2;187;187;187m �[39mFormat�[38;2;187;187;187m �[39mconfound�[38;2;187;187;187m �[39m(QmvFast�[38;2;187;187;187m �[39masymmetric int4�[38;2;187;187;187m �[39mvs�[38;2;187;187;187m �[39mNF4�[38;2;187;187;187m �[39mcodebook)�[38;2;187;187;187m �[39mannotated�[38;2;187;187;187m �[39m�[38;2;170;34;255;01min�[39;00m�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39mQMV�[38;2;187;187;187m �[39moutput�[38;2;102;102;102m.�[39m Co�[38;2;102;102;102m-�[39mAuthored�[38;2;102;102;102m-�[39mBy:�[38;2;187;187;187m �[39mClaude�[38;2;187;187;187m �[39mOpus�[38;2;187;187;187m �[39m�[38;2;102;102;102m4.7�[39m�[38;2;187;187;187m �[39m(�[38;2;102;102;102m1�[39mM�[38;2;187;187;187m �[39mcontext)�[38;2;187;187;187m �[39m�[38;2;102;102;102m<�[39mnoreply@anthropic�[38;2;102;102;102m.�[39mcom�[38;2;102;102;102m>�[39m
…g�[38;2;187;187;187m �[39m�[38;2;102;102;102m4�[39m�[38;2;102;102;102m-�[39mway�[38;2;187;187;187m �[39mNF4�[38;2;187;187;187m �[39mvs�[38;2;187;187;187m �[39mzp�[38;2;102;102;102m-�[39mscalar�[38;2;187;187;187m �[39mbench Rewrite�[38;2;187;187;187m �[39mqmm_lut_bench�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mto�[39;00m�[38;2;187;187;187m �[39mencode�[38;2;187;187;187m �[39mN�[38;2;187;187;187m �[39mdispatches�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mof�[39;00m�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39msame�[38;2;187;187;187m �[39mkernel�[38;2;187;187;187m �[39m�[38;2;170;34;255;01minto�[39;00m�[38;2;187;187;187m �[39mone command�[38;2;187;187;187m �[39mbuffer�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mand�[39;00m�[38;2;187;187;187m �[39mdivide�[38;2;187;187;187m �[39mgpu_execution_time�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mby�[39;00m�[38;2;187;187;187m �[39mN,�[38;2;187;187;187m �[39mamortizing�[38;2;187;187;187m �[39mfixed per�[38;2;102;102;102m-�[39mCB�[38;2;187;187;187m �[39mGPU�[38;2;187;187;187m �[39moverhead.�[38;2;187;187;187m �[39mBaseline�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mis�[39;00m�[38;2;187;187;187m �[39mnow�[38;2;187;187;187m �[39mzp�[38;2;102;102;102m-�[39mscalar�[38;2;187;187;187m �[39mint4�[38;2;187;187;187m �[39m(QmvFast�[38;2;102;102;102m/�[39m QmmTransposed,�[38;2;187;187;187m �[39muse_zero_points�[38;2;102;102;102m=�[39m�[38;2;170;34;255;01mtrue�[39;00m,�[38;2;187;187;187m �[39muse_mlx_quant�[38;2;102;102;102m=�[39m�[38;2;170;34;255;01mfalse�[39;00m,�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mno�[39;00m�[38;2;187;187;187m �[39mbias); challengers�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mare�[39;00m�[38;2;187;187;187m �[39mnf4�[38;2;187;187;187m �[39m�[38;2;102;102;102m/�[39m�[38;2;187;187;187m �[39mnf4�[38;2;102;102;102m-�[39me4m3�[38;2;187;187;187m �[39m�[38;2;102;102;102m/�[39m�[38;2;187;187;187m �[39mnf4�[38;2;102;102;102m-�[39m�[38;2;102;102;102m4�[39m�[38;2;0;0;255mbit�[39m�[38;2;102;102;102m-�[39mlut�[38;2;187;187;187m �[39mreported�[38;2;187;187;187m �[39m�[38;2;170;34;255;01mas�[39;00m�[38;2;187;187;187m �[39mΔ�[38;2;102;102;102m%�[39m�[38;2;187;187;187m �[39mvs�[38;2;187;187;187m �[39mbaseline. Passes�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39mmagnitude�[38;2;187;187;187m �[39m�[38;2;102;102;102m+�[39m�[38;2;187;187;187m �[39mdirection�[38;2;187;187;187m �[39msanity�[38;2;187;187;187m �[39mgates�[38;2;187;187;187m �[39magainst�[38;2;187;187;187m �[39mthe�[38;2;187;187;187m �[39mtrusted�[38;2;187;187;187m �[39mM4 reference�[38;2;187;187;187m �[39m�[38;2;0;0;255mtable�[39m. Co�[38;2;102;102;102m-�[39mAuthored�[38;2;102;102;102m-�[39m�[38;2;170;34;255;01mBy�[39;00m:�[38;2;187;187;187m �[39mClaude�[38;2;187;187;187m �[39mOpus�[38;2;187;187;187m �[39m�[38;2;102;102;102m4.7�[39m�[38;2;187;187;187m �[39m(�[38;2;102;102;102m1�[39mM�[38;2;187;187;187m �[39mcontext)�[38;2;187;187;187m �[39m�[38;2;102;102;102m<�[39mnoreply�[38;2;184;134;11m@anthropic�[39m.com�[38;2;102;102;102m>�[39m
…2;187;187;187m �[39mSPECIALIZE�[38;2;187;187;187m �[39m�[38;2;102;102;102m+�[39m�[38;2;187;187;187m �[39m�[38;2;102;102;102m3�[39m�[38;2;102;102;102m-�[39mway�[38;2;187;187;187m �[39mscalar�[38;2;102;102;102m/�[39mawq�[38;2;102;102;102m-�[39mlut256�[38;2;102;102;102m/�[39mnf4�[38;2;187;187;187m �[39mbench Co�[38;2;102;102;102m-�[39mAuthored�[38;2;102;102;102m-�[39m�[38;2;170;34;255;01mBy�[39;00m:�[38;2;187;187;187m �[39mClaude�[38;2;187;187;187m �[39mOpus�[38;2;187;187;187m �[39m�[38;2;102;102;102m4.7�[39m�[38;2;187;187;187m �[39m(�[38;2;102;102;102m1�[39mM�[38;2;187;187;187m �[39mcontext)�[38;2;187;187;187m �[39m�[38;2;102;102;102m<�[39mnoreply�[38;2;184;134;11m@anthropic�[39m.com�[38;2;102;102;102m>�[39m
…6�[38;2;187;187;187m �[39m(byte�[38;2;102;102;102m-�[39mbatched�[38;2;187;187;187m �[39mhalf2�[38;2;187;187;187m �[39m�[38;2;102;102;102m256�[39m�[38;2;102;102;102m-�[39mLUT)�[38;2;187;187;187m �[39m�[38;2;102;102;102m+�[39m�[38;2;187;187;187m �[39mcorrectness�[38;2;187;187;187m �[39m�[38;2;102;102;102m+�[39m�[38;2;187;187;187m �[39mbench Co�[38;2;102;102;102m-�[39mAuthored�[38;2;102;102;102m-�[39m�[38;2;170;34;255;01mBy�[39;00m:�[38;2;187;187;187m �[39mClaude�[38;2;187;187;187m �[39mOpus�[38;2;187;187;187m �[39m�[38;2;102;102;102m4.7�[39m�[38;2;187;187;187m �[39m(�[38;2;102;102;102m1�[39mM�[38;2;187;187;187m �[39mcontext)�[38;2;187;187;187m �[39m�[38;2;102;102;102m<�[39mnoreply�[38;2;184;134;11m@anthropic�[39m.com�[38;2;102;102;102m>�[39m
NF4 vs scalar int4 — short, clear, with QMM (Apple M4, reproduced)
Decode (QMV)
Prefill (QMM)
* Why these M=1 cells are less reliable (not "noise" hand-waving — here's the cause): at M=1 these small matrices run in only ~15–20 µs, so absolute time is dominated by GPU clock-ramp / kernel-launch jitter and the % vs scalar swings run-to-run (e.g. LFM-2048 M=1 measured +29% / +36% / +71% across three independent runs; the table shows the canonical-run value). Direction is consistent (NF4 always neutral-to-slower at M=1, never faster) but treat the exact M=1 small-shape % as ±high. All M≥2 and Llama cells are stable (σ small) and trustworthy. The story in three lines
|
Adds a third dequant mode (use_nf4 SPECIALIZE) to QuantizedMatmulQmvFast: 16-entry NF4 codebook lookup, scale-only (no zero-points/bias), inside the exact production QmvFast tiling/occupancy/loop. Precedence: use_nf4 -> codebook path, else existing use_lut branch. Wired through the CPU kernel signature (additive trailing bool), all existing call sites (default false), and the qmv_lut_bench dispatcher (new nf4-grafted column). Adds nf4_graft_test correctness gate: grafted-NF4 is bit-exact vs Nf4QmvConstant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s + bench Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tested replacing QmvFast's pure-ALU int4→float dequant:
uint_to_fpmantissa trick (nibble extract via shift/mask + bit-OR + fsub) with
a threadgroup-memory LUT lookup. No win at any tested shape, mild
E2E regression on real models. Mantissa trick stays optimal.
Headline (Apple M4, ZP_BF16_gs64, 4-bit, kernel µs medians)
E2E LFM2.5 4-bit decode: −1.8% (RHT), −3.5% (MLX).
What was tried
bf << 16widen: eliminatesair.convertfrom AIR(verified) but no wallclock change. Convert wasn't the cost.
Verdict
The actual cost is L1 cache port contention: LUT reads compete
with weight loads at the same L1 read port. The mantissa trick has
zero memory ops in the dequant chain (pure ALU, extracts nibbles
and converts to float in one fused bit-twiddle), so it doesn't fight
for the port. No LUT variant can beat that on Apple GPU.