Round 33 Track C Audit Report: Decode GDN Recurrence (gdn.metal) & glue.metal #
- Agent:
argon-r33-gdn-and-glue-opt(gemini-4-argon) - Target Device: Apple M5 (10-core GPU, 24 GB unified memory)
- Patch Path:
/tmp/argon_r33_gdn/argon_r33_gdn.patch(git -C vendor/strata apply --checkclean) - Scratch Repo:
/tmp/argon_r33_gdn/strata - Baseline Kernels:
/tmp/argon_r33_gdn/base_kernels
1. Optimizations Implemented & Tested #
Target 1: gdn_step_t (metal/kernels/gdn.metal, lines 99–162) #
- Critical-Path
klSplit Across Barrier 1 and Barrier 2:- Immediately after Barrier 1 (
line 125), onlytot_k,rsk, andkl = (rsk * ks[qk_idx]) * scaleare computed before launching the 32-iterationkvFMA loop (for (int r = 0; r < RPT; ++r) kv = fma(st[r], simd_broadcast(kl, ushort(r)), kv);) and storingred[ib][j] = kv. tot_q,rsq,ql = (rsq * qs[qk_idx]) * scale,g = gb[0],be = gb[1], andvj = vs[j]are issued afterred[ib][j] = kvright before Barrier 2 (line 140), shortening the live range ofql,g,be, andvjacross the 32-stepkvloop and overlapping their latency with thered[ib][j]store and Barrier 2.
- Immediately after Barrier 1 (
- Early Conv-History Commit (
hist_out) & Pre-Barrier-3 State Commit (state):- Conv History (
hist_out):hst[0..2]is fully updated at the end of theconv + SiLUblock (line 101, before Barrier 1). Emitting thehist_out[ch * 3 + k] = hst[k]stores immediately insideif (ch >= 0)whent + 1 == commit_at && (tid >= 256 || h < int(a.h_k))makeshst[0..2]dead before Barrier 1 on single-token decode (GDN_NTOK == 1) and on the final token of any multi-token window. - Recurrent State (
state):st[0..31]is finalized at the end of thest/oupdate loop (line 150, before Barrier 3). Previously, the 32 global state stores per thread were deferred until after Barrier 3, theib == 0readout reduction, Barrier 4, and theib == 0y/planestores — leaving simdgroupsib = 1..3(75% of the threadgroup) idle across two barriers before issuing 64 KB of global stores per head. Issuingst_base[r * st_stride] = st[r]immediately before Barrier 3 overlaps the global state writeback withib == 0's readout norm and output plane stores across Barriers 3 and 4. - Rejected Variant (
1b— deferringtot_q/rsq/ql/g/beuntil after Barrier 2): Tested and rejected (+1.5% to +3.7% regression) because issuing 7 threadgroup loads (part[0..3],gb[0..1],qs[qk_idx]) andrsqrtafter Barrier 2 delays thered[0..3][j]loads and thest/oloop. - Rejected Variant (
zzload moved afterst/oloop): Tested and rejected (+1% to +5% regression) because prefetchingzzat the top of the token loop hides its global memory latency behind the 4 barriers of tokent.
- Conv History (
Target 2: swiglu_prep & moe_combine_sh (metal/kernels/glue.metal, lines 18–56) #
- In
moe_combine_sh: hoistedconst int row_base = int(t * a.topk);,device const int* te = plan + P_TOKENT + row_base;, anddevice const float* yep = ye + k;outside the 10-way unrolled expert accumulation loop soyep[te[j] * int(a.n_embd)]eliminates the+ kaddress addition across all 10 loads. - In
swiglu_prep: hoistedconst uint idx = t * a.n + d;acrossg[idx],u[idx], andxp + idxwhile preserving the uniformt * (a.n / 16) + tg.xaddress for thej == 0plane-4 sum write.
Test Harness (metal/tests/gdn_parity.cpp) #
- Extended
gdn_parity --ab <ref.metal|ref_dir>to accept a directory (/tmp/argon_r33_gdn/base_kernels) or file path, run all 88/88 GDN bitwise checks (ntok = 1..8,plane = 0 / 49152,commit = 0 / 1 / 0x101..0x107), run paired A/B timings across all 32(plane, ntok, commit)configurations (36 layers rotated, 113 MB state), and whenglue.metalis present inref_dir, run 24/24 bitwise checks (swiglu_prepandmoe_combine_shforntok = 1..8,topk = 10, 8) plus paired A/B timings.
2. Verification & Bitwise Parity Results #
gdn_parity --ab /tmp/argon_r33_gdn/base_kernels(gdn_step,IB = 4, 512 threads):- Pipeline occupancy:
max 512 threads per threadgroup (the kernel needs 512)for allGDN_NTOK = 1..8. - GDN A/B bitwise checks: 88/88
PASS(0 fail(s)) acrossy,state, andhist_out. - Glue A/B bitwise checks: 24/24
PASS(0 fail(s)) acrossswiglu_prep(xpplanes 0..4) andmoe_combine_sh(bo,topk = 10, 8).
- Pipeline occupancy:
GDN_IB8=1 gdn_parity --ab /tmp/argon_r33_gdn/base_kernels --no-bench(gdn_step8,IB = 8, 1024 threads):- Pipeline occupancy:
max 1024 threads per threadgroup (the kernel needs 1024)for allGDN_NTOK = 1..8. - GDN A/B bitwise checks: 88/88
PASS(0 fail(s)).
- Pipeline occupancy:
gdn_parity(double-precision CPU reference + window invariants +plane = 49152verification):ALL PASS.fuse_parity(gemv_cat,router_route,moe_combine_sh + gr_norm == gr_norm_comb / gr_norm_comb_4sacrossntok = 1..8):ALL PASS.
3. Paired A/B Benchmark Results on Apple M5 #
3.1 gdn_step Paired A/B (36 layers rotated, 7 interleaved pairs x 72 dispatches) #
plane |
ntok |
Mode | Base (us/layer) | Cand (us/layer) | Paired Ratio (cand/base) |
36-Layer Total (Base -> Cand) |
|---|---|---|---|---|---|---|
| 0 | 1 | commit | 55.81 | 55.08 | 0.9877 (-1.23%) | 2.009 -> 1.983 ms |
| 0 | 1 | verify | 27.77 | 27.25 | 0.9895 (-1.05%) | 1.000 -> 0.981 ms |
| 0 | 2 | commit | 60.26 | 58.54 | 0.9775 (-2.25%) | 2.169 -> 2.107 ms |
| 0 | 2 | verify | 32.34 | 31.75 | 0.9813 (-1.87%) | 1.164 -> 1.143 ms |
| 0 | 3 | commit | 61.59 | 60.82 | 0.9842 (-1.58%) | 2.217 -> 2.190 ms |
| 0 | 3 | verify | 37.68 | 36.96 | 0.9844 (-1.56%) | 1.356 -> 1.330 ms |
| 0 | 4 | commit | 63.45 | 62.54 | 0.9891 (-1.09%) | 2.284 -> 2.251 ms |
| 0 | 4 | verify | 42.85 | 41.80 | 0.9768 (-2.32%) | 1.543 -> 1.505 ms |
| 0 | 5 | commit | 66.20 | 64.15 | 0.9717 (-2.83%) | 2.383 -> 2.309 ms |
| 0 | 5 | verify | 48.23 | 46.85 | 0.9702 (-2.98%) | 1.736 -> 1.687 ms |
| 0 | 6 | commit | 71.00 | 68.55 | 0.9638 (-3.62%) | 2.556 -> 2.468 ms |
| 0 | 6 | verify | 53.81 | 52.12 | 0.9692 (-3.08%) | 1.937 -> 1.876 ms |
| 0 | 7 | commit | 75.97 | 73.37 | 0.9658 (-3.42%) | 2.735 -> 2.641 ms |
| 0 | 7 | verify | 59.01 | 57.23 | 0.9698 (-3.02%) | 2.124 -> 2.060 ms |
| 0 | 8 | commit | 81.66 | 78.20 | 0.9589 (-4.11%) | 2.940 -> 2.815 ms |
| 0 | 8 | verify | 64.65 | 62.72 | 0.9683 (-3.17%) | 2.327 -> 2.258 ms |
| 49152 | 1 | commit | 56.16 | 56.03 | 0.9943 (-0.57%) | 2.022 -> 2.017 ms |
| 49152 | 1 | verify | 27.37 | 27.23 | 0.9959 (-0.41%) | 0.985 -> 0.980 ms |
| 49152 | 2 | commit | 64.22 | 62.80 | 0.9808 (-1.92%) | 2.312 -> 2.261 ms |
| 49152 | 2 | verify | 33.07 | 32.66 | 0.9868 (-1.32%) | 1.190 -> 1.176 ms |
| 49152 | 3 | commit | 62.00 | 60.73 | 0.9797 (-2.03%) | 2.232 -> 2.186 ms |
| 49152 | 3 | verify | 38.34 | 38.05 | 0.9934 (-0.66%) | 1.380 -> 1.370 ms |
| 49152 | 4 | commit | 64.05 | 63.00 | 0.9833 (-1.67%) | 2.306 -> 2.268 ms |
| 49152 | 4 | verify | 43.43 | 43.18 | 0.9942 (-0.58%) | 1.564 -> 1.555 ms |
| 49152 | 5 | commit | 66.96 | 65.55 | 0.9794 (-2.06%) | 2.411 -> 2.360 ms |
| 49152 | 5 | verify | 49.08 | 48.56 | 0.9917 (-0.83%) | 1.767 -> 1.748 ms |
| 49152 | 6 | commit | 71.80 | 70.17 | 0.9766 (-2.34%) | 2.585 -> 2.526 ms |
| 49152 | 6 | verify | 54.65 | 54.10 | 0.9919 (-0.81%) | 1.967 -> 1.948 ms |
| 49152 | 7 | commit | 77.41 | 75.36 | 0.9748 (-2.52%) | 2.787 -> 2.713 ms |
| 49152 | 7 | verify | 60.30 | 59.62 | 0.9865 (-1.35%) | 2.171 -> 2.146 ms |
| 49152 | 8 | commit | 82.69 | 80.06 | 0.9717 (-2.83%) | 2.977 -> 2.882 ms |
| 49152 | 8 | verify | 65.62 | 64.97 | 0.9899 (-1.01%) | 2.362 -> 2.339 ms |
3.2 glue.metal Paired A/B (swiglu_prep & moe_combine_sh, 256 dispatches/cb with buffer barrier) #
| Kernel | ntok |
Base (us) | Cand (us) | Paired Ratio (cand/base) |
|---|---|---|---|---|
swiglu_prep |
1 | 1.01 | 1.02 | 1.0118 |
swiglu_prep |
2 | 1.10 | 1.10 | 1.0003 |
swiglu_prep |
4 | 1.25 | 1.25 | 0.9982 |
swiglu_prep |
8 | 1.57 | 1.55 | 0.9941 |
moe_combine_sh |
1 | 1.28 | 1.30 | 1.0178 |
moe_combine_sh |
2 | 1.50 | 1.49 | 0.9973 |
moe_combine_sh |
4 | 1.97 | 1.97 | 0.9937 |
moe_combine_sh |
8 | 2.78 | 2.77 | 0.9971 |