Repository navigation
dsv41 metal: the lane target, the prompt cache and the native server over Metal - #1720
Conversation
bfcd533 to
2b0d77e
Compare
|
The full-model receipt in #1720 and #1722 is now from the stack's final head,
Each number is within 1% of the pre-rebase run. The 4 x 912K memory gate is still the 29 Oct run, as the bodies say. |
1840d05 to
f647501
Compare
|
Thanks @gilby. The code holds: no new kernel, the target refuses wrong slots, bad tokens, position and row mismatches, tree windows and non-prefix keeps, the lanes keep DeepSeek's opt-outs, the prompt cache is an exact token-prefix store under a byte cap, and CUDA is unchanged. Exactness is shown (concurrent = solo = serial, drafted = draft:false, cache hits = fresh; full model 0 unequal of 8 cells), and drafts are faster in all four single-stream cells (53.8/50.5/43.8/44.2 against 35.4/34.8/35.4/34.6 tok/s). One ask, a receipt, so never-slower can be checked: bench_concurrent at 1 and 4 streams with --no-drafts, and a 32,768-token cold first request with and without drafts. Small: adding logits to an existing entry can briefly exceed the cache cap, and the 4x912K memory gate isn't re-run on this head. |
f647501 to
26f52c1
Compare
a05bbb4 to
87436e1
Compare
|
Thanks @gilby. We compared this push with the version we reviewed. The only change is one build line, the lane test now importing |
|
Thanks @gilby. #1720 and #1721 still apply cleanly to today's main, so neither needs a rebase; that part of our 5 Nov note is #1722's. What's left before #1720 lands is the never-slower switch from that note. Your four-stream cells show drafts losing: 68.2 against 83.6 tok/s on code and 63.6 against 78.6 on chat at T=0. So:
#1720 is where serving starts, so please put the switch in #1720 itself, or tell us to land #1720 to #1722 together. If the switch uses the draft pricing that CUDA shares, scope it to Metal, or show a CUDA row that's unchanged. Please also add a CHANGELOG line for #1720, citing "(#1720, part of #1676)". The two small points, the cache cap with logits added and the 912K memory gate, still don't block. |
87436e1 to
de8495c
Compare
|
Updated at the head you asked for on 5 Nov. The switch is in, decided from the cells you wanted. The switch (#1720, commit aaef961 + 52fb89885 + a832608 + bb41254b8): rounds with three or more active streams decode plain and skip the draft pass (TF_DSV41_DRAFT_PLAIN_STREAMS, default 3 on Metal, 0/off for CUDA — CUDA's rounds are unchanged, and the setting reads the same env var on both so a CUDA row can be shown). The 2- and 3-stream cells placed it: drafts win at 1 (47.0 vs 35.7 tok/s code T0) and 2 (58.2 vs 54.7), and lose from 3 streams (61.8 vs 71.9). The never-slower question, honestly. The rule holds at 1 and 2 streams and does not hold yet at 3-4: with the switch on, plain-with-drafts-armed rounds run at 0.955-0.965 of plain (receipt8, fresh server per cell, --prompt-cache-gib 0, one M3 Ultra 512 GB, deepseek-ai/DeepSeek-V4.1-Flash-1017 release weights; token_sha256 equal in every cell):
Two rounds of fixes narrowed it from 0.70 to ~0.96: the switch now skips the DSpark pass in plain rounds and does not launch one for the next round (52fb89885), and a stream's first (admission-time) draft ask waits for its first round (e361d1fbe). What remains is a per-round cost on the drafted path even when every window is plain — we are still narrowing it, and if it turns out inherent to keeping the drafted path armed, the honest reading is: the switch recovers 13 of the 15 lost points (C 80.0 vs B 68.1 at N=4 code T0), the remaining ~4% is the cost of having drafts armed, and we'd like your judgement on whether 0.98·A must include that. Cells you asked for, receipts at the pushed head: 1 and 4 streams rerun with the switch in — drafted cells no slower than plain at 1-2 streams (C/A 1.22-1.49 at N=1), token_sha256 equal in every cell, 30/30 rep pairs equal. Full tables: receipt8 runs in the PR notes below (runs 2 and 3, summary.txt quoted). Also in this push: CHANGELOG line citing "(#1720, part of #1676)"; the receipt script (receipt8.sh) and its summary format are in the repo's nodes/ tree, not this branch (say if you want them here). |
|
Thanks @gilby for the switch and for the honest table. The switch is well scoped: it counts streams instead of pricing, CUDA passes no default so its rounds are unchanged, and every new branch is gated on the setting. Some things need fixing before it lands. Several come from the rebase, which seems to have started from an older copy of the main commit than the one we reviewed on 4 Nov:
The two small points (the cache cap when logits are added, and the 912K memory gate) stand as before and don't block. Main is frozen for today's release. With these in, #1720 to #1722 land in order after it.
|
|
Hi @gilby, @ashhart — first-time commenter here. The PR notes say Metal on M5 hasn't been run, so I ran this stack on an M5 Ultra (512 GB) and am posting the receipt in case it's useful. Happy to rerun anything in a different shape. What this is and isn't. The current head Setup
Tests on M5 (all at
Plain vs drafts, 1–4 streams —
Cold 32,768-token first request —
4 × 912K memory gate, re-run — same server line with
Where my run differs from the receipt you asked for
Raw JSON for every cell, the server logs and the memory trace are kept; I can attach them or put them in a gist if that helps. |
|
Thank you @3utsu, and welcome. This is a careful receipt, and an M5 Ultra with 512 GB is a machine we can't run DeepSeek-V4.1 on ourselves. A few things it settles for the 4 Nov commit (
Your offer to rerun on the fixed head is the most useful next step. Once @gilby pushes a head that compiles (the @gilby, 3utsu also found a second missing
|
|
Thanks for the welcome! As offered, here is the raw data behind the It has the full Once the head compiles, I'll rerun the same matrix there with a fresh server per load (code and chat separately) and add it to the same gist. |
|
Thanks @3utsu, that's everything we asked for: the per-server JSON, the logs and the scripts that drove them. We'll read the C column on M5 from your rerun once the head compiles.
|
|
The rerun I offered, at #1720's head C/A, this run against @gilby's M5 Ultra at
Cold 32,768-token first request,
Tests at this head: Raw JSON, server logs, per-cell thermal and load snapshots and the scripts are in the same gist, as files named |
|
Thanks @gilby, and thanks @3utsu for the independent rerun at The copy-window fix is right and small. The receipts agree. On the M3 Ultra (the fix on On the plain-streams switch: keep it in this PR as reviewed. It doesn't change tokens, it only applies to DeepSeek on Metal, and it's what keeps the default from ever being slower than Against today's main, only
|
…over Metal target.zig is the lanes' verify target: a slot's prompt, its windows of rows for several slots in one launch, keeps and rewinds, and kept prompt states (the prompt cache) whose resumed rows the reply reports as cached_tokens. boot.zig loads a release checkpoint folder and entry.zig serves it as tensorfold-dsv41 (dsv41-metal-serve). Tests serve the tiny model through LaneHost: concurrent equals solo equals serial, drafted equals draft:false, cache hits equal fresh runs, seeds and cancels.
…for the next A shared round with the plain switch at it asked no drafts and ran no head pass (core Rule.plain_streams, threaded from the family's resolved setting: 0 on CUDA, so its rounds are unchanged), and the family's speculation no longer launches a pass for a round that wide (armSpec/speculate plainRound).
…teps and the forward try's
…stays within 600 lines
…nything else by name
…treams streams decode
…er holds a rejected draft's taps
…nd the next ask catches the drafter up
c97d661 to
445a3f5
Compare
|
Thank you @gilby. This is merged into main with your commits under your own name, so you're listed as a TensorFold contributor. It ships in the next release, credited to you in the changelog and the release notes. |
Figures and scope corrected to the PRs (#2948, #2863, #2934, #2933, #2921, #2906, #2878, #2892, #2851, #2728, #3072, #2915, #2864, #2854 and others), promises of later work removed (#2903, #2875, #1630, #1720), #3074 and #3047/#3046 said as their PRs scope them, the duplicate #2861, #2585, #2321 and #2719 entries and two copies of released 1.2.5 lines removed, #1953's line named for its PR, and a line for #3255. Released sections unchanged.
|
Thanks @gilby, and @3utsu for the independent M5 Ultra receipt! This is in TensorFold 1.2.8, out now: https://github.com/ashhart/TensorFold/releases/tag/v1.2.8
|
What this changes
The Metal lane target (prompts, windows of several slots in one launch, keeps), the prompt cache with
cached_tokens, and the native server over Metal (zig build dsv41-metal-serve); text only.Part 16 of 18 of the stack for #1676; stacks on
dsv41-metal-pr/15-serve-lanes(part 15, #1719), on main with parts 1 to 5 (#1705 to #1709) merged.Receipt
tools/bench_concurrent.py --alone --serialortoken_shaagainst"draft": false: the tiny model served through LaneHost intest-dsv41-metal-serve: concurrent == solo == serial, drafted =="draft": false, prompt-cache hits == fresh runs, seeded replies repeat, a cancelled prompt leaves the next request valid.serve --parallel 4 --context 1048576 --prompt-cache-gib 8 --vision, DSpark drafts on; measured at the stack's top before the rebase onto main 3ce4a04, 60d51fd, the same 13 commits on main 9e8c368 (git range-diffshows each patch unchanged except part 10's one planted-control line,TF_CTL == 4only, which the served kernel compiles out), whose served path for text is this part's):tools/bench_concurrent.py --tokens 128 --temperatures 0,1 --levels 1,4 --alone --serial: 8 cells, 0 failed, 0 unequal (alone 1/1 or 4/4 and serial 1/1 or 4/4 equal in every cell). The memory gate, 4 cold 912K-token prompts at once in 4 slots of 1,048,576 positions (all four recall their needle, about 333 GB of GPU memory at peak), is from the 29 Oct stack's top (5db73126) and was not re-run on this head.TF_DSV41_REAL=<checkpoint> zig build test-dsv41-metal-realon layer 2 (compress ratio 2) and layer 21 (ratio 1): exit 0, 5/5 steps, 4/4 tests each; every stage at 1 and 4 rows within its float64 bound, the closest margins at 1.000 of the bound (layer 2: shared SwiGLU 6.103e-5 vs 6.104e-5, routed + shared join 2.441e-4 vs 2.441e-4, hc post 3.906e-3 vs 3.907e-3; layer 21: shared SwiGLU 1.221e-4 vs 1.221e-4, join 4.883e-4 vs 4.883e-4, hc post 1.953e-3 vs 1.953e-3); mapped weights give the same output as copied weights, bit for bit, at 4 rows.tools/bench_openai.py: no Metal DeepSeek-V4.1 backend before this stack. After (60d51fd, the same patches before this rebase,--tokens 256 --reps 3 --temperatures 0,1, median): drafts on, fibonacci-raw 53.8 tok/s at T=0 and 50.5 at T=1, gpu-chat-no-think 43.8 at T=0 and 44.2 at T=1; drafts off (serve --no-drafts, one token a round), fibonacci-raw 35.4 at T=0 and 34.8 at T=1, gpu-chat-no-think 35.4 at T=0 and 34.6 at T=1.bench_concurrentaggregate at 1 / 4 streams: code 46.9 / 78.5 at T=0 and 52.1 / 61.4 at T=1; chat 43.2 / 76.1 at T=0 and 47.5 / 62.2 at T=1.tools/bench_cache.py --prompt-file <32,768 token ids> --expected-prompt-tokens 32768 --require-cold --require-reuse --tokens 64 --repeats 2: cold first requestttft_s42.76 (about 766 tok/s), cached_tokens 0; repeats 0.028 and 0.029 s and two concurrent 0.029 and 0.056 s with cached_tokens 32,768, the same tokens in every row; qualified.zig build test tf-kernel-contract -Dcpu=apple_m1: exit 0, 627/627 steps succeeded; kernel contract,tf-kernel-contract --only dsv41(Metal):SUMMARY 89 kernels: 89 pass gates 1-4, 0 fail, 0 known findings; 186 controls: 186 red as planted, 0 missed; 0 limit problems; gates 119142 ms, limits 161 ms;zig build test-dsv41-metal-all -Dcpu=apple_m1(every DeepSeek Metal device step): exit 0, 9/9 steps succeeded; 37/37 tests passed;python3 tools/zig/lean_check.py: 5144 files, 424 problems, the same count as main (5027 files, 424). Zig's summary counts only the test binaries it ran in that invocation, so the step count is the comparable figure.time-dsv41-metal-real(timing only) was not part of this receipt.Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo.SUMMARYline is in the receipt.