Repository navigation
Flash Next shared sessions sized to the traffic: FLASHNEXT_SLOT_CONTEXTS, and a stream that outgrows its session moves - #10
Conversation
…XTS, and a stream that outgrows its session moves Every session held the whole window, so few fit beside the model (three 262K sessions in 15.4 GiB on a 256 GB Mac). - FLASHNEXT_SLOT_CONTEXTS lists the sessions past the engine's own (token counts, CONTEXTxN for N alike, e.g. "65536,32768x3,16384x11": 16 streams in 11.6 GiB); unset, nothing changes. - A new stream takes the smallest free session that holds its prompt and its reply's next FLASHNEXT_SLOT_GROW tokens (default 8192); LaneHost's admit hook (as on main since ashhart#639) holds a request until one is free. - Before a round, a stream left too little room moves to the smallest free larger session that holds its next FLASHNEXT_SLOT_GROW tokens (Session.moveTo: its cache rows, DeltaNet states, n-gram tail, head rows and pooled blocks copied on the GPU at a round's end, states settled first), or pauses (Stream.paused) until one frees. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cwschroeder
left a comment
There was a problem hiding this comment.
Thanks, @sethforprivacy. I can't merge this one yet:
families/flashnext/backend.zig:144-152:makeRoompauses based on the window width plus headroom, not on whether the rest of the reply fits. In the largest session, a partly accepted window near the context limit can leave tokens outstanding afterpaused = true, andmoveneeds a strictly larger session (:166), so the stream never resumes. Growth should depend on the remaining work and never wait for a larger session that does not exist. Please add near-limit tests with rejected drafts, also with the option unset.native/flashnext_batch_host.zig:35-40bounds the repetition counts after allocation, andtokens + MARGINcan overflow before the clamp. Please validate the slot count before appending and use checked arithmetic.- With
FLASHNEXT_SLOT_CONTEXTSunset the behaviour still changes: smallest-fit replaces first-free allocation, and the growth checks run. Either keep the old path when the option is unset or say so in the description so the receipts cover it.
The move itself (waiting for settled state, copying caches, recurrent and head state) looks right to me.
b9ed2ae to
5551aba
Compare
|
Posted by Claude (Anthropic's AI assistant) on behalf of @sethforprivacy, as part of our local-inference tuning work on a Mac Studio M5 Ultra. @cwschroeder thanks for the reviews. First, the rebase you asked for: onto the branch's new tip
Checks on the M5 Ultra (macOS 27.0, Zig 0.17.0,
I haven't rerun it live, so the served receipts in the description are from the pre-rebase head. Each branch still sits directly on the batching branch, so they can be reviewed and merged in any order. Your review is next, as separate commits on top:
|
…wait for a session that doesn't exist; old path when unset Review fixes (cwschroeder on cwschroeder#10): - slots.room decides before each round from the reply's end (prompt + max_new + a window): a stream whose session holds it is never moved or paused, so one in the largest session (admission's guarantee) runs to its end however many drafts are rejected near the limit. A stream that does need more room moves while a larger session is free, else pauses on a round that still fits; it only waits when a larger session exists, and the waits go up in size, so a paused stream resumes once that session frees. - slots.parse validates each repetition count against the sessions still allowed before appending, and adds the margin with checked arithmetic (an overflowing count or repeat is refused, nothing allocated for it). - FLASHNEXT_SLOT_CONTEXTS unset keeps the old path: the first free session (ContextFull when it can't hold the reply), no admission hook, no growth checks. - Tests (slots.zig, in the core test root): the list's parsing, overflow and session-count refusals; session choice unsized (first free) and sized (smallest that holds the first grow); near-limit rounds with every draft but one rejected in a session that holds the reply (never pauses); a smaller session moving while a larger one is free and pausing on a round that fits otherwise; and no wait when no session is larger.
|
Posted by Claude (Anthropic's AI assistant) on behalf of @sethforprivacy, as part of our local-inference tuning work on a Mac Studio M5 Ultra. @cwschroeder your review points are in
I haven't rerun the served receipts in the description since the fixes. They're from |
|
@sethforprivacy thanks, |
cwschroeder
left a comment
There was a problem hiding this comment.
Follow-up to my merge-readiness comment above: the three requested fixes are present in ba31b918, but two remaining issues need fixing before merge.
-
The model parity harness still calls
Backend.init(gpa, eng, count, capacity)atzig/tests/flashnext_batch.zig:147, while this PR changes it toBackend.init(gpa, eng, capacities). Please update that caller and buildzig build tf-flashnext-batch -Dcpu=apple_m1. On Zig 0.17.0, the unmodified harness first stops at the two oldergenerateFromcalls that lack the thinking-budget argument. In a temporary diagnostic copy I supplied that argument to both calls; the compiler then confirmed line 147: "expected 3 argument(s), found 4". ThegenerateFrommismatch already exists on04c8571; theBackend.initmismatch is introduced by this PR. No model was loaded or run. -
resumePausedlogs and swallows every migration error, includingGpuFailedandStateNotSettled, leaving the stream paused. If the last running larger stream has just released its session, there may be no further release to retry the move. The lane core counts paused streams as active but skips them instep, so the request can remain unfinished while the host spins. OnlyLaneMemoryshould keep waiting; other migration errors need a terminal path visible to the host. Please add a fault-injection test where the last larger session frees and the move fails. This is a source-review finding, not a reproduced GPU failure.
The successful-growth cases, bounded parsing and unset-option path look correct. Astra independently reviewed the correction commits. Growing-session model parity still needs a receipt on the corrected/rebased head.
…atch-sessions Conflicts: backend.zig keeps the sized-session fields beside ashhart#9's serial-drafts and costs; session.zig keeps moveTo beside ashhart#9's encodeDrafts and heldDrafts; flashnext_batch_host.zig sets the sized sessions, then times the costs (on a session too small to time, ashhart#9 serves unpriced), and its startup line lists the sessions and the drafts mode; tensorfold.zig's test root takes both slots.zig and batch_costs.zig.
… an error; the lane core sweeps streams a release ends; harness on Backend.init's capacities Review fixes (cwschroeder on cwschroeder#10): - slots.resumePaused: LaneMemory keeps a paused stream waiting; any other move failure (GpuFailed, StateNotSettled, ...) ends it through Backend.failed: slots.endPaused marks it finished with an error the host reports as a failed request, and its session frees at once. Fault-injection test: the last larger session frees, one paused stream's move fails on the GPU (ended), one finds none free (waits), one moves. - The lane core: a release can now end another stream, so Engine.sweep releases finished live streams until a pass ends none, from step's prune and from discard. Without it a stream ended during another's release could stay in the live list after the host freed its job (failAll, cancels and drop skip finished streams). Tests on the fake target, which gains a release hook: a stream ended by another's release in a step, and by a discard, leaves the live list. - zig/tests/flashnext_batch.zig: Backend.init takes the sessions' capacities (refusing more than MAXR as init did), and its two generateFrom calls pass the thinking budget (.{}) that 1.0.8 added, which already broke the harness on 04c8571.
|
Posted by Claude (Anthropic's AI assistant) on behalf of @sethforprivacy, as part of our local-inference tuning work on a Mac Studio M5 Ultra. @cwschroeder both points are in 1. The harness. 2. A paused stream's failed move.
M5 Ultra, Zig 0.17.0: Still open: the growing-session model parity receipt on this head. I'll run it in our next lane window and add it to the description. #10 and #11 touch the same spots in |
Posted by Claude (Anthropic's AI assistant) on behalf of @sethforprivacy, as part of our local-inference tuning work on a Mac Studio M5 Ultra.
As asked on ashhart#606: the sized, growing sessions, alone against
feat/flashnext-continuous-batching. It was rebased onto04c8571(1.0.8 with #7 and #8), with review fixes on top, and later merged with the tip after #9. It needs neither of the other two PRs (round costs, the lone driver). The receipts below are from77ebc3f, before the rebase and the fixes.What it does
FLASHNEXT_SLOT_CONTEXTSlists the sessions past the engine's own, as token counts withCONTEXTxNfor N alike. On our 256 GB lane,65536,32768x3,16384x11is 16 streams in 11.6 GiB, where three whole-window sessions took 15.4 GiB.FLASHNEXT_SLOT_GROWtokens (default 8192).Info.admit(merged with 1.0.8)Backend.fits, so a request waits for a session that holds it rather than failing.slots.room), a stream whose session can't hold its reply to the end (prompt,max_newand a window) and is running out of room moves to the smallest free larger session.Session.moveTocopies its cache rows, DeltaNet states, n-gram tail, head rows and pooled blocks on the GPU at a round's end, so the bits are the same. With none free, the stream pauses (Stream.paused) on a round that still fits, until one frees.LaneMemory. Any other failed move ends it with an error the host reports, and frees its session (slots.resumePaused,Backend.failed).Engine.sweepreleases finished live streams until none is left, fromstepanddiscard, so none outlives its job.Receipts on this branch. Mac Studio M5 Ultra, 256 GB, macOS 27.0,
TensorFold/Qwen3.8-Flash-Next-MLX-6bit-MTP@45032a1, greedy.FLASHNEXT_SLOT_CONTEXTS=16384,4096x6 FLASHNEXT_SLOT_GROW=2048 --context 32768 --parallel 8opens 32800, 16416 and 6 × 4128 tokens under the 70 % share; the base at--context 16384fits four.ca7e464a7a501db9).FLASHNEXT_SLOT_CONTEXTS=4096x3 --parallel 4): the two replies outgrew 4K together. One moved to the engine's session; the other loggedwaits for a session larger than 4128 tokens to free, then moved once the first finished. Both equal the base's reply. (My harness marked that step failed because of its job control; both reply files show identical.)On our combined build (
add3da3onsethforprivacy:flashnext-lane-parity, 16 sessions with sampling and images):zig fmt --checkpasses on the changed files.zig build testat069ef4dpasses 1531/1539 (8 skipped), includingslots.zig's tests and the lane core's sweep tests. One step fails:core.checkpoint_metal's split-checkpoint test, which fails the same way on the tip here.zig build tf-flashnext-batchbuilds.🤖 Generated with Claude Code