Repository navigation
lane core: several queued prompts in one pass (prefill_many, addStreams, the lane host admitting together) - #853
BobClawblaw wants to merge 10 commits into
Conversation
…wer: batched prompt passes (prefill_many, addStreams), a backend's refusals for a memory guard, follow() for a tensor-parallel rank 1, shared-pool admission fields, image and video inputs for the native server (vision_inputs, media_fetch, qwen_image, stb_image)
b8b17ab to
39de039
Compare
…cel; lean rule and zig fmt setup() returned cancel()'s true for a background warm pass that yields to a newer request, so the caller launched the job cancel() had just finished (SEGV in lane_host_warm_test). It now returns false, as for a drop. Comments one line each; lean_check skips zig/vendor/ (stb_image.h, as on ashhart#726). lane_host.zig and lanes/engine.zig stay under 600 lines: the batched prompt pass moves to lane_host_admit.zig (many, one) and lanes/open.zig (addStreams, adoptPrefilled), aliased where they were.
…rozen words (the errors/content-image golden)
|
CI fix.
Locally: |
…nsorfold-native takes memcpy from libSystem again (zig build test on macOS)
|
Hello @BobClawblaw, Thank you for the lane-host hooks for two-rank families. Several streams in one pass (engine.zig:119), follow for rank 1 (cuda.zig:257), two_ranks (cuda.zig:352), setStreams and setRoom (cuda.zig:396, cuda.zig:397), and the vision input check (vision_inputs.zig:122) move in with #804, which is the GLM CUDA family. JPEG and PNG stay on the pinned libjpeg-turbo. Please drop zig/vendor/stb and stop compiling it (vision.zig:7). refusedFn is unused (fake.zig:246), so that function needs to be wired or removed. admitMany sets up several jobs before the backend runs them (lane_host.zig:411, lane_host.zig:424). setup keeps a saved state that is only safe until that job's own pass (lane_host.zig:317). The next job's reserve can evict it (prompt_cache.zig:279, prompt_cache.zig:293), and the first restore then reads freed memory. Pin each setup job's entry until its restore. No family installs prefill_many yet (engine.zig:113), so nothing serves this path today. Please fix it before the hook moves. Thank you again. |
…eports; images wait for the shared decoder; no refused hook - prompt_cache: Entry.pins, Store.pin/unpin. victimBut passes pinned entries over, so a later job's lookup in admit.many (or a keep during the batched pass) no longer frees a state an earlier job has yet to restore; a keep with nothing evictable fails instead of unwrapping null. LaneHost.setup pins, reported and requeue unpin. - vision: zig/vendor/stb dropped and no longer compiled. qwen_image.decode refuses by name (NoDecoder) until the shared runtime decoder (pinned libjpeg-turbo) lands; lean_check's vendor exemption goes with it. - lanes: Backend.VTable.refused, Engine.refused, cuda_bound's forwarding and the fake's stray refusedFn removed; nothing consumed them.
|
Hello @ashhart, Thank you. Pushed in 9e6dfcd:
|
|
Thank you, @BobClawblaw, for the cleanup and the restore pinning. At One should-fix remains at Mark E invalid at once so new lookups miss it, and free it only when its last pin goes. The same rule applies to Posted by Ash's AI Assistant Synthena |
…eed only at its last unpin; a job reports resumed before it unpins
|
@ashhart Thank you. Fixed in
Two regressions in
With the old |
ashhart#853's host builds each family's options from F.Options; with it, image input from ashhart#885 reaches the 35B-A3B unchanged. Claude-Session: https://claude.ai/code/session_019t9cKWEuJaAitqMuN9rYFE
The ashhart#853 merge removed learnBytes (ashhart#836 reads learn_bytes in place); its doc line stayed above toGib. Claude-Session: https://claude.ai/code/session_019t9cKWEuJaAitqMuN9rYFE
…d a trailing blank line - vision_inputs opens libtfvideo through sys.DynLib (LoadLibraryW on Windows, as tfvideo.dll): std.DynLib has no Windows. media_fetch's connect is Linux socket calls; a Windows server refuses image URLs by name. ashhart#836 builds the server's tests on Windows and ashhart#853 brought both, so they met here. - tf-qwen35-cuda's header and two comments within one line and 120 columns. - docs/vision.md ends in one newline (git diff --check). Claude-Session: https://claude.ai/code/session_019t9cKWEuJaAitqMuN9rYFE
ashhart#853's host builds each family's options from F.Options; with it, image input from ashhart#885 reaches the 35B-A3B unchanged.
|
Thank you, @BobClawblaw, for covering both failed restore and forget while another borrower still holds the entry. At 52b82fc, The lifetime finding is closed in source. This is ready for the cache landing checks, including the two-borrower regressions. Posted by Ash's AI Assistant Synthena |
…h (core/picture, server images and videos, media_fetch), its two-rank serving (--tp/--rank, engines.follow, room by the smallest rank) and the prompt cache's borrowers replace this branch's; the batched prompt passes come back on main's lane host next
…ill_many (Engine.addStreams; the lane host takes, sets up and launches each job as before and prefills the shared-pass ones together); a pass that errs or has no room leaves none prefilled and each stream goes alone; the CUDA and recorder wrappers forward it; the fake's batched backend and four host tests
cwschroeder
left a comment
There was a problem hiding this comment.
Reviewed b416ec8 on main 46a08c18. I found one test-backend contract mismatch and prepared a small patch with additional CPU coverage: https://gist.github.com/cwschroeder/169d1f6ec8254a7fc8e696b7fc78b118.
In lanes/fake.zig:92, an error after prefill inserts the current lane leaves that lane behind: the cleanup visits only earlier participants. Direct callback tests for Cancelled and Yielded both fail on the unchanged implementation (expected 1, found 2, with one unrelated lane already live). Including the failing participant in the cleanup fixes both. This is a Fake contract defect; the solo fallback can clean it up later, so this does not establish a persistent serving leak.
The patch also checks:
- Cancel and yield at the first, middle and last participant, preserving the unrelated lane and allowing solo retries.
- A successful batch followed by one first-token or draft error: the other replies retain their expected tokens and all lane state is released by the host.
Recordedaround the batched backend, including batch refusal and solo fallback. Recorded and unrecorded replies match for each configuration; each stream's token, position and feature files match its own context. Removing the batch prompt recording makes the new test fail.
Local Zig 0.17.0 validation at patch commit 4094e022 passes: 175/175 host and 61/61 recorder tests in Debug and Fast, plus the full No-GPU workflow commands, whole-tree formatting and lean (zero new findings). The PR's four current-head GitHub checks separately pass; the offered patch has local validation only.
Astra reviewed the patch with no remaining material source finding. These are CPU host/recorder tests. GPU rollback, model parity and performance have not been run. The family callback still owns complete rollback and completion of queued device work before returning false or an error.
|
@cwschroeder Thank you for the patch and the clear write-up. Taken in
|
…) into pr/glm-flash-cuda: the glm_cuda family leaves; DFlash2, history-copy drafts, the vision tower and the EXL3 routed experts move into families/glm commit by commit, its kept states are main's
cwschroeder
left a comment
There was a problem hiding this comment.
Rechecked adopted commit ae4461d8 with Zig 0.17.0 on macOS arm64. The actual CPU host root passes 175/175 tests and recorder_test.zig passes 61/61. In a temporary source copy, restoring only the old exclusive cleanup makes both new Cancelled/Yielded rollback regressions fail (expected 1, found 2); the tracked worktree stays unchanged. Whole-tree format and patch whitespace pass. All four current-head GitHub checks are green.
Astra found no material issue in this adoption delta. This closes my Fake rollback finding and confirms the added host/recorder assertions. It remains test-backend coverage: no family implements prefill_many here, and this is no GPU rollback, model-parity or performance qualification.
|
Thanks @BobClawblaw and @cwschroeder for the failing-participant rollback control and its credited fix. The distinction is right: ae4461d fixes the fake backend's contract, rather than demonstrating a serving leak. Every real batched-prompt implementation must leave all passed streams clean on failure, including the participant that failed. We retain that requirement in the maintained family integration alongside slot ownership, media state and prompt-cache lifetimes. The host and recorder results cover their stated paths; GPU failures and rank-wide cleanup still need the final family's device checks. This remains shared lane admission, with ordinary cache reuse preserved. Posted by Ash's AI Assistant Synthena |
…-cuda: the glm_cuda family leaves; DFlash2, history-copy drafts, the vision tower and the EXL3 routed experts move into families/glm commit by commit, its kept states are main's
… prompts in one pass for a backend that batches them The pull request's newest head merges 1.0.12 in, so it merges cleanly here. Its commits are copies without zig/vendor/stb (author, committer and message byte for byte; each tree differs from the original only there), so the vendored decoder is in no tree of this history. It adds prefill_many to the lanes backend, Engine.addStreams and the lane host's admission of several queued jobs in one prompt pass, with a failed pass leaving none prefilled. No backend here sets prefill_many, so every family admits one job at a time as before; the fake backend's tests cover the path.
…s and trees), and a platform layer for Windows The pull request's head is rebased on 1.0.12 by its author, who resolved what the earlier landing's thirteen conflicts held; checked here: the request log stays owner-only (its test skips the mode on Windows), prefill_attention.cu keeps the four instantiations, and a family's stream buffers are still reserved once the count is known (now through the drafter wrapper's reserve). One conflict with #853, resolved keeping both: recorder_test.zig's planted link skips without the privilege on Windows, and its target can be the batched one. The head's newest commits take 1.0.12's new modules through the platform layer for Windows, keep a stream's recorder file off links, and move the docs to port 8888, which a later commit here puts back to 8080.
…iling blank line - vision_inputs opens libtfvideo through sys.DynLib (LoadLibraryW on Windows, as tfvideo.dll): std.DynLib has no Windows. media_fetch's connect is Linux socket calls; a Windows server refuses image URLs by name. #836 builds the server's tests on Windows and #853 brought both, so they met here. - tf-qwen35-cuda's header and two comments within one line and 120 columns. - docs/vision.md ends in one newline (git diff --check).
…red decoder): Qwen's image tower on CUDA and M-RoPE rows in the CUDA forward The pull request's head is unchanged, but it sits on #836's previous line and #853's vendored decoder, so its own commits are cherry-picked here onto the rebased line, each under its author: the forward's image rows and M-RoPE positions, the tower and --vision on the Qwen engine, the tool's vision and mrope checks, the tower's bounds and the lean fixes. Its doc-comment removal finds the line already gone here. As in the earlier landing, the server side (vision_inputs.zig and media_fetch.zig, which came with #853) keeps this tree's code, qwen35.cu keeps #849's embed8 beside the splice, and the forward embeds through #849's embed before the splice. What the line adds equals what the earlier landing's merge of this head added.
…re/qwen_vl, the engine's Vision) #885's tower read its own vision_config and took #853's image type (patches and a grid, placeholders found by scanning) from a server path this tree does not have. The family now takes what the server sends every image family: --vision's limits at open, and requests' images as lanes.stream.Image (pixels, grid, prompt row, tokens). - cuda_vision.zig: the tower's shape comes from core/qwen_vl's Config (the checkpoint's processor settings included), with this tower's own bounds (patch 16, temporal 2, merge 2, 48 x 48 positions, heads of 64 or 72, depth up to 32) and the text's interleaved M-RoPE sections 11, 11, 10 still checked. Vision holds the settings, the tower and the limits; its prepare is core/qwen_vl's (the server's decode, resize and patches, and the image's identity), at most one tower call's 4,096 tokens. - cuda_vision_prompt.zig: placeholder checks and t, h, w positions are core/qwen_vl's Layout (the Metal 27B's), feature rows in prompt order; the tower still runs whole images in calls of at most 16,384 patches. - cuda_native.zig: Options.vision is the limits, Loaded.vision the tower; open refusals are worded (explains_open). - native/cuda_vision_offer.zig offers Qwen's processor, image token and markers (the template writes vision_start and vision_end itself) beside Nemotron Omni's. - tf-qwen35-cuda vision runs picture files through core/qwen_vl and the tower twice (bit-equal), and compares the rows with float32 reference rows (relative L2, worst and mean, bounded), as tf-qwen-vision does on Metal.
…red decoder): Qwen's kept prompt states on CUDA, in pinned host memory The pull request's head is unchanged but sits on #836's previous line and #853's vendored decoder, so its commits are cherry-picked here onto the rebased line, each under its author: the family's kept states (cuda_reuse.zig) with hostCacheBytes, the check of a kept state before its restore, and the tool's resume and rope-shift controls. As in the earlier landing, its lane host, engine_api, server and image_key changes keep this tree's code, so three of its commits (the cache key from #726, the server's image cache key, the lanes digest) add nothing here and are left out. What the line adds equals what the earlier landing's merge of this head added.
… images and video, with #855 beneath it The merged commits keep their authors' names, dates and messages with two changes: a login-only noreply address becomes its author's id+login noreply, and no tree carries the stb_image decoder an early commit vendored and a later one removed. The #853 commits beneath them are the ones the #853 merge landed without that decoder. Both sides keep their kernel lists, launch records, test commands and GLM forward fields. The GLM host keeps this tree's open and openRank split, with #976's image tower inside openRank and its _exit for a failed follower. The CUDA family options take #976's video limits in cuda_options.zig, and the vision offer keeps Qwen's case and the wrapper rule beside #976's video offer.
|
Thank you, @BobClawblaw, for batching queued prompts and the failed-pass rollback checks. We carried your work into 1.1.0 in 1f5631f, retaining your authorship while replaying the history without the vendored decoder. A backend implementing No served family enables it in 1.1.0. The GLM batched-prompt follow-up is for 1.1.1. We are closing this PR because the credited replay has different commit IDs. Posted by Ash's AI Assistant Synthena |
… queued prompts in one pass for a backend that batches them The pull request's newest head merges 1.0.12 in, so it merges cleanly here. Its commits are copies without zig/vendor/stb (author, committer and message byte for byte; each tree differs from the original only there), so the vendored decoder is in no tree of this history. It adds prefill_many to the lanes backend, Engine.addStreams and the lane host's admission of several queued jobs in one prompt pass, with a failed pass leaving none prefilled. No backend here sets prefill_many, so every family admits one job at a time as before; the fake backend's tests cover the path.
…2 drafts and trees), and a platform layer for Windows The pull request's head is rebased on 1.0.12 by its author, who resolved what the earlier landing's thirteen conflicts held; checked here: the request log stays owner-only (its test skips the mode on Windows), prefill_attention.cu keeps the four instantiations, and a family's stream buffers are still reserved once the count is known (now through the drafter wrapper's reserve). One conflict with ashhart#853, resolved keeping both: recorder_test.zig's planted link skips without the privilege on Windows, and its target can be the batched one. The head's newest commits take 1.0.12's new modules through the platform layer for Windows, keep a stream's recorder file off links, and move the docs to port 8888, which a later commit here puts back to 8080.
…d a trailing blank line - vision_inputs opens libtfvideo through sys.DynLib (LoadLibraryW on Windows, as tfvideo.dll): std.DynLib has no Windows. media_fetch's connect is Linux socket calls; a Windows server refuses image URLs by name. ashhart#836 builds the server's tests on Windows and ashhart#853 brought both, so they met here. - tf-qwen35-cuda's header and two comments within one line and 120 columns. - docs/vision.md ends in one newline (git diff --check).
…e vendored decoder): Qwen's image tower on CUDA and M-RoPE rows in the CUDA forward The pull request's head is unchanged, but it sits on ashhart#836's previous line and ashhart#853's vendored decoder, so its own commits are cherry-picked here onto the rebased line, each under its author: the forward's image rows and M-RoPE positions, the tower and --vision on the Qwen engine, the tool's vision and mrope checks, the tower's bounds and the lean fixes. Its doc-comment removal finds the line already gone here. As in the earlier landing, the server side (vision_inputs.zig and media_fetch.zig, which came with ashhart#853) keeps this tree's code, qwen35.cu keeps ashhart#849's embed8 beside the splice, and the forward embeds through ashhart#849's embed before the splice. What the line adds equals what the earlier landing's merge of this head added.
…re/qwen_vl, the engine's Vision) ashhart#885's tower read its own vision_config and took ashhart#853's image type (patches and a grid, placeholders found by scanning) from a server path this tree does not have. The family now takes what the server sends every image family: --vision's limits at open, and requests' images as lanes.stream.Image (pixels, grid, prompt row, tokens). - cuda_vision.zig: the tower's shape comes from core/qwen_vl's Config (the checkpoint's processor settings included), with this tower's own bounds (patch 16, temporal 2, merge 2, 48 x 48 positions, heads of 64 or 72, depth up to 32) and the text's interleaved M-RoPE sections 11, 11, 10 still checked. Vision holds the settings, the tower and the limits; its prepare is core/qwen_vl's (the server's decode, resize and patches, and the image's identity), at most one tower call's 4,096 tokens. - cuda_vision_prompt.zig: placeholder checks and t, h, w positions are core/qwen_vl's Layout (the Metal 27B's), feature rows in prompt order; the tower still runs whole images in calls of at most 16,384 patches. - cuda_native.zig: Options.vision is the limits, Loaded.vision the tower; open refusals are worded (explains_open). - native/cuda_vision_offer.zig offers Qwen's processor, image token and markers (the template writes vision_start and vision_end itself) beside Nemotron Omni's. - tf-qwen35-cuda vision runs picture files through core/qwen_vl and the tower twice (bit-equal), and compares the rows with float32 reference rows (relative L2, worst and mean, bounded), as tf-qwen-vision does on Metal.
…e vendored decoder): Qwen's kept prompt states on CUDA, in pinned host memory The pull request's head is unchanged but sits on ashhart#836's previous line and ashhart#853's vendored decoder, so its commits are cherry-picked here onto the rebased line, each under its author: the family's kept states (cuda_reuse.zig) with hostCacheBytes, the check of a kept state before its restore, and the tool's resume and rope-shift controls. As in the earlier landing, its lane host, engine_api, server and image_key changes keep this tree's code, so three of its commits (the cache key from ashhart#726, the server's image cache key, the lanes digest) add nothing here and are left out. What the line adds equals what the earlier landing's merge of this head added.
… states, and a platform layer for Windows (ashhart#734, ashhart#746, ashhart#797, ashhart#798, ashhart#836, ashhart#849, ashhart#852, ashhart#853, ashhart#859, ashhart#885, ashhart#886, ashhart#888)
…) into pr/glm-flash-cuda: the glm_cuda family leaves; DFlash2, history-copy drafts, the vision tower and the EXL3 routed experts move into families/glm commit by commit, its kept states are main's
…xperts, images and video, with ashhart#855 beneath it The merged commits keep their authors' names, dates and messages with two changes: a login-only noreply address becomes its author's id+login noreply, and no tree carries the stb_image decoder an early commit vendored and a later one removed. The ashhart#853 commits beneath them are the ones the ashhart#853 merge landed without that decoder. Both sides keep their kernel lists, launch records, test commands and GLM forward fields. The GLM host keeps this tree's open and openRank split, with ashhart#976's image tower inside openRank and its _exit for a failed follower. The CUDA family options take ashhart#976's video limits in cuda_options.zig, and the vision offer keeps Qwen's case and the wrapper rule beside ashhart#976's video offer.
…) into pr/glm-flash-cuda: the glm_cuda family leaves; DFlash2, history-copy drafts, the vision tower and the EXL3 routed experts move into families/glm commit by commit, its kept states are main's
Several queued prompts in one pass (lane core)
Since 1.0.12, main already carries most of what this PR first brought, so it is down to the one piece main lacks:
core/picture, the server'simages/videos/media_fetch, and the image fields on requests. I dropped this branch'svision_inputs,qwen_image,glm_imageandtf_video.--tp/--rank/--master,engines.followfor ranks above 0, and room set by the smallest rank. I dropped this branch's versions.What remains: batched prompt passes.
Backend.VTable.prefill_many(ss): a backend that prefills several prompts in one pass gets them together (up to 16), and each stream opens as after its ownprefill. Returning false or an error leaves none prefilled, and the lane core then runs each stream alone. One stream's refusal, or no room for all of them, never takes the others down.Engine.addStreamsandEngine.batchesPrompts.LaneHost.admitOneis split intotakeJob(off the queue, under the lock),setup(the stream) andlaunch(warm pass, lone driver, fill queue or its own pass). Admission one at a time behaves as before. When the backend batches prompts, none fill by chunks, and two or more requests wait with two lanes free,admit.manytakes, sets up and prefills them together. Warm and lone ones launch as before.cuda_bound.zigand the--recordwrapper (recorder.zig) forwardprefill_many. The recorder records each prompt as after its own prefill.No family implements
prefill_manyyet; GLM's two-rank family (#855) will in a follow-up.Checks
zig build testwith four new lane-host tests on the fake's batched backend (Fake.batched()), each reply checked against the target's own continuation:test-kernel-contract,test-golden,test-cuda-host,zig build native(CUDA, sm_121),zig fmt --checkand the lean check pass.