Repository navigation
Conversation
The seam carries one round's partials between two Macs: pair.metal writes a frame, the host relay owns the exchange instead of spinning on device counters (which only works while both ranks share a launch group), and pair_sum completes the partial on the far rank. The payload is f32, the seam's accumulation, and simd_qmm grows the matching store. pair.zig splits into pair_layout and pair_loopback so each module stays under the 600-line rule. Nothing registered the seam before: three of the four kernels already ran under the older ABI on the shipped glm_dsa speed-up path, but there was no record and no spec, so no gate covered the kernels this stack changes. Add the four launch records, the seam spec with its four probes, the `metal pair ` route in the limits table, and the fp32-out simd_qmm variant, so the transport and family changes that follow have a SUMMARY to post. The glm_dsa call sites and the two Pipeline.load test call sites are forced by the shared signatures; the family changes themselves come later.
On a pair rank the embedding table is global while the vocabulary in the split config is the shard's width, so the gather bound took the shard's number and read the wrong rows; embedBound now takes the whole table and refuses a bound below it. Rank-sliced projections, the head seam, the GDN partials and the attention plan follow the same split, and the drafts-off path keeps the two ranks in lockstep. The regression test pins the old behaviour (124160) against the new (248320) and fails when the split width is used again.
7 of 9 tasks
A supervised pair has to survive an unattended night: rank 0 now waits for rank 1's handshake before it advertises /health, the first turn is warmed so the client does not pay the load, and either rank exiting takes the other down instead of leaving it serving alone. The launch script starts and stops both, with the kill/restart drill recorded in the receipt. The benchmark and TF_DUMP_IDS receipts in server/ are the support code for those runs; dump.zig and input.zig are their two halves.
tf-qwen27-tp-check runs rank-1 parity bit for bit and then joins two rank-local shards through pair.Loopback on one Mac, comparing ids against the single-host load and the forced replay. It SKIPs without a checkpoint, so the suite stays clean on hosts that have none. The module registration is the only build change.
pair_accept.py walks a live pair through the fixture set and compares each token_sha against the recorded single-host oracle, so the check needs no second reference machine. pair_supervise.sh starts rank 1 on the peer, waits for the handshake, starts rank 0, polls both health endpoints, restarts either rank if it dies, and stops both on SIGTERM. Hosts and paths come from arguments or environment only.
akol1
force-pushed
the
qwen27/pair-tools
branch
from
October 27, 2026 03:58
54957a6 to
53a0d27
Compare
akol1
marked this pull request as ready for review
October 27, 2026 04:32
Owner
|
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.
What this changes
Adds three files under
tools/qwen27/.qwen38_27b_oracle.jsonpins four single-host receipts (temperature 0, seed 1234, no drafter, one stream) with the checkpoint revision, and records forchat-256the one value a pair is accepted at and why it parts from the oracle.pair_accept.py runsends each fixture twice, requires identical replies and the oracle'stoken_sha, accepts that recorded value for its case, and prints3/4 … 0 unexpectedon a pair;pair_accept.py warmholds a two-turn conversation and requires the second turn to report cached prompt tokens.pair_supervise.sh up|down|status|watchstarts rank 1 first and rank 0 second, refuses two installs whose binaries differ unlessALLOW_MISMATCH=1, waits for both/healthports, and inwatchstops and restarts both ranks whenever either stops answering. Every location is environment overridable, and the script prints that environment from its usage text.Refs #1236, the tracker for tensor-parallel ranks: these are the harness and receipts this stack was accepted with, and they do not cover the mixed Metal/CUDA case that issue is about. Refs #808: it asked for two-Mac prompt-splitting speed with drafts and images; this stack splits rounds and refuses both, so nothing here is a retry of that report. Stacked on #1432, #1433, #1434, #1435; the diff against
maincarries them too, so review this pull request's own commit,53a0d278.Receipt
8c36359dplus this commit (53a0d278); no MLX or PyTorch; macOS 27.0.1 on two Apple M4 Pro Macs (Mac16,11), Metal only (applegpu_g16, no tensor units), Apple metal version 32023.921; checkpointTensorFold/Qwen3.8-27B-MLX-4bitat revision22d8d538154e0e5b6f8dcb1fcc74a60a0798104c, 4-bit affine with group 64, on both Macs; the two Macs joined by a Thunderbolt bridge. The three files are not compiled and need no checkpoint to read; they were exercised againstsha256 2dda0e50fad3ca10487c215820f5cd9acee83d3914ab474955659333d9e81bdf, which is this stack's native code (later commits add tests, tools and docs only).tools/bench_concurrent.py --alone --serialortoken_shaagainst"draft": false:pair_accept.py run --repeat 2against one Mac matches all four oracle fixtures on both repeats,chat-256ata06fab348fbe; against the pair it matches three, twice each, and reportsKNOWN chat-256 token_sha=58daf9743077 is the pair value recorded for this case, not the oracle's a06fab348fbe, endingpair_accept: 3/4 cases match the oracle, 1 recorded as different, 0 unexpected.pair_accept.py warmon the one-Mac arm printswarm: turn 1 prefill marked 0; turn 2 cached=158andPASS warm: the next turn resumed 158 cached prompt tokens. The supervisor confirmed matching installs (binaries match: 2dda0e50fad3), held rank 0's port until the handshake (rank 0's port refused 2 probes while the pair handshake completed), survivedkill -9on rank 0 (restarting both (restart 1), same shas afterwards), and on TERM stopped both ranks with no serve process or listener left on either host.tools/bench_openai.py: n/a — these tools time nothing. The pair/lifecycle pull request carries thedone … tok/s=lines from the same binary: 16.8 to 17.1 tok/s for the pair against 12.3 to 13.6 tok/s for one Mac.warmadds a 187-token conversation over two turns without timing a cold long prompt; the pair/lifecycle pull request owns those numbers.zig build test test-goldenat this tree: 7116 passed, 45 skipped, 0 failed of 7161, with 535 of 535 build steps; the 45 skips are the image-codec and pixel cases that need libjpeg-turbo 3.1.4.1 or libwebp 1.6.0, plusSKIP qwen27-tp-check: no --model DIR. The three files add no CI test; their own runs at this tree:pair_accept.py run --repeat 2sent 8 requests per arm — one Mac 4 of 4 cases matched on both repeats (0 failed), the pair 3 matched and 1 recorded and 0 unexpected (0 failed) —pair_accept.py warmpassed once with 158 cached tokens, andpython3 -m py_compile tools/qwen27/pair_accept.pyplussh -n tools/qwen27/pair_supervise.shwere clean.pair_accept.pyneeds a serving pair, so CI covers none of these three files; and the oracle is four short fixtures, not a corpus, so it is a regression pin rather than a release-wide benchmark.Checklist
"drafter": falsebecause the pair refuses a drafter, so they cannot check a drafted reply and the drafted path keeps its existing single-host tests."draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. — the pair refuses a prompt cache and a second stream by name, sowarmchecks resume on the one-Mac arm only and concurrency is not exercised; those refusals are the lifecycle pull request's receipt.SUMMARYline is in the receipt. — no kernel in this commit; the pair's four are registered in the first pull request.tools/bench_openai.py's shape, and the supervisor opens with two comment lines and prints its environment from its usage text instead of a header block; the lean check reports 428 problems, 428 on the base, 0 new.127.0.0.1loopback default.