Repository navigation
qwen3_5 cuda: map an EXL3 embedding from host memory only when the card has no room - #1678
Open
diwakergupta wants to merge 1 commit into
Open
diwakergupta wants to merge 1 commit into
diwakergupta wants to merge 1 commit into
Conversation
…ly when the card has no room An EXL3 checkpoint's bf16 embedding rows (2.37 GiB on the 27B) load into the arena as before, unless a discrete card's room could not hold the weights, one stream at the asked window and the DFlash2 drafter beside them. Then the rows go to mapped pinned host memory, which the embedding gather reads in place. Unified memory never maps them. qwen3_5's Options take the server's room probe and the drafter's directory; Engine.initFit sizes the load with them, and init is initFit without a fit. Draft.streamBytesFor sizes a drafter's stream before it loads.
9 tasks done
Owner
|
Thanks @diwakergupta, this is the shape we asked for. Two things before it lands:
|
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
A dense EXL3 checkpoint's bf16 embedding rows (2.37 GiB on the 27B) now load into mapped host memory, but only when the card has no room for them. In every configuration that fits today, the load and the default path are
main's.This is the host-mapped embedding from #1476, made automatic as @ashhart suggested when parking #1476. Unconditional mapping slowed decode on the GB10, so it's now a fallback rather than the default. Its value is on a 24 GB card: there it lets the 27B with DFlash2 serve a 98k or 128k-token window that
mainrefuses to start.cuda_host_embed.zig): the rows go to host memory when a discrete card's room is less than the weights and scratch, one stream at the asked window, the DFlash2 drafter's weights and one stream of its ring, taps and frame scratch, plus 256 MiB for the load's other buffers (about 85 MB measured: kernel modules and the EXL3 kit). Unified memory (the GB10) never maps them: its host memory is the same memory.qwen3_5'sOptionsgainroom(the server's room probe, whichgemma4already takes) anddrafter.openpasses them toEngine.initFit, which decides between the loader's measure pass and the arena allocation.Engine.initisinitFitwithout a fit, so its other callers are unchanged.Draft.streamBytesFor(config, hidden)uses the drafter's ownlayout()for one frame, plus its ring and the target's taps. Without it, the rule missed the 98k case by the drafter's 0.35 GiB.cuda_exl3_weightsskips the rows in the arena whenEngine.host_embedis set, and copies them into that pinned, device-mapped buffer. The engine frees it indeinitand on a failed load.qwen3_5: embedding rows read from host memory: no room beside a 98304-token stream.Receipt
Environment. RTX 3090 Ti (24 GB,
sm_86).turboderp/Qwen3.8-27B-exl3branch3.50bpw(rev8351c54e),z-lab/Qwen3.8-27B-DFlash2(rev50307d4c) at 4 bits, bf16 KV cache. Both binaries came fromzig build native -Dsm=86, one frommain(a0d24896) and one from this branch.What starts, by
--context. Each run was a fresh server, with the start-up line's numbers:--contextmainExactness with the rows mapped (
--context 98304).tools/bench_concurrent.py --levels 1 --tokens 384 --reps 3 --alone --serial, the default code and chat cells (greedy and sampled), and--promptswith two long prompts (5,080 and 2,278 tokens):"draft": falseand every repeat equal: 0 unequal, 0 failed.token_sha256equalsmain's (at--context 32768) in 72/72 replies.Decode speed with the rows mapped, against
mainon the card, per-stream tok/s (a median of 3). Here it costs 0–1.2%;maincan't run at this window at all:main, 32k, rows on the cardDefault path. At 32k and 64k the rows stay on the card and the same model bytes load as on
main. The code that runs per token ismain's.Tests. The full checklist suite (
zig build test test-kernel-contract test-golden test-server-security test-pull-security fuzz-cortheon test-cuda-host) plustest-qwen35-formats-host: 481/481 steps succeeded.lean_new.pyagainstmain: 0 new problems. New host test:the rows stay on the card unless a discrete card's room is short of the device bytes and one stream(cuda_host_embed.zig, run bytest-qwen35-formats-host).Not run. GB10: unified memory never maps, so its path is
main's. Metal: not affected. MLX and MoE EXL3 checkpoints: the rule is EXL3-only and the MLX loader doesn't read it; a MoE EXL3 checkpoint takes the same rule but wasn't served. Other drafters: the rule sizes only a DFlash2 drafter and counts nothing for any other.Checklist
"draft": false, and the mapped rows givemain's tokens.sm_86only.