Repository navigation
Conversation
|
Thanks @Defilan. This is the first slice as we agreed it on #2270: world 3 plans, writes and reads back its rank
One note, no change needed: nothing tests that |
… and four Hash the files the prepared cache writes on a synthetic pack with eight output groups, hash the decode, DSpark, prefill and prefetch output of the emitters, and add world four to the pinned plan fingerprints. Every digest was captured on main with no production code changed, so a later change to how ranks are planned has to keep these bytes.
plan.build accepts a world of 3. Output groups split 3/3/2 by canon.partition, ties to the lower rank, so heads are 24/24/16. wq_b columns, wo_b rows and the attention sink follow the groups; expert and vocabulary slices keep whole blocks (768 each, 337/337/336). Worlds 1, 2 and 4 get the same split as before, and their pinned plans and rank files are unchanged. canon's rule sits outside the sources the prepared cache hashes, so its key now holds the rank's groups. Serving still refuses three ranks, now before the pack opens, because the exchanges don't exist yet.
block, block_attn, block_prefill_attn, block_prefetch and dspark_emit divided heads and output groups evenly by the world. They now take the rank's share, and block.emit accepts a world of 3 so host tests can reach them. Worlds 1, 2 and 4 emit the same calls, pinned on main. Prefill at 24 heads stays Unsupported until it has a kernel, and serving still refuses three ranks before anything is emitted.
c5ae6e6 to
fe8148d
Compare
|
Thanks @ashhart. The branch is now at
Agreed on Could you approve the CI runs on this head? They've been waiting on first-contributor approval. I pushed these changes first so you'd only have to approve once. |
|
Thanks @Defilan. The world 1 and 2 prefill pins are what we asked for, and keeping both tests is fine. You're right about |
fe8148d to
a91cd59
Compare
|
@ashhart here's the rebuild time at TP2 on my nodes: about 10.5 minutes to weights loaded on a first boot, against about 5 on a later one. Each rank's folder is 98.4 GiB.
The first column is wall clock from each rank's The one-time cost I actually measured is 5 min 1 s, on rank 1. A boot waits for its slower rank, so it would be about 6 minutes if rank 0's later boot matches rank 1's, but I didn't measure that one. 177 to 181 s of every row comes before the weights loop, which is where Setup: two GB10s, driver 580.178.04, local NVMe, page cache dropped before each boot. The pack is 197 GiB, EXL3 2.9 bpw: LibertAI's, with an overlay that keeps its layout. World 2, What to know about these numbers:
For the line, maybe: "their prepared folders rebuild once after upgrading, about 6 extra minutes at TP2 on two GB10s (#2325, part of #2270). Thanks to @Defilan." Change it however you like. I'll send the |
What this changes
Before,
deepseek_v41refused a world of 3 and its plan, rank files and emitted calls all assumed an even head split. After, it plans three ranks with output groups split 3/3/2 bycanon.partition(heads 24/24/16), writes and reads back their rank files, and every head- and group-sliced site takes the rank's own share. Serving still refuses three ranks.atc overlap --json: run 2026-11-06 19:12Z onfe8148d8e, with main atc3f64ca8a. On its own it returnscomplete: false, so I read the full file lists of all 224 open pull requests. Four share a code file with this branch, andatc overlap --pulls 1665,1924,2030,2379 --jsonis complete for them. dsv41: serve structured output with the lane core's grammar masks #1665 is clean. It reports conflicts on DeepSeek-V4.1: read the pack's weight spans past the page cache (core/direct_io) #1924, DeepSeek-V4.1 TP=2: every-rank receipts and opt-in per-layer hash files for repeat divergence (#1395) #2030 and DeepSeek-V4.1 on CUDA: refuse a malformed TF_DSV41_* setting by name before loading, and register the ones that change outputs #2379, inCHANGELOG.md,cuda_model.zigandCHANGELOG.md, and each one conflicts in the same file with main alone. A further 83 share onlyCHANGELOG.md, and ATC's time limit stops it finishing those, so I test-merged all 87 against this head and against main withgit merge-tree: 28 are clean, 58 conflict the same way with main alone, and one, Qwen3.8-27B on a Mac: the disk staging permit takes one whole state at its context #2388, gains aCHANGELOG.mdconflict from this branch's line. That's a one-line fix for whichever lands second.Decisions to check:
wq_bcolumns,wo_brows and the attention sink follow the rank's output groups. Expert and vocabulary slices keep whole 128-column blocks (768 each, 337/337/336).block.emitnow accepts a world of 3, because host tests can't reach the emit sites otherwise. A newblock_admission.servingrefuses three ranks before the pack opens, inModel.openandgate_decode_tp, andnativePrefillstill refuses too. The remaining planners,gate_forwardandtool_main, are fixed at world 2.aot_needsandcalls_checktake their world from the environment or a capture's metadata, so they can now emit world 3 calls. They only emit and check, with nothing running on a device.dspark_emit.zig, which the issue's list doesn't name, because the same even split would be wrong there.canonis now imported by the family's module and byload_prefetch_host. Its rule sits outside the sourcesprepared.zighashes, so the cache key now holds the rank's groups.prepared.sourceshashes these files. The bytes they rebuild to are pinned unchanged. I haven't measured how long that takes at TP2 yet.Unreleased, so new entries at the top don't conflict with it. Drop or move it as you prefer.Review requests:
emit_pins_test.zignow pins prefill at worlds 1, 2 and 4, in the first commit. Digest captured on main's codetest-dsv41-forwardpassed on main's production code with the pin in place. Three new planted bugs at worlds 1 and 2 fail it by name.prefill_heads_test.zigalready pinned those two worlds on main, so this overlaps it, and it can go if you'd rather not carry bothcanon: every family module gets it throughshared.moduleAtcompile-dsv41-cuda(below).compile-dsv41-serverfails on main tooChecks on this head
a91cd5925, basec3f64ca8a. The checks below ran onfe8148d8e; the only change since is "Thanks to @Defilan." inCHANGELOG.md.python3 tools/zig/lean_check.py, on the base and on this head: 210 and 210 bytools/zig/lean_new.py, 0 new.zig build test test-golden -Dcpu=apple_m1: 11001 passed, 0 failed, 89 skipped, 720/720 steps.zig build dev-tools: 234/234 steps.zig build test-dsv41-forward test-dsv41-shared compile-dsv41-forward compile-dsv41-shared test-load-prefetch-host test-cuda-host: 925 passed, 0 failed, 4 skipped, 336/336 steps.zig build test-dsv41-cuda-host test-dsv41-device-host test-dsv41-bounds-host test-dsv41-sm-host test-draft-dsv41-host test-dsv41-serve-line-host: 580 passed, 0 failed, 2 skipped, 40/40 steps.zig build compile-dsv41-cuda compile-dsv41-server compile-dsv41-tool compile-dsv41-device-host compile-dsv41-sampler compile-dsv41-runner compile-dsv41-draft compile-dsv41-forward compile-dsv41-kv compile-dsv41-shared compile-dsv41-engram-alloc-aarch64 compile-dsv41-token-map compile-cuda-contract-consumers dsv41-prefill-heads: 13 of 14 pass.compile-dsv41-serverfails withzig/src/server/clef_systemone.zig:5:25: no module named 'lanes' available within module 'root'. It fails the same way on main alone, checked atb3933ecd3, and neither that file nor the build files behind it have changed since.zig fmt --check build.zig zigandgit diff --check: clean.test-dsv41-forwardfailed on every one (list below).compile-dsv41-cudaor a Linux serving build, so CI may not cover those steps, which is why I ran them above.kernel-contract, because no kernel changes. Linux is compile-only here, the 14 steps above. Two lines no test can distinguish yet: thegroupslines atblock_prefill_attn.zig:221and:278. Ranks 0 and 1 stop atUnsupportedfirst, and rank 2's two groups equal the old 8 / 3, so a planted even split there can't fail until 24-head prefill exists.The 24 planted bugs
wq_bandwo_bignore the output groups; world 3 stays refused; other uneven worlds admitted.canoneach send ties to the higher rank; a rank's slices all start at zero;wo_atakes the wrong groups;wo_a's local index is off; a column split reads from the first tile.Receipt
fe8148d8e, Zig 0.17.0, Xcode 27.1 with Metal 32023.921, Apple M5 Max, macOS 27.0.1, 128 GB. No checkpoint: rank files are checked on a synthetic pack.test's available Metal checks, thoughmetal/has no notion of a world, so those checks don't exercise this change. Not run: CUDA on any SM, including the GB10, which comes with the device gate; HIP; Windows; the desktop and mobile apps.tools/bench_concurrent.py --alone --serialortoken_shaagainst"draft": false: not run. The evidence for this slice is byte-identical output: worlds 1, 2 and 4 keep their plan fingerprints, rank-file digests and emitted calls (decode, DSpark, prefill and prefetch), pinned on main. The TP2token_shacomparison is gate item 1, before serving, on my GB10s.tools/bench_openai.py: not run. The calls are pinned identical at worlds 1, 2 and 4. The only added work is a host-sidecanon.partitionat each emit site, which I haven't measured.Checklist
This change reaches inference, but with no device run yet I've left these unticked rather than claim them. They come with the device gate:
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo.--drafter, no slower than without it, greedy and sampled.