Round 6 Track C Audit Report: Register-Cached rv in gr_norm_h* + 1-Simdgroup-Per-Head Barrier-Free gdn_pre & gdn_post #
- Agent:
argon-gr-regs-and-gdn-post - Device: Apple M5 (10-core GPU, 24 GB unified memory)
- Patch:
/tmp/argon_r6_gr_gdn/argon_r6_gr_gdn.patch(git -C vendor/strata apply --checkclean) - Modified files (within owned boundaries):
metal/kernels/prompt.metal(lines 171-319)metal/kernels/gdn_prompt.metal(gdn_preandgdn_post)metal/src/engine/window.cpp(lines 3407 and 3412 only, inside 3402-3414 boundary)metal/tests/comb_fold_parity.cppmetal/tests/gdn_prompt_parity.cpp
1. Target 1: Register-Cached rv in gr_norm_h, gr_norm_h4, gr_norm_h_moe, gr_norm_h_moec (metal/kernels/prompt.metal) #
Design & Exact Arithmetic Preservation #
- In
gr_norm_h(1stream per threadgroup of256threads,n = 2560 = 10 * 256), Pass 1 now caches the updated residual stream valuesrv[i] = v(float rv[10],i = 0..9) in registers and Pass 2 computeso[d] = half(rv[i] * w[d] * rs)directly from registers without re-readingr[d]from device memory. - In
gr_norm_h4,gr_norm_h_moe, andgr_norm_h_moec(hc = 4streams per threadgroup of256threads), Pass 1 cachesrv[c][i] = v(float rv[4][10]) in registers and passesrvtogr_norm_h_out, which writeso[d] = half(rv[c][i] * w[d] * rs)directly from registers with zero device re-reads ofR(-83.89 MBper call atT=2048,-7.89 GBacross96calls atT=1983).
Bitwise Parity & M5 GPU Benchmark (comb_fold_parity + ple_moe_parity + prompt_parity) #
- Bitwise Parity (
memcmp == 0): 100% PASS acrossT in {1, 7, 64, 1024, 2048}on bothR'andxnhforgr_norm_h_moec,gr_norm_h_moe,gr_norm_h4 (apply 0), andgr_norm_h4 (apply 1). - M5 GPU Benchmark (
48reps per command buffer, best of 3):
Kernel (48 reps) |
T=1024 Baseline |
T=1024 Register rv |
T=1024 Delta |
T=2048 Baseline |
T=2048 Register rv |
T=2048 Delta |
|---|---|---|---|---|---|---|
gr_norm_h (apply 0, (hc, T)) |
21.99 ms | 21.22 ms | -0.77 ms (-3.5%) | 45.45 ms | 44.07 ms | -1.38 ms (-3.0%) |
gr_norm_h4 (apply 0, (1, T)) |
24.84 ms | 23.38 ms | -1.46 ms (-5.9%) | 50.03 ms | 47.41 ms | -2.62 ms (-5.2%) |
gr_norm_h (apply 1, (hc, T)) |
53.31 ms | 52.87 ms | -0.44 ms (-0.8%) | 108.05 ms | 107.60 ms | -0.45 ms (-0.4%) |
gr_norm_h4 (apply 1, (1, T)) |
44.05 ms | 43.52 ms | -0.53 ms (-1.2%) | 86.81 ms | 85.80 ms | -1.01 ms (-1.2%) |
gr_norm_h_moe ((1, T)) |
47.92 ms | 47.71 ms | -0.21 ms (-0.4%) | 94.99 ms | 94.32 ms | -0.67 ms (-0.7%) |
gr_norm_h_moec ((1, T)) |
83.74 ms | 83.53 ms | -0.21 ms (-0.3%) | 166.16 ms | 165.36 ms | -0.80 ms (-0.5%) |
(Note: In standalone microbenchmarks where a single threadgroup's 40 KB slice of R[t] remains hot in L1/SLC between Pass 1 and Pass 2, the savings reflect eliminated load instructions + L1/SLC traffic; in full-window execution with concurrent dispatches and cache pressure, eliminating the second R read avoids SLC eviction re-reads from DRAM.)
2. Target 2: 1-Simdgroup-Per-Head Barrier-Free gdn_pre & gdn_post (metal/kernels/gdn_prompt.metal + window.cpp) #
Design & Exact Arithmetic Preservation #
-
Barrier-Free 1-Simdgroup-Per-Head
gdn_post(grid = (12, T),128threads =4heads/TG):- Each simdgroup (
32lanes) handles one headh = int(tg.x) * 4 + int(sg)(with automatic fallback toh = sg == 0 ? int(tg.x) : hvwhen launched with legacygrid.x == 48). - Lane
lane(0..31) loadsov0 = o[base],ov1 = o[base + 32],ov2 = o[base + 64],ov3 = o[base + 96]and computes:p0 = simd_sum(ov0 * ov0),p1 = simd_sum(ov1 * ov1),p2 = simd_sum(ov2 * ov2),p3 = simd_sum(ov3 * ov3),tot = (p0 + p1) + (p2 + p3). - Because each
simd_sumreduces the exact same 32 elements (0..31,32..63,64..95,96..127) as the 4 simdgroups in the original kernel and sums them with identical(p0 + p1) + (p2 + p3)parenthesization, the result is 100% bitwise identical (memcmp == 0) while using 0 bytes of threadgroup memory, 0threadgroup_barriers, and 4x fewer threadgroups (24,576vs98,304atT=2048).
- Each simdgroup (
-
Barrier-Free 1-Simdgroup-Per-Head
gdn_pre(grid = (8, T),256threads =8heads/TG):- When launched with
grid.x == (h_k + h_v) / 8 = 8(2key-head threadgroups +6value-head threadgroups per token, vs40threadgroups in the legacy grid; legacygrid.x == 40is also supported):- For
x < h_k / 8(2TGs =16simdgroups for16key heads): each simdgroup (32lanes) owns one key headkh = x * 8 + sgand computes bothcv_q[0..3]andcv_k[0..3](4channels per lane) in registers. - L2 norms
tot_q = (sq0 + sq1) + (sq2 + sq3)andtot_k = (sk0 + sk1) + (sk2 + sk3)and the dot productkq = (p[0] + p[1]) + (p[2] + p[3])are reduced within the single simdgroup in the exact same floating-point association order aspart[0..3]andpart[4..7]in the original kernel. - For
x >= h_k / 8(6TGs =48simdgroups for48value heads): each simdgroup (32lanes) owns one value headh = (x - 2) * 8 + sg(4channels per lane).
- For
- Eliminates
threadgroup float part[8]andthreadgroup float prod[128](544 Bthreadgroup memory ->0 B), eliminates all 3threadgroup_barriers (3 -> 0), and cuts threadgroups by 5x (8 * Tvs40 * T) while remaining 100% bitwise identical (memcmp == 0) on all 6 outputs (qn,kn,vc,gb,kq,hist_out).
- When launched with
Bitwise Parity & M5 GPU Benchmark (gdn_prompt_parity) #
- Bitwise Parity (
memcmp == 0): Verified 100% bitwise identical (PASS) between packed 1-simdgroup-per-head(8, T)/(12, T)and legacy(40, T)/(48, T)acrossT in {1, 3, 37, 300}, and all 28gdn_steprecurrence parity checks pass (history exact). - M5 GPU Benchmark (
T = 2048andT = 1024):
Benchmark Metric (T = 2048) |
Baseline (40xT / 48xT, barriers) |
Optimized (8xT / 12xT, 0 barriers, 0 tgmem) |
Delta |
|---|---|---|---|
gdn_pre (1 layer, T=2048) |
1.542 ms | 1.293 ms | -0.249 ms (-16.1%) |
gdn_pre (36 GDN layers, T=2048, f32=0) |
55.51 ms (53.63 ms @ T=1983) |
46.63 ms (45.15 ms @ T=1983) |
-8.88 ms (-16.0%) |
gdn_pre (36 GDN layers, T=1024, f32=0) |
27.68 ms | 22.52 ms | -5.16 ms (-18.6%) |
gdn_post (36 GDN layers, T=2048, f32=0) |
34.65 ms (34.12 ms @ T=1983) |
33.71 ms | -0.94 ms (-2.7%) |
gdn_post (36 GDN layers, T=1024, f32=0) |
17.10 ms | 16.54 ms | -0.56 ms (-3.3%) |
Full gdn_pre + gdn_scanr_4 + gdn_post (1 layer, T=2048, f32=1) |
9.828 ms | 9.565 ms | -0.263 ms (-2.7%) |
Full gdn_pre + gdn_scanr_4 + gdn_post (36 layers, T=2048, f32=1) |
353.81 ms | 344.34 ms | -9.47 ms (-2.7%) |