Round 17 Track C: Decode qsa_attn Vectorized char4 Loads / Hoisting & gdn_step ib == 0 Readout Pruning + Loop Unrolling #
Summary of Changes #
1. metal/kernels/gdn.metal (gdn_step_t) #
ib == 0Readout Pruning: Moved the readout reductionfor (int k = 0; k < IB; ++k) o += red2[k][j], scalingo *= scale,simd_sum(o * o), andpart2[cb] = osqwrite insideif (ib == 0)(tid < 128), keeping the surroundingthreadgroup_barrier(mem_flags::mem_threadgroup)uniform across all threads. Threadsib = 1, 2, 3(tid = 128..511, 75% of the threadgroup) never readoorpart2afterred2[ib][j] = o, so pruning their redundant readout eliminates1,536shared-memory loads and384simd_sums per token per value head (73,728shared-memory loads per GDN layer).- State Base Pointer Hoisting &
#pragma clang loop unroll(full): Hoisteddevice float* st_base = state + (i0 * hv + h) * S + jwith stridest_stride = hv * Sacross the initial state load and commit writeback, and added#pragma clang loop unroll(full)to all fixed-trip loops (k < 3,k < 4,r < RPT,k < IB,k < 16; k += 2). - Threadgroup Occupancy Preserved: All
GDN_NTOK = 1..8specializations compile withmaxTotalThreadsPerThreadgroup = 512(gdn_step) on Apple M5.
2. metal/kernels/qsa.metal (qsa_attn, lines 327–398) #
- Vectorized
char4Key Loads & Query Pointer Hoisting: Replaced the 8 scalarcharloads fromkq + rowi * QD + lane * 8(which is 8-byte aligned sinceQD = 256andlane * 8is a multiple of 8) with two 32-bitchar4loads (k0,k1), hoistedthreadgroup const float* q_lane = &qs[0][lane * 8]outside the cell loop with strideQDper query head, and added#pragma clang loop unroll(full)on theHPG = 12andi < 8loops in both the score and value-accumulation phases.
Verification & Bitwise Parity #
- Standalone Test Suite (
/tmp/argon_r17_gdn/strata/build-metal):gdn_parity:ALL PASS(allGDN_NTOK = 1..8pipelines reportmax 512 threads per threadgroup;ntok = 1..4verify/commit/partial-commit checks pass).gdn_prompt_parity:ALL PASS(T = 1..2048single-pass vs TB=16 andCBscan checks pass).qsa_parity:ALL PASS(prep,score,top-k,attention + gatepass).qsa_prompt_parity:ALL PASS(pos0 = 0..30000qsa_attn_mm/qsa_flash/qsa_prepchecks pass).
- Paired A/B Bitwise Parity (
/tmp/argon_r17_gdn/ab_bench):gdn_step:100% bitwise memcmp == 0acrossstate,hist_out, andy(including all 4 preparedxprepplanes + per-16 sums whenplane = MAXT * 6144 = 49152) for allntok in {1, 2, 3, 4},commit in {0, 1},plane in {0, 49152}.qsa_attn:100% bitwise memcmp == 0acrosspart([n_tok][chunks][QH][QD + 2]) for allpos0 in {256, 2048, 8192},ntok in {1, 2, 3, 4}.
Paired Interleaved A/B Benchmark Results (Apple M5) #
1. gdn_step (36 layers rotated, 113 MB state, median of 9 interleaved runs) #
ntok |
commit |
plane |
Baseline (us/layer) | Candidate (us/layer) | Speedup | Delta | Bitwise memcmp |
|---|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 28.78 | 27.73 | 1.04x | -3.63% | 0 (PASS) |
| 1 | 0 | 49152 | 28.94 | 28.62 | 1.01x | -1.11% | 0 (PASS) |
| 1 | 1 | 0 | 55.17 | 55.34 | 1.00x | +0.32% | 0 (PASS) |
| 1 | 1 | 49152 | 55.71 | 55.95 | 1.00x | +0.44% | 0 (PASS) |
| 2 | 0 | 0 | 37.05 | 33.69 | 1.10x | -9.05% | 0 (PASS) |
| 2 | 0 | 49152 | 37.66 | 34.58 | 1.09x | -8.18% | 0 (PASS) |
| 2 | 1 | 0 | 58.45 | 58.09 | 1.01x | -0.62% | 0 (PASS) |
| 2 | 1 | 49152 | 58.51 | 58.27 | 1.00x | -0.42% | 0 (PASS) |
| 3 | 0 | 0 | 42.89 | 38.62 | 1.11x | -9.95% | 0 (PASS) |
| 3 | 0 | 49152 | 42.62 | 39.20 | 1.09x | -8.02% | 0 (PASS) |
| 3 | 1 | 0 | 62.42 | 60.81 | 1.03x | -2.58% | 0 (PASS) |
| 3 | 1 | 49152 | 62.10 | 60.61 | 1.02x | -2.39% | 0 (PASS) |
| 4 | 0 | 0 | 48.47 | 44.66 | 1.09x | -7.87% | 0 (PASS) |
| 4 | 0 | 49152 | 49.05 | 45.28 | 1.08x | -7.70% | 0 (PASS) |
| 4 | 1 | 0 | 65.13 | 62.29 | 1.05x | -4.36% | 0 (PASS) |
| 4 | 1 | 49152 | 66.28 | 63.75 | 1.04x | -3.81% | 0 (PASS) |
2. qsa_attn (24 dispatches per timing batch, median of 11 interleaved runs) #
pos0 |
ntok |
Baseline (us/layer) | Candidate (us/layer) | Speedup | Delta | Bitwise memcmp |
|---|---|---|---|---|---|---|
| 256 | 1 | 20.45 | 18.77 | 1.09x | -8.21% | 0 (PASS) |
| 256 | 2 | 23.16 | 21.55 | 1.07x | -6.95% | 0 (PASS) |
| 256 | 3 | 28.87 | 26.53 | 1.09x | -8.13% | 0 (PASS) |
| 256 | 4 | 40.03 | 35.46 | 1.13x | -11.41% | 0 (PASS) |
| 2048 | 1 | 64.69 | 59.60 | 1.09x | -7.87% | 0 (PASS) |
| 2048 | 2 | 115.09 | 106.63 | 1.08x | -7.35% | 0 (PASS) |
| 2048 | 3 | 170.40 | 158.91 | 1.07x | -6.74% | 0 (PASS) |
| 2048 | 4 | 222.10 | 205.59 | 1.08x | -7.43% | 0 (PASS) |
| 8192 | 1 | 64.82 | 59.42 | 1.09x | -8.32% | 0 (PASS) |
| 8192 | 2 | 114.44 | 106.70 | 1.07x | -6.76% | 0 (PASS) |
| 8192 | 3 | 171.15 | 159.12 | 1.08x | -7.03% | 0 (PASS) |
| 8192 | 4 | 223.25 | 206.02 | 1.08x | -7.72% | 0 (PASS) |
Artifacts #
- Unified patch:
/tmp/argon_r17_gdn/argon_r17_gdn.patch(verified withgit -C vendor/strata apply --check /tmp/argon_r17_gdn/argon_r17_gdn.patch) - Paired A/B benchmark source & binary:
/tmp/argon_r17_gdn/ab_bench.cpp,/tmp/argon_r17_gdn/ab_bench - Scratch build & test tree:
/tmp/argon_r17_gdn/strata/build-metal