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 --check clean)
  • 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) #

  1. Critical-Path kl Split Across Barrier 1 and Barrier 2:
    • Immediately after Barrier 1 (line 125), only tot_k, rsk, and kl = (rsk * ks[qk_idx]) * scale are computed before launching the 32-iteration kv FMA loop (for (int r = 0; r < RPT; ++r) kv = fma(st[r], simd_broadcast(kl, ushort(r)), kv);) and storing red[ib][j] = kv.
    • tot_q, rsq, ql = (rsq * qs[qk_idx]) * scale, g = gb[0], be = gb[1], and vj = vs[j] are issued after red[ib][j] = kv right before Barrier 2 (line 140), shortening the live range of ql, g, be, and vj across the 32-step kv loop and overlapping their latency with the red[ib][j] store and Barrier 2.
  2. 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 the conv + SiLU block (line 101, before Barrier 1). Emitting the hist_out[ch * 3 + k] = hst[k] stores immediately inside if (ch >= 0) when t + 1 == commit_at && (tid >= 256 || h < int(a.h_k)) makes hst[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 the st/o update loop (line 150, before Barrier 3). Previously, the 32 global state stores per thread were deferred until after Barrier 3, the ib == 0 readout reduction, Barrier 4, and the ib == 0 y/plane stores — leaving simdgroups ib = 1..3 (75% of the threadgroup) idle across two barriers before issuing 64 KB of global stores per head. Issuing st_base[r * st_stride] = st[r] immediately before Barrier 3 overlaps the global state writeback with ib == 0's readout norm and output plane stores across Barriers 3 and 4.
    • Rejected Variant (1b — deferring tot_q/rsq/ql/g/be until 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]) and rsqrt after Barrier 2 delays the red[0..3][j] loads and the st/o loop.
    • Rejected Variant (zz load moved after st/o loop): Tested and rejected (+1% to +5% regression) because prefetching zz at the top of the token loop hides its global memory latency behind the 4 barriers of token t.

Target 2: swiglu_prep & moe_combine_sh (metal/kernels/glue.metal, lines 18–56) #

  • In moe_combine_sh: hoisted const int row_base = int(t * a.topk);, device const int* te = plan + P_TOKENT + row_base;, and device const float* yep = ye + k; outside the 10-way unrolled expert accumulation loop so yep[te[j] * int(a.n_embd)] eliminates the + k address addition across all 10 loads.
  • In swiglu_prep: hoisted const uint idx = t * a.n + d; across g[idx], u[idx], and xp + idx while preserving the uniform t * (a.n / 16) + tg.x address for the j == 0 plane-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 when glue.metal is present in ref_dir, run 24/24 bitwise checks (swiglu_prep and moe_combine_sh for ntok = 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 all GDN_NTOK = 1..8.
    • GDN A/B bitwise checks: 88/88 PASS (0 fail(s)) across y, state, and hist_out.
    • Glue A/B bitwise checks: 24/24 PASS (0 fail(s)) across swiglu_prep (xp planes 0..4) and moe_combine_sh (bo, topk = 10, 8).
  • 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 all GDN_NTOK = 1..8.
    • GDN A/B bitwise checks: 88/88 PASS (0 fail(s)).
  • gdn_parity (double-precision CPU reference + window invariants + plane = 49152 verification): ALL PASS.
  • fuse_parity (gemv_cat, router_route, moe_combine_sh + gr_norm == gr_norm_comb / gr_norm_comb_4s across ntok = 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