Skip to content

metal: gate the M3-class fusion whitelists on the pre-M5 predicate - #770

Open
kk1987 wants to merge 1 commit into
antirez:mainfrom
kk1987:metal-m4-fusion-whitelist
Open

metal: gate the M3-class fusion whitelists on the pre-M5 predicate#770
kk1987 wants to merge 1 commit into
antirez:mainfrom
kk1987:metal-m4-fusion-whitelist

Conversation

@kk1987

@kk1987 kk1987 commented Aug 10, 2026

Copy link
Copy Markdown

Fixes #769.

The exact-fusion campaign's newest decode ports gate on ds4_gpu_ported_m5_decode_feature_enabled(), whose pre-M5 predicate already admits M1–M4. The older fusion sites still used literal device_name_contains("M3") || ("M5") whitelists, so pre-M5 devices other than M3 silently skipped fifteen eligible fusions, and ds4_test failed its 29 forced-fusion exactness assertions there because the entry points refuse to run at all.

This switches those fifteen sites to the same predicates the ported gate uses: is_pre_m5 || is_m5 where M5 was admitted, plain is_pre_m5 for the M3-only sites (those screened negative on M5, so M5 stays out). Net −15 lines. Left untouched: the Metal 4 tensor API sites and the M5 private-scratch heuristic (pre-M5 hardware lacks them), and the router SIMD sites (already on the predicate). ds4.c needs nothing.

Verified on M4 Max 128 GiB, DS4F 0731 IQ2XXS resident:

  • make test goes from 29 failures to fully green, including the bit-exact fused-vs-reference comparisons for both previously failing kernels.
  • Per-fusion A/B with metal_decode_schedule_bench / metal_prefill_variant_bench, 3 samples per fusion, cool-down rounds, medians; every run bit-exact over the full vocabulary with identical token selection:
fusion side median
zero-prefix prefill mask cache prefill +4.5%
inplace/affine RoPE pair decode +3.8%
gathered KV stage decode +1.8%
persistent zero attention mask decode +0.8%
router weights batch prefill +0.8%
remaining nine both neutral (±0.15%)
  • Full ds4-bench curves (ABBA, this branch vs main, 32 ctx points): median generation +1.55%, prefill +0.7%.

On M1 Ultra 128 GB, an equivalent generalization measured roughly 23.5 → 25 tok/s generation on an empty context (thanks @lmr — see comments). M2 has no tester, but every site keeps its DS4_METAL_DISABLE_* rollback and the forced-fusion test assertions now cover any device the predicate admits.

A benchmarking note: on a MacBook the numbers drift heavily once thermal throttling kicks in — enough that two prefill deltas came out with the wrong sign on back-to-back hot runs. The numbers above are cool-down multi-round medians.

🤖 Generated with Claude Code

@lmr

lmr commented Aug 12, 2026

Copy link
Copy Markdown

Just as a comment, I made a more generalized version of your change to admit any pre-M5 hardware to these M3-class fusion whitelists and it seems to work well on my M1 Ultra 128GB. I would have to get the precise benchmark numbers to validate it, but I am getting around 25 tops of generation on an empty context, which is better than I had before (23.5 on an empty context, consistent with what another M1 Ultra user reported in #706).

@lmr

lmr commented Aug 12, 2026

Copy link
Copy Markdown

So I can test a more generalized version of your PR in case you want to make it (or leave it like this since we don't have an M2 user to verify it on that hardware too).

The exact-fusion campaign's newest decode ports gate on
ds4_gpu_ported_m5_decode_feature_enabled(), whose pre-M5 predicate
admits M1-M4. The older fusion sites still used literal M3/M5
device-name whitelists, so pre-M5 devices other than M3 silently
skipped fifteen eligible fusions and ds4_test failed its 29
forced-fusion exactness assertions there (pair compressor store,
gathered KV staging) because the entry points refuse to run at all.

Switch the fifteen sites to the same predicates the ported gate
uses: is_pre_m5 || is_m5 where M5 was admitted, plain is_pre_m5 for
the M3-only sites (those screened negative on M5, so M5 stays out).
Metal 4 tensor API sites and the M5 private scratch heuristic are
unchanged (pre-M5 hardware lacks them); the router SIMD sites
already use the predicate; ds4.c needs nothing.

Verified on M4 Max 128 GiB with the DS4F 0731 IQ2XXS GGUF: ds4_test
goes from 29 failures to fully green, per-fusion A/B medians reach
+3.8% decode (RoPE pair) and +4.5% prefill (zero-prefix mask cache)
with every run bit-exact, and the full ds4-bench curve improves
+1.55% median generation over 2K-64K. An equivalent generalization
measured ~23.5 -> 25 tok/s empty-context generation on M1 Ultra
128 GB (reported by lmr on the PR).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H58vqtiLFWWWAbcB7oHAp8
@kk1987
kk1987 force-pushed the metal-m4-fusion-whitelist branch from 7ed2b8f to dfea3a7 Compare August 13, 2026 06:29
@kk1987 kk1987 changed the title metal: admit M4 to the M3-class fusion whitelists metal: gate the M3-class fusion whitelists on the pre-M5 predicate Aug 13, 2026
@kk1987

kk1987 commented Aug 13, 2026

Copy link
Copy Markdown
Author

Nice, thanks for testing! That M1 Ultra bump matches what I'd hope for — the RoPE pair fusions were the biggest single win on M4 too.

I've switched the PR to the pre-M5 predicate: is_pre_m5 || M5-name for the sites that admitted M3/M5, plain is_pre_m5 for the M3-only ones (those are the fusions that screened negative on M5, so M5 stays out). Nobody can verify M2, but every site keeps its DS4_METAL_DISABLE_* rollback and ds4_test's forced-fusion assertions now cover any device the whitelist admits, so an M2 user would find out quickly and can opt out per fusion.

If you want precise M1 numbers, the harness I used: ./speed-bench/metal_decode_schedule_bench -m model.gguf --candidate-env DS4_METAL_DISABLE_INPLACE_ROPE_PAIR --include-selection (same for the other DISABLE names) — it aborts unless both variants are bit-identical. One caveat from my runs: on my MacBook the numbers drift heavily once thermal throttling kicks in, enough that two prefill deltas came out with the wrong sign on back-to-back hot runs. Letting the machine cool down before each run and taking the median of 3 runs was what it took to get numbers that were stable run-to-run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ds4_test fails 29 fusion assertions on M4 — fusion whitelists only admit M3/M5 device names

2 participants