Repository navigation
Single-Mac GLM-5.3-Flash native fixes without JACCL - #37
Merged
Merged
Conversation
Upstream ml-explore/mlx c7ff35d ("Skip unnecessary simdgroup computations for quantised MOE matmuls on NAX", ml-explore#4352) reached this fork through the v0.32.2 squash (734241b), not by ancestry, in the form that ml-explore#4572 later gave it: `const bool sg_active = sgp_sm > 0;` and two `if (sg_active)` blocks around the MMA loop in each of fp_gather_qmm_rhs_nax (fp_quantized_nax.h) and affine_gather_qmm_rhs_nax (quantized_nax.h). This removes the flag and runs the MMA in every simdgroup again, as before ml-explore#4352. It is the same change as the earlier revert of ml-explore#4352 on 0.32.2 (e9debbe) and its re-application on the 0.32.3 kernels, hand-ported because the surrounding lines differ here. Why: these kernels run only on GPUs with NAX. On a two-Mac JACCL pair with one NAX GPU, mixture-of-experts serving with the skip present lost all-reduce completions, and 92 to 96 GiB stayed wired on the host until it was rebooted. The builds that served that pair afterwards carried the revert. It is therefore kept out of every build that runs distributed on mixed hardware. Output is unchanged: stores stay bounded by sgp_sm, and the rows past the tile that the MMA now reads are either inside M (rows_in_bounds) or loaded as zeros by load_safe with sgp_sm rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit ccf517a)
Use the remaining reduction width for the final activation tile. Check row and packed-column bounds before reading affine or floating-quantized weights and scales, then zero padding lanes. Add exact-value partial-tile and NaN-neighbor regression coverage for affine, MXFP4, MXFP8 and NVFP4. The companion Swift regression reproduced 48 failing geometries and passes all 272 cases with this repair. The original MiMo and Qwen fallback failures also pass on M5 Max. AI assistance: Codex diagnosed, implemented and tested this patch under the repository owner's explicit direction. (cherry picked from commit eb576eb)
(cherry picked from commit 65eb14f)
(cherry picked from commit f7bbf7d)
(cherry picked from commit 1fb86d3)
(cherry picked from commit adbc349)
(cherry picked from commit 9e22e19)
Keep the allocation bound stable before and after process cap installation. Add real ordinary/capped boundary coverage without changing allocation, ownership, process-cap enforcement or the policy ABI. Document the bound. Implemented and validated with OpenAI Codex. (cherry picked from commit 4d91320)
…mensions Prefault capped no-copy backing before handing it to Metal. Add a one-shot JACCL startup wait budget with C-facing group operations and failure cleanup tests. Validate custom Metal launch dimensions and bound the 1024-thread pipeline retry to the declared geometry. CPU policy, bridge, allocation-ledger and evaluator regressions pass. Native GPU and end-to-end qualification are tracked separately. Single-Mac release split: this pick keeps only the Metal half (CPU prefault of capped no-copy backing, validated custom-kernel launch dimensions and the bounded pipeline retry). The JACCL startup wait budget and its group API stay on darkbloom/sealed-all-sum with the rest of the two-Mac code. (cherry picked from commit 54975cd)
(cherry picked from commit 3a17911)
This was referenced Oct 21, 2026
Merged
Merged
This reverts commit 99dc5f4.
The file still differs from upstream (capped no-copy backing paragraph), so its glob stays in the allocator accounting section.
jonathan308
marked this pull request as ready for review
October 21, 2026 17:16
This was referenced Oct 22, 2026
jonathan308
added a commit
that referenced
this pull request
Oct 26, 2026
…ectives branch Brings in merge/33 at 187b6c6, which is main f78f0fa (the upstream ml-explore/mlx sync to afc03c5 with its restored history, and the fork fixes #40, #43-#46) merged into the JACCL send-frame and progress-guard branch. This branch had merged main up to ad4745a; everything main added since comes in here. Conflicts and how they were resolved: - mlx/fence.h, mlx/backend/{metal,cuda,no_gpu}/fence.cpp, mlx/transforms.cpp: main's value-based fence API (upstream ml-explore#4552: update returns a value, wait takes it) with this branch's fenced inputs and eager commit. Fence::wait_in_consumer now takes the value of the update it waits for, and FencedInput carries that value, so a fenced input never waits for a later update than its own. The Metal fence keeps the two-word buffer of the fused coherent update, now owned through main's allocator::Data. - Metal fast fence wait: this branch orders the spin with wait_for_all_pending (the pass waits for every pass in flight). Upstream ml-explore#4689 gets the same order by putting the spin in a pass of its own (end_encoding() before it, end_encoding(true) after it). The merge keeps the spin in the current pass and adds a buffer barrier after wait_for_all_pending, so it also follows the earlier kernels of the same pass, as upstream's separate pass does (the same line that the next branch, fix/cluster-metal-fence-wait, adds). A wait adds no encoder boundary; tensor-parallel decode waits for a CPU-stream all-sum about twice a layer. end_encoding(bool wait_in_flight) stays and shares one loop with wait_for_all_pending. - docs/src/usage/environment_variables.rst: both sides' entries (MLX_METAL_FUSED_FENCE_UPDATE, MLX_METAL_FENCED_INPUTS, MLX_CONV_WINOGRAD). - fork.yaml: the merged JACCL branch's file plus this branch's sections (startup readiness, two-rank sealed all-sum, fused fence update, fenced inputs, cheaper custom-kernel launches). The fenced-input section now explains the fence-wait order against upstream ml-explore#4689 and the value-based waits. The "not fork work" backport section is gone (upstream ancestry). Also adapted: - mlx/distributed/jaccl/lib/jaccl/mesh.h: main's mesh has one MeshImpl per wire (upstream ml-explore#4607). The startup wait budget goes to every wire; the two-rank exchange of the streamed sealed sum runs on the first wire. The two-Mac cluster's device matrix has one device per peer, so it has one wire and nothing changes for it. Unchanged by the merge: main's quantized, matmul and SDPA kernels and their dispatch (this branch had no change there beyond what main already carried since #37), main's revert of the upstream ml-explore#4352 simdgroup skip, and this branch's revert of 4d91320 (main does not carry 4d91320; the footprint policy keeps {page, page, 0, 0, page}). Tests (Ultra A, M5 Ultra; Debug build with Metal, 8 jobs): - tests/tests on the GPU: 310 of 316 cases passed. The 6 failures (linalg QR, inverse, Cholesky, pseudo-inverse, eigh, LU) fail the same way on main f78f0fa on this machine. - tests/tests with DEVICE=cpu: 316 of 316 passed. - ctest process_allocation_cap: 15 of 15 passed. - check_forkdiff.py --upstream-ref upstream/main: 137 changed files, all described, base afc03c5 is the merge-base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Update 2026-10-21: merged main
The head is now
ad596687:mainmerged in (mlx#36, thread-scoped command-buffer commit limits, the Nemotron 3.5 Super native prerequisite). No conflicts.scripts/check_forkdiff.pypasses (190 changed files, all described). The Metal library built from this tree is unchanged (156f2624…); #36 changes host code only.Update: production footprint charges restored
The head is now
6ee3062c.4a355746reverts99dc5f42(the one-page minimum inget_allocation_footprint_policy()), so the Metal footprint policy is again{page, page, 0, 0, page}, the same as the core the current provider release ships.6ee3062ckeepsdocs/src/usage/unified_memory.rstinfork.yaml, because the capped no-copy paragraph still differs from upstream.Why: with the page minimum, the SDK's allocation estimates for MTP drafters that declare no buffer layout (Qwen4 inline MTP, NemotronH35 MTP) grow from about 4.5 KB to 37–671 MB per token, so those requests can never be admitted, and Qwen3.5 MTP's partitioned buffers cost about 32 KB more per token. This release is for GLM-5.3-Flash and must not change how other models are charged. Nothing in the provider or the SDK installs the allocation cap whose page-backed fallback the minimum covered.
Effect on GLM: the serving MTP charge is 4.05 GB per request (4.89 GB with the minimum). It was rechecked on one M5 Ultra with the rebuilt chain (d-inference ml-explore#1516
15d7a833d,darkbloom94a83e27…, metallib156f2624…unchanged): admission flood, concurrency, 125K context, SSD prefix restore across a restart and a 20-minute soak. See ml-explore#1516.The source otherwise matches
2bba342d:git diff 2bba342d 6ee3062ctouches onlymlx/backend/metal/allocator.cpp(one line), its docs paragraph, the standalone cap test cases that asserted the minimum, andfork.yaml.Summary
The single-Mac native core for GLM-5.3-Flash. It holds the ten general commits from
darkbloom/sealed-all-sum(#35) that one-Mac serving needs, replayed ontomain, with none of the two-Mac code.Until now, the single-Mac release (d-inference #1516, mlx-swift-lm #314) pinned core
3a179119. That commit exists only on the cluster stack (#33 → #35), so the single-Mac release could not merge before the JACCL and sealed all-sum work. This branch removes that dependency.b7434f7fccf517a00077571eeb576eb26beeabd865eb14fae3799f23f7bbf7d7d02ac7771fb86d3f9266fda0adbc349b2a0c9bbb9e22e19999dc5f424d91320423164b8b54975cd0(Metal half only)2bba342d3a17911954975cd0mixed two things: the JACCL startup-wait budget and Metal fixes. Only its Metal half is here. The startup-wait budget and its group API stay ondarkbloom/sealed-all-sum, together with the JACCL send-frame/progress-guard/GID fixes, the upstream JACCL backports and the sealed all-sum.Before
After
Evidence
git diff 3a179119 2bba342d -- . ':!mlx/distributed' ':!tests/jaccl' ':!fork.yaml'lists only six cluster-only files: the distributed and environment-variable docs,mlx/backend/cpu/distributed.cpp, and three distributed Python test files including thescoped_envhelper.mlx/distributed/andtests/jaccl/are identical tomain. Every Metal kernel source matches3a179119byte for byte.scripts/check_forkdiff.py --upstream-ref upstream/mainpasses, with 189 changed files and all 189 described.fork.yamlis the3a179119version with three sections removed: JACCL, two-rank sealed all-sum, and the upstream JACCL fixes.scripts/fetch-metallib.shin the d-inference [BUG] vmap over function returning constant value has incorrect output shape ml-explore/mlx#1516 worktree buildsmlx.metallibfrom this branch with sha256156f2624f9f1b1413dfabd8b6e16423121b0e5b18e2573c23c4e023b606a462d. That is byte-identical to the metallib built from3a179119on the same Mac and toolchain (Xcode 27.1).-c release, Xcode 27.1 / Swift 6.4) builds and links on the full single-Mac chain (mlx2bba342d, mlx-c2f1bcab9, mlx-swiftcf921c05, SDK3ab6dd68).darkbloomsha256 ise863e668…. No model was loaded with this build; end-to-end single-Mac qualification is the next gate.Relationship to the cluster stack
#35 keeps its commits unchanged. When this PR merges, the cluster stack has to merge
main. Its general commits carry the same patches as the ones here, so the code conflicts should be trivial;fork.yamlwill conflict and needs resolving by hand. The cluster pair (tp/pair.sh) must be re-verified bitwise after that merge.Merge danger
Door: two-way. This is a cherry-pick of commits already reviewed on #35, with no new source.
Blast radius: quantized Metal kernels (tail bounds and loader symbols), the optional allocation cap (off unless installed), footprint quotes and the custom-kernel launch retry. Kernel sources are the ones ml-explore#1516 already pinned through
3a179119.🤖 Generated with Claude Code