Skip to content

[Engine] Metal: opt-in routed-expert tiles (STRATA_METAL_MOE_GU/_DN); Q2_0 8,1,2 + 4,2,4 is 17-24% faster on M1 Max - #4272

Open
joseedson18jc wants to merge 1 commit into
Niko1221:mainfrom
joseedson18jc:m1-q2_0-expert-tiles
Open

joseedson18jc wants to merge 1 commit into
Niko1221:mainfrom
joseedson18jc:m1-q2_0-expert-tiles

Conversation

@joseedson18jc

Copy link
Copy Markdown

Problem and result

On the M1/M2 family the routed experts of a Q2_0 pack run with the gate/up tile 32,1,4 and the down tile 8,1,4 (the Q2_0 down is moe_down_142). On an M1 Max these are not the fastest tiles that moe.metal already instantiates. expert_parity --bench (Q2_0 gate/up + down, synthetic, M1 Max 64 GB):

tokens 32,1,4 + 8,1,4 (default) 8,1,2 + 4,2,4
1 114 us a layer 94 -17%
2 214 167 -22%
3 318 242 -24%

Live (Qwen3.8-Flash-Next Q2_0, --spec 2 + MTP, through serve/server.py) this is +5-7% greedy decode. This PR adds the tiles as an opt-in knob and does not change any default.

Related discussion

#4238 does the same for the K quants on M1/M2 (gate/up 8,1,2) and leaves Q2_0 on the M5 tile. This is the Q2_0 counterpart, as an env knob rather than a default, because it was measured on one machine.

Approach

STRATA_METAL_MOE_GU / STRATA_METAL_MOE_DN ("L,R,S") in metal/src/engine/window.cpp, read once:

  • Both expert windows read it: the decode moe block and mtp_encode.
  • gx_gu / gx_dn and the threadgroup widths follow the chosen tile, since they are computed from the same variables.
  • Only tiles in GU_SET / DN_SET (the ones moe.metal instantiates) are accepted. Anything else is refused with a log line, and the default stays, so a typo cannot fail pipeline creation.
  • The chosen tile is logged once (strata metal: STRATA_METAL_MOE_GU=8,1,2).
  • Unset, the code path and the tiles are unchanged.

Validation

Passed:

Failed:

  • none observed

Not run:

Limits

…perts' tiles as an opt-in knob

Both expert windows (decode and MTP) read "L,R,S" from the environment; only tiles moe.metal instantiates
(GU_SET / DN_SET) are taken, anything else is refused with a log line and the default tile stays. Unset,
nothing changes.

M1 Max, Q2_0 pack (Qwen3.8-Flash-Next), 26 Oct 2026:
- expert_parity --bench: gate/up 8,1,2 + down 4,2,4 against the default 32,1,4 + 8,1,4 cut the expert block
  17-24% at 1-3 tokens (114 -> 94, 214 -> 167, 318 -> 242 us a layer); parity y rel L2 5-6e-8, PASS.
- Live A/B (bracketed B C B C, on 0.1.51 + Niko1221#3301): greedy 32.7 / 34.0 -> 35.8 / 35.7 tok/s, sampled
  31.1 / 32.4 -> 33.8 / 33.3.

Same idea as Niko1221#4238 (M1/M2 tiles for the K quants), measured here for Q2_0.
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.

2 participants