Round 28 Track C: ple.metal tg_sum Barrier Halving & sample.metal tg_argmax Optimization #
Summary of Changes #
1. metal/src/engine/msl/ple.metal #
- Halved
tg_sumbarriers (2 -> 1per reduction) by removing the trailingthreadgroup_barrier(mem_flags::mem_threadgroup)insidetg_sumand alternatingpart[0..7]andpart[8..15]across back-to-back reductions (threadgroup float part[16]= 64 B vs 32 B):ple_gnorm:2 -> 1barrier (-50%), usingthreadgroup float part[8].ple_gate_norm:4 -> 2barriers (-50%), call 1 (acc) onpart[0..7], call 2 (ss) onpart + 8.ple_query_gate_norm&ple_comb_query_gate_norm:6 -> 3barriers (-50%),gnorm_regs(q)onpart[0..7],gate_norm_regsfirst reduction (acc) onpart + 8(whose barrier synchronizes prior readers ofpart[0..7]), andgate_norm_regssecond reduction (ss) onpart[0..7].ple_moe_gate_norm&ple_moe_gate_norm_c(moe_gate_norm_row):8 -> 4barriers per stream (-50%),gnorm_regs(k)onpart + 8,gnorm_regs(q)onpart[0..7], andgate_norm_regsonpart + 8thenpart[0..7]. Acrosshc = 4streams inple_moe_gate_norm_c, totaltg_sumbarriers drop from32 -> 16(33 -> 17including the initialroffsetup barrier).
- Added
#pragma clang loop unroll(full)to bothfor (int r = 0; r < 9; ++r)loops inple_hist_advsofloat col[9]stays in registers without dynamic indexing.
2. metal/kernels/sample.metal #
- Added
#pragma clang loop unroll(full)to both fixed-trip loops intg_argmax:for (ushort m = 16; m > 0; m >>= 1)(5-step warp butterfly reduction).for (int k = 0; k < 8; ++k)(8-way shared-memory reduction).
- Evaluated & Rejected (
tid == 0pruning andunroll_count(4)inargmax_part/argmax_final):if (sg == 0 && lane == 0)/if (tid == 0)around the post-barrier loop intg_argmax: Because all 8 simdgroups must wait for threadgroup completion anyway and simdgroup 0 still executes the 8-way loop whentid == 0is taken, adding divergent predication insidetg_argmaxregressednv = 40525(nt = 1..8) by+2.0%to+3.5%andnv = 248064, nt = 1..2by+0.8%to+2.0%. Leaving the unrolled 8-way reduction uniform across lanes avoids the branch and is faster.#pragma clang loop unroll_count(4)inargmax_partandargmax_final: Inargmax_part, each iteration containsif (!isnan(v)) better(bv, bi, v, int(i)). Unrolling by 4 (or 2) either via pragma or manual split-loop (i + 1024 < b1) bloated register/predicate state and regressed the draft-vocab path (nv = 40525,per = 338, only 1–2 iterations per thread) by+7.5%to+16.4%(+1.0%to+3.8%even with aper >= 2048guard). Inargmax_final,a.parts = 120 < 256, so the loop executes at most once (tid < 120) andunroll_count(4)added dead duplicate checks (+0.5%to+2.0%regression). Both loops are kept unrolled-by-1.
3. metal/tests/ple_moe_parity.cpp & metal/tests/sample_parity.cpp #
ple_moe_parity.cpp:- Added
ple_gnorm,ple_gate_norm,ple_comb_query_gate_norm, andple_comb_query_gate_norm + conv_resto--abbitwise parity and paired A/B timing checks acrossT in {1, 3, 7, 9, 10, 64, 512, 1024, 2048}. - Deferred
prompt.metal/moe_mm.metalcompilation out of--abmode and sliced only the needed kernels (gr_norm,moe_out,gr_norm_h*,gr_apply_moe*,mm_combine) in full-parity mode, cutting cold compilation + execution time from>20s(timeout) to1.2s.
- Added
sample_parity.cpp:- Added
nv = 248064(nt = 1..8) andnv = 40525(nt = 1, 2, 4, 8) to the paired A/B benchmark and bitwise parity sweep. - Reset
lgto normal finite random floats beforetiming()(previouslytrial == 6left-INFINITYinlg, skewingisnan/branch timing) and reported median per-pair ratios over 9 alternating pairs of 64 reps.
- Added
Verification & Measured A/B Results on Apple M5 #
1. ple_moe_parity (100% Bitwise Parity memcmp == 0 across all kernels & T) #
A/B T 1..2048: ple_gnorm PASS, ple_gate_norm PASS, ple_hist_adv PASS
A/B T 1..2048: ple_moe_gate_norm PASS, ple_moe_gate_norm_c PASS, ple_query_gate_norm PASS, ple_comb_query_gate_norm PASS
| Kernel | T = 1 (base -> cand, ratio) |
T = 3 (base -> cand, ratio) |
T = 7 (base -> cand, ratio) |
T = 64 (base -> cand, ratio) |
T = 2048 (base -> cand, ratio) |
|---|---|---|---|---|---|
ple_gnorm (2 -> 1 bar) |
0.0060 -> 0.0058 ms (0.9655, -3.5%) |
0.0074 -> 0.0071 ms (0.9635, -3.7%) |
0.0098 -> 0.0097 ms (0.9710, -2.9%) |
0.0195 -> 0.0196 ms (1.0091, +0.9%) |
1.2843 -> 1.2838 ms (1.0014, +0.1%) |
ple_gate_norm (4 -> 2 bar) |
0.0042 -> 0.0042 ms (0.9855, -1.5%) |
0.0043 -> 0.0043 ms (0.9990, -0.1%) |
0.0048 -> 0.0049 ms (1.0143, +1.4%) |
0.0514 -> 0.0513 ms (0.9977, -0.2%) |
3.3655 -> 3.3687 ms (0.9999, -0.0%) |
ple_query_gate_norm (6 -> 3 bar) |
0.0033 -> 0.0033 ms (0.9911, -0.9%) |
0.0038 -> 0.0037 ms (0.9783, -2.2%) |
0.0050 -> 0.0050 ms (0.9974, -0.3%) |
0.0517 -> 0.0519 ms (1.0045, +0.5%) |
3.3083 -> 3.3120 ms (1.0003, +0.0%) |
ple_comb_query_gate_norm (6 -> 3 bar) |
0.0067 -> 0.0067 ms (0.9933, -0.7%) |
0.0088 -> 0.0087 ms (0.9936, -0.6%) |
0.0115 -> 0.0114 ms (0.9875, -1.3%) |
0.2365 -> 0.2361 ms (0.9985, -0.1%) |
10.6802 -> 10.6833 ms (1.0012, +0.1%) |
ple_moe_gate_norm (8 -> 4 bar) |
0.0042 -> 0.0041 ms (0.9636, -3.6%) |
0.0051 -> 0.0051 ms (0.9964, -0.4%) |
0.0068 -> 0.0067 ms (0.9840, -1.6%) |
0.0910 -> 0.0907 ms (0.9973, -0.3%) |
4.6449 -> 4.6330 ms (0.9978, -0.2%) |
ple_moe_gate_norm_c (33 -> 17 bar) |
0.0245 -> 0.0240 ms (0.9785, -2.2%) |
0.0257 -> 0.0252 ms (0.9807, -1.9%) |
0.0264 -> 0.0258 ms (0.9765, -2.3%) |
0.1105 -> 0.1099 ms (0.9852, -1.5%) |
4.6122 -> 4.6190 ms (0.9988, -0.1%) |
ple_hist_adv (unroll) |
0.0029 -> 0.0029 ms (0.9955, -0.5%) |
0.0029 -> 0.0030 ms (1.0121, +1.2%) |
0.0032 -> 0.0032 ms (1.0042, +0.4%) |
0.0023 -> 0.0023 ms (0.9902, -1.0%) |
0.0024 -> 0.0024 ms (1.0001, +0.0%) |
2. sample_parity (100% Bitwise Parity memcmp == 0 across all nv, nt, and edge-case trials) #
argmax nv=248320 nt=1 baseline 25.275 us candidate 25.307 us ratio 1.0026 (+0.26%)
argmax nv=248320 nt=2 baseline 39.385 us candidate 39.453 us ratio 0.9994 (-0.06%)
argmax nv=248320 nt=3 baseline 134.310 us candidate 134.270 us ratio 0.9996 (-0.04%)
argmax nv=248320 nt=4 baseline 178.275 us candidate 178.151 us ratio 1.0011 (+0.11%)
argmax nv=248320 nt=5 baseline 222.010 us candidate 221.879 us ratio 0.9995 (-0.05%)
argmax nv=248320 nt=6 baseline 265.524 us candidate 265.486 us ratio 0.9999 (-0.01%)
argmax nv=248320 nt=8 baseline 339.676 us candidate 337.559 us ratio 0.9911 (-0.89%)
argmax nv=248064 nt=1 baseline 5.432 us candidate 5.426 us ratio 1.0014 (+0.14%)
argmax nv=248064 nt=2 baseline 8.635 us candidate 8.628 us ratio 0.9999 (-0.01%)
argmax nv=248064 nt=3 baseline 131.288 us candidate 130.807 us ratio 0.9999 (-0.01%)
argmax nv=248064 nt=4 baseline 178.063 us candidate 178.022 us ratio 0.9998 (-0.02%)
argmax nv=248064 nt=5 baseline 206.575 us candidate 202.772 us ratio 0.9957 (-0.43%)
argmax nv=248064 nt=6 baseline 265.328 us candidate 265.270 us ratio 0.9999 (-0.01%)
argmax nv=248064 nt=7 baseline 299.301 us candidate 299.935 us ratio 1.0000 (+0.00%)
argmax nv=248064 nt=8 baseline 352.632 us candidate 352.615 us ratio 0.9999 (-0.01%)
argmax nv=40525 nt=1 baseline 3.287 us candidate 3.323 us ratio 1.0016 (+0.16%)
argmax nv=40525 nt=2 baseline 4.628 us candidate 4.622 us ratio 0.9983 (-0.17%)
argmax nv=40525 nt=4 baseline 7.477 us candidate 7.443 us ratio 0.9978 (-0.22%)
argmax nv=40525 nt=8 baseline 13.010 us candidate 13.027 us ratio 1.0011 (+0.11%)
argmax nv=7 nt=1 baseline 2.857 us candidate 2.728 us ratio 0.9549 (-4.51%)
argmax pv/pi/out bitwise + cpu: 0 wrong PASS
Patch Location #
- Clean unified diff:
/tmp/argon_r28_ple/argon_r28_ple.patch(verified withgit -C vendor/strata apply --check).