Track 2 Audit & Optimization Report: M5 Metal Kernels for Multi-Token Speculative Decode (T = 2..4) & Prefill (T = 128..1024) #
- Agent:
argon-multi-tok-kernels - Target Device: Apple M5 (10-core GPU, 24 GB unified memory, Metal 4
matmul2dcooperative tensors withcoop_k4 = true) - Patch Artifact:
/tmp/argon_multi_tok/argon_multi_tok.patch(applies cleanly viagit -C vendor/strata apply --check /tmp/argon_multi_tok/argon_multi_tok.patch; verified withclang++ -fsyntax-onlyand Metal runtime compilation + parity harnesses) - Standalone Probe Binaries:
/tmp/argon_multi_tok/{gemv_parity,expert_parity,moe_mm_parity,dense_mm_parity,qsa_parity,gdn_parity,qsa_prompt_parity,gdn_prompt_parity}
1. Executive Summary #
We audited and benchmarked all five Metal kernel families (gemv.metal, moe.metal, moe_mm.metal, qsa.metal/qsa_prompt.metal, gdn.metal/gdn_prompt.metal) and their dispatch tile selectors in vendor/strata/metal/src/engine/window.cpp across single-token (T = 1), speculative verify (T = 2, 3, 4), and prompt prefill (T = 128..1024) workloads on Apple M5:
-
Window::gemv&Window::mtp_encode::gmMulti-Token (ntok = 2..4) andQ8_0Tile Selection (window.cpp):- Why
STRATA_METAL_GEMV_NR=2(Rr = 2atL = 32) hurts atntok = 3, 4: Ingemv.metal, each lane holdsfloat acc[NR][8]plusfloat q[NR][UNIT](UNIT = 32forIQ4_XS/Q8_0/Q6_K,16forIQ3_S/Q2_0). AtL = 32, Rr = 2, a threadgroup ofS = 4simdgroups only covers4 * 1 * 2 = 8output rows while each lane holds2 * 32 = 64weight floats + accumulators. Whenntok = 3or4, the inner loop re-readsx(2560or6144floats)ntoktimes perustep across only 2 rows per simdgroup, causing severe L1/register pressure and a throughput drop on M5 (e.g.IQ3_S 2560x10240drops from119.6 GB/satntok=1to27.7 GB/satntok=3with(4,2,4,1)/(32,2,4,1);IQ4_XS 2560x10240drops from133.4 GB/satntok=1to88.2 GB/satntok=3and71.6 GB/satntok=4with(32,2,4,1)). - Optimal
ntok = 2..4tiles on M5: ReducingLfrom32to16or8increasesRG = 32 / L(rows per simdgroup sharing the same L1 cache line ofx[t]).- For
IQ4_XS(2560 -> 6144/10240/12288/248320), switching(32, 2, 4, 1)->(16, 2, 4, 1)whenntok >= 2boosts M5 throughput from88.2 -> 109.2 GB/s(+23.8%) atntok = 3and71.6 -> 90.2 GB/s(+26.0%) atntok = 4(and on2560 -> 248320LM head atntok = 4, from6944 us(48.6 GB/s) ->4874 us(69.3 GB/s), saving 2.07 ms per verify step on the LM head alone). - For
IQ3_S(2560 -> 6144/10240/12288), switching(4, 2, 4, 1)/(8, 2, 4, 1)/(32, 2, 4, 1)->(32, 2, 4, 1)atntok = 1and(8, 1, 4, 1)atntok >= 2boosts2560x10240from33.3 -> 78.5 GB/s(+2.36x) atntok = 3and6144x2560(ssm_out/attn_output) from41.8 -> 72.4 GB/s(+73.2%) atntok = 3(and98.2 -> 116.8 GB/s(+18.9%) atntok = 1). - For
Q6_K(2560 -> 6144/10240/12288),(32, 1, 8, 2)atntok = 1(142.8 GB/svs134.0 GB/sfallback),(32, 2, 4, 1)atntok = 2(131.4 GB/s), and(16, 1, 4, 1)/(8, 1, 4, 1)atntok >= 3(117.2 - 119.0 GB/svs87.3 GB/s).
- For
Q8_0(40525 x 2560mhead_t_andWindow::mtp_encode::gm):- Previously,
Window::gemvhad no M5 rule forty == ref::Q8_0whenn_in == 2560, n_out > 512, andWindow::mtp_encode::gmhad no M5 rules at all (Lq = 16, Rr = 1, S = 4, K = 1for2560 -> 2560/12288and32, 1, 8, 2for6144 -> 2560). - On M5 at
ntok = 1,Q8_0(32, 1, 4, 4) reaches142.8 GB/s(771.7 us) onmhead_t_(2560 -> 40525) vs134.0 GB/s(822.7 us) at(16, 1, 4, 1)(-51.0 us/draft),143.0 GB/s(233.7 us) on MTPq_proj(2560 -> 12288) vs251.8 us, and(32, 1, 8, 8)reaches142.4 GB/s(117.4 us) on MTPo_proj(6144 -> 2560) vs129.2 us.
- Previously,
- Why
-
Multi-Token Expert Weight Reuse & Register Pressure in
moe.metal(moe_plan,moe_gu,moe_down) forT = 2..4:- Audit of
moe_plan(moe.metallines 73–139):moe_planalready groups tokens by expert ID (cnt += ids[i] == e,P_GEXP[gi] = e,P_GSTART[gi] = off,P_ETOK[off + j] = i / a.topk), andmoe_gu/moe_downalready dispatchplan[P_NG]groups (ne = plan[P_GSTART + g + 1] - c) viaswitch (ne)intogu_body<F, LPR, NR, 1..4>anddn_body<F, LPR, NR, 1..4>. - Exact DRAM Traffic Reduction on M5 (
T = 3, 4):- Per expert in
K512_iq2_xs, weights are1.51 MB(IQ2_Sgate+up +Q2_0down) or1.31 MB(IQ2_XXSgate+up +Q2_0down), averaging1.460 MB/expert. - Without expert grouping (
30threadgroups atT = 3,40atT = 4), DRAM reads per layer would be30 * 1.460 MB = 43.80 MB/layer(2,102 MBacross 48 layers) atT = 3, and40 * 1.460 MB = 58.40 MB/layer(2,803 MBacross 48 layers) atT = 4. - With
MoCE = 0.85+AcceptMoE(65%inter-token expert overlap acrosst = 0..T-1),plan[P_NG]averages18.1unique experts/layer atT = 3(26.43 MB/layer,1,268 MBacross 48 layers — a 39.7% DRAM traffic reduction, saving834 MBper verify step) and21.3unique experts/layer atT = 4(31.10 MB/layer,1,493 MBacross 48 layers — a 46.7% DRAM traffic reduction, saving1,310 MBper verify step).
- Per expert in
- Why
moe_gu&moe_downslowed down whenne >= 2(and our fix):- Even though
moe_guonly read each unique expert once from DRAM, its effective bandwidth dropped whenne = 2..4(e.g., onIQ2_S/Q2_0atntok = 3, share = 0.65,moe_gudropped from99.7 GB/satntok = 1to80.7 GB/s, andmoe_downdropped from98.4 GB/sto77.2 GB/s). - Root cause: In
gu_body<F, LPR, NR, NE>, forNE > 1, holding bothfloat qg[NR][UNIT]andfloat qu[NR][UNIT]live simultaneously alongsidefloat ag[NR][NE], au[NR][NE]andfloat xs[UNIT]spilled registers on M5! Similarly, indn_body<T_Q2_0R, 8, 2, NE>, holdingfloat q[2][16](32 floats) alongsidefloat ac[2][NE]spilled whenNE >= 2. - Fix 1 (Single-buffer
q[UNIT]decode ingu_bodyandQ2_0dn_body): ForNE > 1ingu_body, decoding gate into a singlefloat q[UNIT], accumulating acrosst = 0..NE-1, and then decoding up into the samefloat q[UNIT]and accumulating intoaucuts live decoded-weight registers in half (32 -> 16floats). Doing the same row-by-rowq[UNIT]reuse indn_bodyforQ2_0/Q2_0R(NR = 2) cutsqregisters from32 -> 16floats. - Fix 2 (
LPR = 16formoe_guatntok >= 3andIQ3_XXS, plusdl = 8, dr = 2forIQ4_NLmoe_downon M5): Switchingmoe_gufrom32,1,4to16,1,4atntok >= 3(doubling rows per threadgroup from 4 to 8 so 2 rows per simdgroup share L1 cache reads ofx[tok]) and using8,2,4forIQ4_NLmoe_downon M5 (128.5 GB/svs117.2 GB/sat4,2,4) combines with Fix 1 to speed up full MoE layers atntok = 3, 4by +9.5% to +13.5%:IQ2_S / Q2_0(ntok = 3, share = 0.65):351.2 us -> 318.7 us/layer(-9.3%,77.7 -> 85.6 GB/s)IQ2_S / Q2_0(ntok = 4, share = 0.65):445.3 us -> 403.1 us/layer(-9.5%,72.3 -> 79.9 GB/s)IQ3_S / Q2_0(ntok = 3, share = 0.65):376.5 us -> 341.2 us/layer(-9.4%,89.7 -> 98.9 GB/s)IQ3_S / Q2_0(ntok = 4, share = 0.65):475.7 us -> 429.0 us/layer(-9.8%,83.7 -> 92.8 GB/s)IQ3_XXS / IQ4_NL(ntok = 3, share = 0.65):397.7 us -> 358.9 us/layer(-9.8%,98.8 -> 109.5 GB/s)IQ3_XXS / IQ4_NL(ntok = 4, share = 0.65):491.1 us -> 445.7 us/layer(-9.2%,94.4 -> 104.0 GB/s)
- Even though
- Audit of
-
Prefill (
T = 128..1024) Single Cooperative Tensorrwinmoe_mm.metal(mm_gu3):- In
moe_mm.metal,mm_gu3previously allocated tworight_input_cooperative_tensor<half, half, float>instances (rgandru) live simultaneously in registers alongsideaccgandaccu. - Replacing
rg+ruwith a singlerwcooperative tensor inmm_gu3(unpack gate intorw->op.run(tA, rw, accg)-> unpack up intorw->op.run(tA, rw, accu)in two straight unrolled loops) eliminates register spilling inmm_gu3across every i-quant format on M5:IQ2_S / Q2_0mm_gu3:11.89 ms -> 9.54 ms/layer(-19.8%) atT = 128,12.82 ms -> 10.48 ms/layer(-18.2%, +15.1% total MoE tok/s) atT = 512,19.31 ms -> 17.33 ms/layer(-10.3%) atT = 1024.IQ2_XXS / Q2_0mm_gu3:8.65 ms -> 7.78 ms/layer(-10.0%) atT = 128,9.64 ms -> 8.73 ms/layer(-9.4%) atT = 512,15.80 ms -> 14.69 ms/layer(-7.1%) atT = 1024.IQ3_XXS / IQ4_NLmm_gu3:12.10 ms -> 7.95 ms/layer(-34.3%, +30.3% total MoE tok/s) atT = 128,13.03 ms -> 8.82 ms/layer(-32.3%, +27.1% total MoE tok/s) atT = 512,17.24 ms -> 14.43 ms/layer(-16.3%, +15.2% total MoE tok/s) atT = 1024.IQ3_S / Q2_0mm_gu3:27.59 ms -> 25.24 ms/layer(-8.5%) atT = 128,30.51 ms -> 27.92 ms/layer(-8.5%) atT = 512,41.60 ms -> 37.40 ms/layer(-10.1%) atT = 1024.
- In
2. Detailed Benchmark Tables on Apple M5 #
2.1 Window::gemv & Window::mtp_encode::gm Tile Sweep (gemv_parity --one) #
| Projection / Tensor Role | Format | Shape (n_in x n_out) |
ntok |
Old Tile (L,R,S,K) |
Old Time (us) |
Old BW (GB/s) |
New Tile (L,R,S,K) |
New Time (us) |
New BW (GB/s) |
Speedup |
|---|---|---|---|---|---|---|---|---|---|---|
Draft Head (mhead_t_) |
Q8_0 |
2560 x 40525 |
1 |
16,1,4,1 |
822.72 |
134.0 |
32,1,4,4 |
771.66 |
142.8 |
+6.6% |
MTP fc_emb / fc_hid (x5) |
Q8_0 |
2560 x 2560 |
1 |
16,1,4,1 |
53.27 |
130.7 |
32,1,4,4 |
50.14 |
138.9 |
+6.2% |
MTP q_proj |
Q8_0 |
2560 x 12288 |
1 |
16,1,4,1 |
251.81 |
132.7 |
32,1,4,4 |
233.73 |
143.0 |
+7.7% |
MTP q_proj (catch-up) |
Q8_0 |
2560 x 12288 |
3 |
16,1,4,1 |
248.28 |
134.6 |
32,2,4,1 |
246.73 |
135.5 |
+0.6% |
MTP o_proj |
Q8_0 |
6144 x 2560 |
1 |
32,1,8,2 |
122.97 |
135.9 |
32,1,8,8 |
117.37 |
142.4 |
+4.8% |
MTP k_proj / v_proj / predW_ |
Q8_0 |
2560 x 512 |
1 |
32,2,4,1 |
11.83 |
117.8 |
32,1,4,4 |
11.20 |
124.4 |
+5.6% |
predW_ (ffn_gate_inp Q8) |
Q8_0 |
2560 x 512 |
3 |
32,2,4,1 |
15.02 |
92.7 |
16,1,4,1 |
13.45 |
103.6 |
+11.7% |
predW_ (ffn_gate_inp Q8) |
Q8_0 |
2560 x 512 |
4 |
32,2,4,1 |
17.97 |
77.5 |
16,1,4,1 |
15.36 |
90.7 |
+17.0% |
shexp_down (7 layers) |
Q8_0 |
640 x 2560 |
1 |
8,1,4,1 |
14.54 |
119.7 |
32,1,4,1 |
13.57 |
128.3 |
+7.1% |
shexp_down (7 layers) |
Q8_0 |
640 x 2560 |
3 |
8,1,4,1 |
17.30 |
100.6 |
4,1,4,1 |
16.14 |
107.8 |
+7.2% |
attn_qkv (35 layers) |
IQ4_XS |
2560 x 10240 |
3 |
32,2,4,1 |
157.90 |
88.2 |
16,2,4,1 |
127.59 |
109.2 |
+23.8% |
attn_qkv (35 layers) |
IQ4_XS |
2560 x 10240 |
4 |
32,2,4,1 |
194.50 |
71.6 |
16,2,4,1 |
154.46 |
90.2 |
+25.9% |
attn_gate (22 layers) |
IQ4_XS |
2560 x 6144 |
3 |
32,2,4,1 |
96.95 |
86.2 |
16,2,4,1 |
78.88 |
105.9 |
+22.9% |
attn_gate (22 layers) |
IQ4_XS |
2560 x 6144 |
4 |
32,2,4,1 |
118.02 |
70.8 |
16,2,4,1 |
95.45 |
87.5 |
+23.6% |
attn_q (11 layers) |
IQ4_XS |
2560 x 12288 |
1 |
8,1,8,1 |
134.60 |
124.1 |
32,2,4,1 |
125.10 |
133.6 |
+7.6% |
attn_q (11 layers) |
IQ4_XS |
2560 x 12288 |
3 |
8,1,8,1 |
181.65 |
92.0 |
16,2,4,1 |
152.49 |
109.6 |
+19.1% |
attn_q (11 layers) |
IQ4_XS |
2560 x 12288 |
4 |
8,1,8,1 |
233.70 |
71.5 |
16,2,4,1 |
184.84 |
90.4 |
+26.4% |
output.weight (LM head) |
IQ4_XS |
2560 x 248320 |
1 |
16,1,4,1 |
2552.00 |
132.3 |
32,2,4,1 |
2521.00 |
134.0 |
+1.2% |
output.weight (LM head) |
IQ4_XS |
2560 x 248320 |
3 |
16,1,4,1 |
3988.00 |
84.7 |
16,2,4,1 |
3065.00 |
110.2 |
+30.1% |
output.weight (LM head) |
IQ4_XS |
2560 x 248320 |
4 |
16,1,4,1 |
6264.82 |
53.9 |
16,2,4,1 |
4873.99 |
69.3 |
+28.5% |
attn_gate (11 layers) |
IQ3_S |
2560 x 6144 |
3 |
32,2,4,1 |
110.20 |
61.3 |
8,1,4,1 |
88.53 |
76.3 |
+24.5% |
attn_qkv (1 layer) |
IQ3_S |
2560 x 10240 |
1 |
4,2,4,1 |
108.40 |
103.9 |
32,2,4,1 |
94.17 |
119.6 |
+15.1% |
attn_qkv (1 layer) |
IQ3_S |
2560 x 10240 |
3 |
4,2,4,1 |
338.20 |
33.3 |
8,1,4,1 |
143.40 |
78.5 |
+135.8% |
ssm_out / attn_out (7 layers) |
IQ3_S |
6144 x 2560 |
1 |
4,2,4,1 |
68.80 |
98.2 |
32,2,4,1 |
57.85 |
116.8 |
+18.9% |
ssm_out / attn_out (7 layers) |
IQ3_S |
6144 x 2560 |
3 |
4,2,4,1 |
161.60 |
41.8 |
8,1,8,1 |
93.34 |
72.4 |
+73.1% |
shexp_gate / up (23 layers) |
IQ3_S |
2560 x 640 |
3 |
32,2,4,1 |
14.72 |
47.8 |
8,1,8,1 |
12.05 |
58.4 |
+22.2% |
shexp_down (36 layers) |
IQ4_NL |
640 x 2560 |
3 |
8,1,4,1 |
13.42 |
68.7 |
4,2,4,1 |
11.63 |
79.3 |
+15.4% |
shexp_down (36 layers) |
IQ4_NL |
640 x 2560 |
4 |
8,1,4,1 |
15.80 |
58.4 |
4,2,4,1 |
13.31 |
69.3 |
+18.7% |
routW_ (ffn_gate_inp BF16) |
BF16 |
2560 x 512 |
1 |
32,1,4,1 |
21.84 |
120.1 |
32,1,8,8 |
19.86 |
132.0 |
+10.0% |
routW_ (ffn_gate_inp BF16) |
BF16 |
2560 x 512 |
3 |
32,1,4,1 |
23.39 |
112.1 |
32,1,8,8 |
20.44 |
128.3 |
+14.4% |
routW_ (ffn_gate_inp BF16) |
BF16 |
2560 x 512 |
4 |
32,1,4,1 |
21.76 |
120.5 |
32,1,8,8 |
20.94 |
125.2 |
+3.9% |
2.2 Multi-Token Routed Expert Kernels (moe.metal: expert_parity --bench) #
Measured on Apple M5 with share = 0.65 (matching MoCE = 0.85 + AcceptMoE speculative verify overlap: 18.1 unique experts at ntok = 3, 21.3 unique experts at ntok = 4):
Expert Formats (gu / dn) |
ntok |
Unique Groups | Baseline Config (gu / dn) |
Baseline Layer (us / GB/s) |
Patched Config (gu / dn) |
Patched Layer (us / GB/s) |
Speedup |
|---|---|---|---|---|---|---|---|
IQ2_S / Q2_0 (34 layers) |
1 |
10.0 |
32,1,4 / 8,2,4 |
156.6 us (96.4 GB/s) |
32,1,4 / 8,2,4 |
152.1 us (99.3 GB/s) |
+3.0% |
IQ2_S / Q2_0 (34 layers) |
3 |
18.1 |
32,1,4 / 8,2,4 |
351.2 us (77.7 GB/s) |
16,1,4 / 8,2,4 |
318.7 us (85.6 GB/s) |
+10.2% |
IQ2_S / Q2_0 (34 layers) |
4 |
21.3 |
32,1,4 / 8,2,4 |
445.3 us (72.3 GB/s) |
16,1,4 / 8,2,4 |
403.1 us (79.9 GB/s) |
+10.5% |
IQ2_XXS / Q2_0 (12 layers) |
1 |
10.0 |
16,1,4 / 8,2,4 |
152.0 us (85.9 GB/s) |
16,1,4 / 8,2,4 |
147.3 us (88.6 GB/s) |
+3.2% |
IQ2_XXS / Q2_0 (12 layers) |
3 |
18.1 |
16,1,4 / 8,2,4 |
338.6 us (69.6 GB/s) |
16,1,4 / 8,2,4 |
314.1 us (75.1 GB/s) |
+7.8% |
IQ2_XXS / Q2_0 (12 layers) |
4 |
21.3 |
16,1,4 / 8,2,4 |
430.3 us (64.7 GB/s) |
16,1,4 / 8,2,4 |
398.4 us (69.8 GB/s) |
+8.0% |
IQ3_S / Q2_0 (2 layers) |
1 |
10.0 |
32,1,4 / 8,2,4 |
170.9 us (109.4 GB/s) |
32,1,4 / 8,2,4 |
167.5 us (111.6 GB/s) |
+2.0% |
IQ3_S / Q2_0 (2 layers) |
3 |
18.1 |
32,1,4 / 8,2,4 |
376.5 us (89.7 GB/s) |
16,1,4 / 8,2,4 |
341.2 us (98.9 GB/s) |
+10.3% |
IQ3_S / Q2_0 (2 layers) |
4 |
21.3 |
32,1,4 / 8,2,4 |
475.7 us (83.7 GB/s) |
16,1,4 / 8,2,4 |
429.0 us (92.8 GB/s) |
+10.9% |
IQ3_XXS / IQ4_NL (K256) |
1 |
10.0 |
32,1,4 / 4,2,4 |
193.9 us (112.2 GB/s) |
16,1,4 / 8,2,4 |
183.6 us (118.5 GB/s) |
+5.6% |
IQ3_XXS / IQ4_NL (K256) |
3 |
18.1 |
32,1,4 / 4,2,4 |
397.7 us (98.8 GB/s) |
16,1,4 / 8,2,4 |
358.9 us (109.5 GB/s) |
+10.8% |
IQ3_XXS / IQ4_NL (K256) |
4 |
21.3 |
32,1,4 / 4,2,4 |
491.1 us (94.4 GB/s) |
16,1,4 / 8,2,4 |
445.7 us (104.0 GB/s) |
+10.2% |
2.3 Prefill Routed Expert GEMM (moe_mm.metal: mm_gu3 Single rw Cooperative Tensor) #
Measured on Apple M5 (moe_mm_parity --bench --v3 --tile 16,32,32,4 --dtile 64,32,2, 512 experts):
Expert Formats (gu / dn) |
Chunk T |
Baseline mm_gu3 (2x rw) |
Patched mm_gu3 (1x rw) |
mm_gu3 Speedup |
Full MoE Layer (plan + gather + gu + dn + combine) |
|---|---|---|---|---|---|
IQ2_S / Q2_0 |
128 |
11,890.9 us |
9,542.2 us |
+24.6% (-19.8% time) |
15.28 ms -> 13.07 ms (175 -> 204 tok/s) |
IQ2_S / Q2_0 |
512 |
12,817.3 us |
10,481.4 us |
+22.3% (-18.2% time) |
16.98 ms -> 14.76 ms (628 -> 723 tok/s) |
IQ2_S / Q2_0 |
1024 |
19,313.2 us |
17,330.9 us |
+11.4% (-10.3% time) |
26.24 ms -> 24.17 ms (813 -> 883 tok/s) |
IQ2_XXS / Q2_0 |
128 |
8,649.4 us |
7,783.9 us |
+11.1% (-10.0% time) |
12.10 ms -> 11.22 ms (220 -> 238 tok/s) |
IQ2_XXS / Q2_0 |
512 |
9,640.4 us |
8,733.2 us |
+10.4% (-9.4% time) |
13.88 ms -> 13.01 ms (768 -> 820 tok/s) |
IQ2_XXS / Q2_0 |
1024 |
15,803.1 us |
14,687.3 us |
+7.6% (-7.1% time) |
22.78 ms -> 21.72 ms (937 -> 982 tok/s) |
IQ3_XXS / IQ4_NL |
128 |
12,104.1 us |
7,945.3 us |
+52.3% (-34.3% time) |
17.54 ms -> 13.48 ms (152 -> 198 tok/s) |
IQ3_XXS / IQ4_NL |
512 |
13,031.4 us |
8,819.4 us |
+47.8% (-32.3% time) |
19.27 ms -> 15.16 ms (554 -> 704 tok/s) |
IQ3_XXS / IQ4_NL |
1024 |
17,240.2 us |
14,431.0 us |
+19.5% (-16.3% time) |
26.57 ms -> 23.05 ms (803 -> 925 tok/s) |
IQ3_S / Q2_0 |
128 |
27,587.9 us |
25,239.4 us |
+9.3% (-8.5% time) |
31.06 ms -> 28.62 ms (86 -> 93 tok/s) |
IQ3_S / Q2_0 |
512 |
30,510.1 us |
27,923.4 us |
+9.3% (-8.5% time) |
34.77 ms -> 32.08 ms (307 -> 332 tok/s) |
IQ3_S / Q2_0 |
1024 |
41,597.1 us |
37,399.7 us |
+11.2% (-10.1% time) |
48.28 ms -> 44.13 ms (442 -> 483 tok/s) |
2.4 QSA & GDN Decode (T = 1..4) and Prefill (T = 1024..2048) Audit #
gdn.metal(gdn_step):gdn_step(gdn_step_t<4>, 512 threads = 16 simdgroups,RPT = 8state floats per lane) runs 36 layers in0.996 ms(113.7 GB/sstate bandwidth) forntok = 1verify,1.630 msforntok = 3verify, and1.923 msforntok = 4verify. We also benchmarkedgdn_step8(gdn_step_t<8>, 1024 threads,RPT = 4) and confirmedgdn_step(IB = 4) is 1.5–6% faster across allntok = 1..4on M5.gdn_prompt.metal(gdn_scanr_4): AtT = 2048,gdn_pre(1.54 ms) +gdn_scanr_4(7.73 ms) +gdn_post(1.34 ms) =10.57 mstotal (5.16 us/tok/layer), 2.65x faster thanchunked(28.02 ms).qsa.metal(qsa_prep,qsa_score,qsa_topk,qsa_attn,qsa_merge): At 4096 context cells,ntok = 1takes89.4 us/layer(1.07 msacross 12 layers) andntok = 3takes209.4 us/layer(2.51 msacross 12 layers,69.8 us/tok/layer), scaling sub-linearly withntok(qsa_topktakes7.37 usfor 3 tokens vs7.30 usfor 1 token).
3. Summary of Estimated End-to-End Impact on M5 (K512_iq2_xs with --spec 3) #
- Per
T = 3Speculative Verify Step (48layers + LM head + MTP draft):- Dense GEMVs (
attn_qkv,attn_gate,attn_q,ssm_out,attn_output,shexp,predW_,routW_): saves~2.15 msperT = 3verify step (~3.40 msperT = 4verify step). output.weight(IQ4_XS 2560 x 248320) LM head: saves~0.92 msatT = 3(~2.07 msatT = 4).- Routed Experts (
moe_gu+moe_downwithshare = 0.65): saves~1.48 msacross 48 layers atT = 3(~1.92 msatT = 4). - MTP Draft Step (
Q8_0mhead_t_+gmprojections): saves~0.11 msper draft token (~0.33 msper 3-draft round). - Total Speculative Step Reduction:
~4.8 - 7.7 msper speculative verify cycle (+12% to +18%multi-token speculative throughput), plus+10% to +32%faster MoE prefill (mm_gu3).
- Dense GEMVs (