Repository navigation
Conversation
… chunks while no other stream decodes The cold grid stays 4096 rows (cuts, kept states, resumes, pages); a solo pass merges cold chunks of 2048 rows or more up to the set rows and stops at a mark it keeps. A shorter chunk (a 12-row tail, a request start's) runs alone as on main: its rows keep the projections' small-row tiles. Scratch rows, tap rings, int8 and EXL3 grouped scratch are sized at load from the value, so unset allocates as before. Refused by name at load (BadChunkSolo), and on a pipeline stage (QwenSoloStage). Rule: core/lanes/solo_chunk.
Owner
|
Thanks @jschmied. The retained cache grid and short-tail guard look sound; 67 host checks and the native CUDA compilation pass. One small fix remains: the engine module reaches 601 lines on current main, adding a lean finding. Please bring it within 600 lines. After that, we will run the device check on our side for the wider passes and concurrent decoding.
|
This branch has not been deployed
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.
Head:
f366dd58319b00642c433e691dbe3cd0bc7df9e4on main223da7659b. Ledger row 20 (solo chunks), q3.5 cell, #1554 option C.When the variable is set to 8192 and no other stream is decoding, a Qwen prompt pass takes up to 8,192 rows. Once another stream decodes, it goes back to the 4,096-row grid chunk.
The rule is the shared one,
core/lanes/solo_chunk.zig(Limits,rows,read). It is the same rule Gemma 4 (#2391), Flash Next (#1733) and GLM (#1823) use.When the variable is unset, nothing changes: the replies are the same as main's and so is the memory.
What changes
Core: nothing new.
solo_chunk.rowsandsolo_chunk.readread the variable.platform/environment.ziggains aTF_QWEN35_CHUNK_SOLOrow (.size, scope.cuda), with test rows inenvironment_test.zigand a line indocs/environment.md.qwen3_5 CUDA only:
Three row counts, where there used to be one (
max_rows= 4096):grid_rows= 4096. It keeps every cut-related meaning: cold cuts, kept states and resumes (snap_grid,onGrid), the pages' window, readout pieces, stage shapes and the disk probe.max_rows= 8192 is the capacity for host tables, the round staging layout and the pocket row scales.Engine.prompt_rowsis read at load from the variable. It sizes the device memory that grows with the rows: the scratch rows, each stream's tap ring (tapRows()= 2048 +prompt_rows), the int8 prompt scratch, the EXL3 grouped scratch and a stage boundary.admitrefuses a forward past it.cuda_prefill.soloEnd: an uncapped text pass merges consecutive cold chunks while all of these hold:cuda_solo.othersDecode: a stream with a cache and no fill);solo_min_rows= 2048 rows;Images,
--decode-sharecaps and short chunks (a tail, a request start's chunk, a capped step's rest under 2048) take the same cuts as main.Refusals by name, at load, before anything allocates:
error.BadChunkSolo, for any value other than unset, empty, 4096 or 8192;error.QwenSoloStage, for 8192 on a pipeline stage.Both have messages in
cuda_native_explain.zig.Why there is a floor of 2048 rows: in an early version, every cold chunk merged. That moved a 27B reply. The prompt was 12,300 tokens, so main ends it with a 12-row tail, and that tail runs the projections' small-row tiles (
qmmf.fused_rows256; affine large tiles from 2048 rows). The merged pass ran those rows on the large tiles. On the head, a chunk under 2048 rows runs alone, as on main. The tails table below covers 12 to 4,000 rows on both bases.Metal and HIP: none (this is a CUDA prompt-pass knob).
Evidence (GB10 sm_121, clock cap 2300, page cache dropped before every server start)
Binaries: main
223da7659bmd578031f04, head md57b55bf9c. The arm order is main, off, on, on, off, main: off is the head with the variable unset, on is the head withTF_QWEN35_CHUNK_SOLO=8192. Each arm runs on a fresh server with--parallel 8 --context 40960, drafting on (DFlash2 for the 27B, MTP for the 35B-A3B). Paired medians are on vs main, by prompt; the "slower" counts are taken over those pairs.Cold first token, alone (4 greedy prompts and 1 seeded prompt per size):
The 27B gains little: its prompt GEMMs are bandwidth-bound here (this box is bandwidth-bound). A discrete card (sm_120, sm_80) could show more.
Beside decoders: the same prompts while 1 or 3 streams decode.
Concurrency: 4 and 8 prompts sent at once.
Multi-turn chats (
/v1/chat/completions, A-B-B-A, 3 chats × 4 turns, greedy and seeded). With--prompt-cache-gib 8the turns resume from kept states at 8,192 and 20,480 tokens.Exactness (on == off == main):
runs/tails27,runs/tails35Memory (MemAvailable after load,
--parallel 8):Refusals:
6144,off,on,2," 0",16384or8kexits 1 with theTF_QWEN35_CHUNK_SOLOmessage (runs/refuse.log).cuda_solo.zigcovers the refused texts, the message and the stage refusal.cuda_prefill.zigandprefill_widths_qwen_host.zigcover merges, tails, marks, request starts, capped rests, and a decoding neighbour keeping the grid.Checks on this head:
q35solo-x86b):zig build -Dfixed-cpu test test-golden test-kernel-contract test-server-security test-pull-security fuzz-cortheon check-release-paths,tools/pr_check.py(lean 341 vs 341, 0 new),zig fmt --check,git diff --check: all green.zig build test-cuda-host393/393 steps.Overlap
These open PRs touch the same files:
cuda_prefill.zig.cuda_native.zig.cuda_cache.zig.cuda_prefill.zig,cuda_native.zigandqwen35_formats_host.zig.Every conflict is textual. No other open PR does solo chunks for Qwen.
Proposed CHANGELOG line (not committed)
TF_QWEN35_CHUNK_SOLO=8192lets a prompt pass take up to 8,192 rows while no other stream decodes, and the usual 4,096 once one does. On a GB10, a cold prompt's first token comes 3.5–8.7 % sooner on Qwen3.6-35B-A3B and 1.2–1.9 % sooner on Qwen3.8-27B NVFP4, at 6K–33K tokens, with the same replies. Each stream's tap ring and the prompt scratch grow with it (about 0.7 GB and 2.2 GB at--parallel 8). Unset, nothing changes. It uses the shared solo-chunk rule (gemma4 cuda: TF_GEMMA4_CHUNK_SOLO, on a solo-chunk rule shared in lanes (#1554 option C) #2391).