# 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** |
