Skip to content

Perf: compiled GeGLU product for Gemma4 MoE experts (remaining piece of mlx-swift-lm#27) #236

Closed

Description

@solderzzc

Tracks what is still worth taking from the closed-for-now draft SharpAI/mlx-swift-lm#27 (2026-04, 8 commits, conflicting with main). Issues are disabled on mlx-swift-lm, so this lives here.

What #27 set out to do

  1. GDN: fp32 recurrent state and asyncEval chunk pipelining in prefill (DFlash: generation ignores EOS and outlives the stream; the next request overlaps it and crashes the server (flaky dflash-speculative-decoding job) #224, fix: stop DFlash at end-of-sequence, and cancel it when the stream ends early #225)
  2. Fuse silumul / gelumul into one compiled Metal dispatch (compiledSwiGLU, compiledGeGLU)
  3. Review follow-ups: keep SwitchGLU intermediates in the original dtype (a gatherQuantizedMM NaN on pre-M4 GPUs), contiguous-array signatures to dodge an MLX Swift segfault, no unconstrained .float32 promotion in GELU

Already on main (checked against SharpAI/mlx-swift-lm main 4d76a2e and ml-explore/mlx-swift-lm main 48114ee)

  • (1) is covered: GatedDelta.swift keeps state in .float32, and LLMModel.swift prefill pipelines chunks with asyncEval.
  • The SwiGLU half of (2) is covered: SwitchLayers.swift has compiledSiluProduct and SwitchGLU.activationProduct; upstream also has weightedExpertSum and Gemma4Fusions.swift (compiled softcap).

Still missing

  • Gemma4 MoE experts use an uncompiled GeGLU. Gemma4Text.swift builds SwitchGLU(..., activation: geluApproximate), and the SwitchGLU forward paths compute activation(xGate) * xUp as two dispatches. Only the per-layer-input gelu*mul (_geluMul) is compiled. A compiled gelu-product for the MoE path is the remaining piece of test: add speculative decoding E2E test to CI pipeline #27's fusion idea.

Before doing it

  • Measure first: tokens/s and prefill time on gemma-4 MoE (e.g. 26b-a4b) with and without the fused product. test: add speculative decoding E2E test to CI pipeline #27 shipped no numbers.
  • Re-check the pre-M4 gatherQuantizedMM NaN claim on an M1/M2 machine before copying the dtype downcast; it may no longer reproduce on mlx 0.32.3.
  • Do it on current main, not by rebasing the old branch (it is based on a 2026-04-19 tree and touches files that moved, e.g. GatedDelta.swift is now in MLXLMCommon).
  • Drop the stray run_test.py and test_gemma4_crash.swift from the old branch.

Activity

  1. solderzzc commented on Oct 29, 2026

    @solderzzc
    MemberAuthor

    Done in SharpAI/mlx-swift-lm#91 (merge commit 7e235090629d35b2247b30ee4932d64ed43ec070): a compiled geluApproximate(gate) * up product for the Gemma 4 MoE experts, used on every SwitchGLU activation path.

    Measured on gemma-4-26b-a4b-it-4bit, A/B interleaved, 4 rounds x 3 runs, machine under load: decode median 62.6 -> 65.1 tok/s (about +4%), ~3k-token prefill time to first token 2.13 -> 2.03 s (about -5%). Fused was faster in 3 of 4 rounds; the run-to-run drift was larger than the gap, so treat it as a modest, not a precise, gain.

    Not done: the pre-M4 gatherQuantizedMM NaN claim was not re-checked (no M1/M2 here), and generated text was not diffed between the two builds (numerics are covered by unit tests only). Reopen or file a new issue if either matters.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions