metal: parallel top-8 expert selection (r_top8_par), default ON

Re-derives the campaign's rtop8 breakthrough (fuse/rtop8-par @ b32439b,
commits 48b3a98 + b32439b) cleanly onto origin/dev @ 61004dc (post-#391
split), dropping the cb-chain commit (1130ac9) that branch was stacked
on. cb-chain touched only c/glm.c (now split into c/colibri.c); rtop8
touches only c/backend_metal.{h,mm} and c/tests/test_backend_metal.mm —
disjoint files, verified zero cb-chain remnants in this diff.

- r_top8_par: one SIMDGROUP per row (blocked lane ownership, taken
  bitmask, shuffle-down argmax with ties->lower-index) replicating the
  serial r_top8's first-max-wins ascending order exactly; topp/normk/
  rscale tail verbatim on lane 0. Bench: serial 0.465 ms/layer (~55% of
  the layer CB), parallel ~93x faster on the kernel, bit-exact.
- COLI_RTOP8 gate, default ON (renamed and inverted from the campaign's
  COLI_RTOP8_PAR=0-default gate; COLI_RTOP8=0 is the opt-out escape).
- Expert-count generality (new hard requirement, REAP E=168 packages):
  the parallel kernel's E<=256 contract is now enforced at EVERY call
  site in host code (g_rtop8_width_ok / E<=256 checked before selecting
  the pipeline), not just as an in-kernel defensive no-op -- closes a
  latent gap where the campaign's SIMD-width guard only protected the
  engine's automatic dispatch, not the standalone coli_metal_rtop8(par=1,
  ...) probe function metal-test itself uses. Out-of-contract requests
  (E>256, or non-32-wide SIMD) now transparently run the serial kernel
  instead of silently no-op'ing.
- metal-test: 16 new cases -- the campaign's 10-case exact-match fuzz
  (now E-parametric) plus 6 new E-generality cases: E=168 (REAP) generic
  + massed-dup-ties, E=24 (<32 lane width) generic + ALL-EQUAL ties,
  E=200 (a lane straddles the E boundary -- per=ceil(200/32)=7 doesn't
  divide 200, so lane 28's ch[] block mixes 4 real indices with 3
  sentinel ones; input is constructed to force those 4 into the top-8
  deterministically, and the test asserts they were actually selected,
  not just that serial==parallel), and E=257 (out-of-contract, proves
  the auto-serial-fallback engages: this case is confirmed load-bearing
  -- it fails without the new host-side guard). 15 stock + 10 ported +
  6 new = 31 total metal-test cases.

Builds (METAL=0/1) and full C/python suites verified unchanged vs stock
61004dc (0 new warnings, identical pass counts). On-box A/B on this
branch is pending (see PR_BODY.md) -- no model runs performed here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
monotophic
2026-07-19 16:56:14 -04:00
parent 61004dcb84
commit 9f30916003
3 changed files with 240 additions and 5 deletions
+17
View File
@@ -84,6 +84,23 @@ int coli_metal_layer_decode(float *x,
int coli_metal_gemm(float *y, const float *x, const void *weights, const float *scales,
int fmt, int S, int I, int O); /* large-batch sync GEMM; 0 -> CPU */
/* Parallel top-8 expert selection (r_top8_par): run ONE top-8 selection kernel standalone
* on host arrays — par=0 the serial r_top8, par=1 the parallel exact-match replica gated
* in the engine by COLI_RTOP8 (default ON; COLI_RTOP8=0 opts out to the serial kernel).
* Exists so the metal-test suite (and any battery probe) can prove serial/parallel
* equivalence on the ENGINE build's own compiled shaders, not just in the bench tool.
* sig[S*E], bias[E], idx[S*K], w[S*K], keff[S].
* Expert-count generality: the parallel kernel's blocked-lane design (ch[8]/32-lane
* threadgroup) is validated correct for arbitrary E<=256, including non-multiples of the
* 32-lane width and small E (see metal-test's E=24/E=168/E=256 cases — 168 is the REAP
* expert-pruned package width from #428/#426). For E>256 (out of contract) this function
* transparently falls back to the serial kernel even when par=1 is requested, and the
* same automatic fallback is wired into the engine dispatch site — "par" is a request,
* never a guarantee, so no caller can reach the unguarded parallel path out of contract.
* Returns 1 on success, 0 if Metal is unavailable. */
int coli_metal_rtop8(int par, const float *sig, const float *bias, int S, int E, int K,
int Ksel, float topp, int normk, float rscale,
int *idx, float *w, int *keff);
void coli_metal_attn_counts(uint64_t *ok, double *wall, double *kernel);
void coli_metal_attn_lat(double *ksched, double *gsched);
int coli_metal_attn_decode(const float *x,