opus_r33_gr — Round 33 Track A: hyper-connection read (gr_norm, gr_norm_comb, gr_down_f, gr_up_f) #

Patch: /tmp/opus_r33_gr/opus_r33_gr.patch (git -C vendor/strata apply --check OK; touches only metal/kernels/gr.metal and metal/tests/fuse_parity.cpp). Scratch tree: /tmp/opus_r33_gr/strata; baseline kernels: /tmp/opus_r33_gr/base_kernels; raw final logs: /tmp/opus_r33_gr/final_bench.txt. Device: Apple M5 (10-core GPU), GPU quiet for the final run.

Shipped (all bitwise PASS, ntok 1..8, every gr.metal/gr2.metal entry point incl. BF16/Q4/Q5/F32-inject; default fuse_parity ALL PASS) #

  1. gr_norm: apply branch hoisted out of the 10-step unrolled loop, pointers pre-offset (rp = r + tid, bp = bo + t*2560 + tid, o += tid; w += tid) so every access is an immediate [i * 256]. -6..-11% at ntok 1..4, -2..-3% at 7..8 (~0.2 µs per dispatch; gr_norm is ~2.3-4.3 µs, mostly launch-bound).
  2. grd_acc Q8_0, NR = 2 (gr_down_q8_*_r2, gr_down_q8f_*_r2): a GrdUnit<F, NR> holder with a GrdUnit<T_Q8_0, 2> specialization that keeps the codes packed as char4[8] per row (8 regs instead of 32 floats) and widens with float4(char4) per token. Same fmas in the same order, so bitwise identical. The generic path is unchanged codegen (all other formats/NR = 1: ±0.5%, noise). ntok 7: -13..-16%, ntok 8: -10..-15%; ntok 5-6 neutral; ntok ≤ 4 never uses _r2 in the engine.
  3. fuse_parity --gr-unroll ... bench: 16 pairs × 128 iters, reports the median pair ratio (A/A noise went from ±15% to ±0.3% for gr_down/gr_up, ~±2% for the tiny gr_norm_comb); gr_norm/gr_norm_comb now timed; added same-entry A/B benches for the engine's real entry points (gr_down_q8_4_4, _4_4_r2, q8f_4_4(_r2), q8_8_8(_r2)).

Final paired timings (median Δ, quiet GPU) #

kernel ntok base µs new µs median Δ
gr_down_q8_4_4 1 23.213 23.210 +0.0%
gr_down_q8_4_4 2 23.836 23.831 +0.0%
gr_down_q8_4_4 3 31.574 31.606 +0.1%
gr_down_q8_4_4 4 40.602 40.610 +0.0%
gr_down_q8_4_4 5 55.545 55.580 +0.0%
gr_down_q8_4_4 6 75.455 75.441 +0.0%
gr_down_q8_4_4 7 97.495 97.445 -0.0%
gr_down_q8_4_4 8 119.752 119.762 -0.0%
gr_down_q8_4_4_r2 1 23.348 23.443 +0.4%
gr_down_q8_4_4_r2 2 23.814 23.786 -0.2%
gr_down_q8_4_4_r2 3 32.917 32.977 +0.2%
gr_down_q8_4_4_r2 4 41.266 41.331 +0.1%
gr_down_q8_4_4_r2 5 49.493 49.428 -0.1%
gr_down_q8_4_4_r2 6 58.338 58.370 +0.1%
gr_down_q8_4_4_r2 7 79.517 68.066 -14.4%
gr_down_q8_4_4_r2 8 90.285 79.752 -11.7%
gr_down_q8_8_8 1 23.584 23.729 +0.6%
gr_down_q8_8_8 2 24.839 24.843 -0.0%
gr_down_q8_8_8 3 34.813 34.802 -0.1%
gr_down_q8_8_8 4 45.466 45.464 -0.0%
gr_down_q8_8_8 5 62.634 62.615 -0.0%
gr_down_q8_8_8 6 83.515 83.568 +0.1%
gr_down_q8_8_8 7 115.168 115.243 +0.0%
gr_down_q8_8_8 8 140.286 140.303 +0.1%
gr_down_q8_8_8_r2 1 23.953 24.036 +0.3%
gr_down_q8_8_8_r2 2 25.738 25.852 +0.5%
gr_down_q8_8_8_r2 3 34.776 34.844 +0.2%
gr_down_q8_8_8_r2 4 46.604 46.623 +0.0%
gr_down_q8_8_8_r2 5 58.045 58.184 +0.3%
gr_down_q8_8_8_r2 6 70.499 70.514 -0.1%
gr_down_q8_8_8_r2 7 100.167 83.844 -16.3%
gr_down_q8_8_8_r2 8 114.260 97.570 -14.6%
gr_down_q8f_4_4_r2 1 24.422 24.454 +0.1%
gr_down_q8f_4_4_r2 2 24.889 24.863 -0.4%
gr_down_q8f_4_4_r2 3 33.414 33.478 +0.2%
gr_down_q8f_4_4_r2 4 41.238 41.304 +0.2%
gr_down_q8f_4_4_r2 5 49.481 49.448 -0.1%
gr_down_q8f_4_4_r2 6 58.534 58.637 +0.2%
gr_down_q8f_4_4_r2 7 80.516 70.128 -12.9%
gr_down_q8f_4_4_r2 8 91.064 81.766 -10.2%
gr_norm apply 0 1 3.241 2.882 -11.1%
gr_norm apply 0 2 2.478 2.227 -10.4%
gr_norm apply 0 3 2.506 2.269 -9.2%
gr_norm apply 0 4 2.578 2.400 -7.1%
gr_norm apply 0 5 2.668 2.523 -5.5%
gr_norm apply 0 6 3.039 2.849 -6.4%
gr_norm apply 0 7 3.044 2.958 -2.8%
gr_norm apply 0 8 3.185 3.084 -3.3%
gr_norm apply 1 1 3.293 3.088 -6.1%
gr_norm apply 1 2 3.347 3.096 -7.7%
gr_norm apply 1 3 3.361 3.160 -6.2%
gr_norm apply 1 4 3.468 3.256 -5.9%
gr_norm apply 1 5 3.620 3.428 -5.4%
gr_norm apply 1 6 3.834 3.763 -1.8%
gr_norm apply 1 7 4.069 3.980 -2.2%
gr_norm apply 1 8 4.346 4.255 -2.2%
gr_norm_comb 1 5.135 5.047 -1.4%
gr_norm_comb 2 5.335 5.363 +0.7%
gr_norm_comb 3 6.176 6.248 +1.3%
gr_norm_comb 4 6.754 6.678 -1.0%
gr_norm_comb 5 6.985 6.874 -1.5%
gr_norm_comb 6 8.941 8.889 -0.7%
gr_norm_comb 7 9.091 9.133 +0.5%
gr_norm_comb 8 10.624 10.563 -0.7%
gr_up_q8 1 23.770 23.762 -0.0%
gr_up_q8 2 24.547 24.535 -0.1%
gr_up_q8 3 26.172 26.186 +0.1%
gr_up_q8 4 29.213 29.184 -0.1%
gr_up_q8 5 32.855 32.889 +0.1%
gr_up_q8 6 37.063 37.025 -0.1%
gr_up_q8 7 42.019 41.957 -0.1%
gr_up_q8 8 47.111 47.046 -0.1%

Tried and rejected (measured, bitwise-safe but not wins) #

  • deq<T_Q8_0> #pragma unroll(full): 0.0% (the compiler already unrolls it). Not shipped, quant.metal untouched.
  • Packed Q8 for NR = 1 gr_down: +1..3% at ntok 2 (q8_8_8 +3.2%), neutral elsewhere → restricted to NR = 2.
  • Packed Q8 + always-unrolled token loop at ntok 7-8: +12..45% (registers). Rolled-from-ntok-5 for NR = 2: 4_4_r2 -3% at ntok 5 but 8_8_r2 +0.4..1%; kept the existing ≤ 6 threshold.
  • unroll_count(3) on the gr_down u loop: +2..42% everywhere. Software-pipelined prefetch of the next Q8 block: +3..53%.
  • Aligned 9×uint Q8 block load + funnel shift instead of 16 ushort loads: +25..66% (much worse).
  • gr_up_q8: staging lo in threadgroup float[8*320]: +1..6% (lo reads are already L1 broadcast hits); packed Q8 dot: +2..8% at ntok 4-8; unroll_count(3): +4..30%.
  • gr_norm_comb apply-hoist + gs guard: -0.3..-0.8% vs repeated A/A (within the ~1-2% order bias of that bench) → not shipped.

Why the rest is stuck (diagnosis) #

  • ntok 1: gr_down_q8 (~23.2 µs for 3.48 MB) and gr_up_q8 (~23.8 µs, 3.48 MB) are both at ~150 GB/s = M5 DRAM roofline.
  • ntok 4 gr_down_q8_4_4 (40.6 µs): non-bitwise probes — removing the xn loads → 25.8 µs, removing the weight loads → ~26-31 µs, a fully coalesced (wrong-math) xn pattern → no change. It is the sum of DRAM weights + L2 xn re-reads (1 row/threadgroup × ntok × 40 KB), and _r2 (half the xn traffic) is no faster at ntok 4 → latency/occupancy bound. Real gains need a different row→threadgroup mapping / grid, i.e. host changes in window.cpp (out of my file scope).