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.
This was referenced Oct 27, 2026
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.
akol1
force-pushed
the
qwen27/pair-tests
branch
from
October 27, 2026 03:58
51d0707 to
dff7857
Compare
akol1
marked this pull request as ready for review
October 27, 2026 04:32
Owner
|
Keep this gate. It's the right one:
When the seam is exact, both fixtures should pass with no exemption. |
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
tf-qwen27-tp-check, a test program thatzig build testbuilds and launches, so the 27B pair has a gate that runs on one Mac. Stage 1 loads the model, then rank 1 throughloadShard, and requires bit-identical greedy ids, logits bytes and prompt-state digest. Stage 2 starts two rank-local shards joined bypair.Loopback, a host-memory link, and requires both ranks to emit the same ids;bad_pick_at,seam_gave_up_rank0andseam_gave_up_rank1report any time the merge handed a reply to a rank that did not produce it, or the seam gave up on a partial. Stage 3, the default, runs both and--stage 1|2narrows it. The program needs--model, so CI'szig build teststarts it, getsSKIP qwen27-tp-check: no --model DIR, and carries on; a real run happens on a host that has the checkpoint.zig/qwen27_core.zigexportspairso the test can reach the seam.Refs #1236, the tracker for tensor-parallel ranks: this gate pins the stack's 27B pair against its own single-Mac path, and does not touch the mixed Metal/CUDA case that issue is about. Stacked on #1432, #1433, #1434; the diff against
maincarries them too, so review this pull request's own commit,dff7857f.Receipt
8c36359dplus this commit (dff7857f); no MLX or PyTorch; macOS 27.0.1 on an Apple M4 Pro (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; one Mac, both ranks on it.tools/bench_concurrent.py --alone --serialortoken_shaagainst"draft": false: stage 1 is byte-identical —shard1_tokens_equal: true,shard1_logits_byte_equal: true,shard1_first_logits_difference: null, prompt-state digestf46a40128a4d7399b71be2bc1fe1f3ba4aad902844b91124d618bde86c746b68on the 31-token chat fixture (128-token chunks, 256 steps), and19232096256resident bytes for the model against19235241984for shard 1. Stage 2 givesranks_token_equal: trueon both fixtures andreference_token_equal: falsewithfirst_difference: 236on the chat fixture and7on the 4-id fixture: at the chat tie one Mac's top two are17077/24.625 and369/24.5 while the merged pair's are369/24.625 and17077/24.625, the bf16 reduction-order tiedocs/known-issues.mdcarries and the same tie the oracle records forchat-256as58daf9743077.bad_pick_atisnulland both seam give-up counters are0on both fixtures.tools/bench_openai.py: n/a — this is a test program, not a serve, and it reports no timings. It does drive both paths: the 4-id fixture at--chunk 1on the decode path and the chat fixture at--chunk 128through the prompt kernels.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 program this commit adds is the skip named above, andtf-qwen27-tp-check --stage 1and--stage 2were run by hand at this tree with the counts quoted in Exactness (both fixtures, 0 failures, stage 1 byte-identical).pair.Loopback, so that link's receipt is the served path's, not this program's; CUDA, HIP/RDNA, M1-M3, M5 and Windows are absent here; and there is no maintainer-agreed gate for a tensor-parallel family —zig/gate.jsonhas no entries at8c36359d— so this gate is the stack's own and is offered for the maintainer to replace.Checklist
RunnerandSessiondirectly, the same rounds both ranks run, and adds no serial path and no drafter requirement."draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. — n/a here: the program serves no HTTP and takes no drafter; the pair's refusals are exercised by the served path's tests and receipt.SUMMARYline is in the receipt. — this commit adds no kernel; it drives the registered qwen27 kernels through the pair, and the pair's own four are registered in the first pull request.SKIPline and exits 0.