Repository navigation
Conversation
…ges too, --parallel lanes and no reserved window
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.
With
TF_QWEN_KV_PAGES=nandTF_QWEN_KV_PAGES_ALL=1, main runs every stream on pool pages, but it still reserves the engine's own window, a full stream cache at--context, and leaves it idle. The drafters also keep one ring of their own. With this change the engine's own stream becomes a pool lane too (engine_paged), as on GLM, Gemma 4 (#1619) and Kolibri-1 (#1620). The plan sets one window's worth of pages aside for it, no window is reserved, and DFlash2 and MTP keep their rings in the lane runs. Without_ALL, nothing changes. This follows #1156 and #1357 (the lane count fix, d60cc24, is already on main).attachmakesstreams + 1lanes when the engine's stream is paged;Loaded.engine_pagedtells the host's plan.reservemakes no window then: shapes warm on the first pool lane.nulland makes its ownwindow_rowscache, ascost_adapter.resolvealready does for MTP.RingOf.all: neither drafter keeps a ring of its own.Startup line at
--parallel 8 --context 16384:_ALL_ALLNo kernel changed. The 27B and 35B attend over pages through
tf_q35_attn_partial_paged(qwen35_attn.cuh), not throughwindow_rows, so the paged merge that slowed #1653 (tf_wrows_merge_256_pg, fixed there in 7c0a80b) is not on this path.Gates (GB10, sm_121)
These are the #1357 gate suite: 37 greedy outputs per arm (solo, concurrent 1/2/4/8, resumes at 8192/8292/8448/4796),
--parallel 8 --context 16384, a fresh server per arm. Models: Qwen3.8-27B MLX-4bit with DFlash2, and Qwen3.6-35B-A3B MLX-4bit with its MTP layer, each with bf16 and fp8 KV. Main is the merge base 5d19272._ALL: this == main_ALL(solo, resumes)_ALL== contiguous (solo, resumes)_ALL: concurrent == solo_ALL: resumed == main_ALL_ALL: drafted == plainPAGESalone: concurrent == window or page soloSpeed against main (GB10, sm_121)
Setup: same models and drafters, bf16 KV,
--parallel 8 --context 16384 --prompt-cache-gib 0, a fresh server per arm. The four arms (main, this, main_ALL, this_ALL) alternate in ABBA order: 3 rounds for the 27B, 4 for the 35B.ignore_eos), 1, 4 or 8 in flight; aggregate tok/s = completion tokens / wall.token_shaequal across arms in every cell.Default (no env):
Without the env, the decode path is the same code (the new fields are read only at startup), and the 103 fatbins embedded in the two binaries are byte-identical (md5). Two cells still had one sign in every round, so I checked both:
--cuda-graph-trace=graph, 1 and 8 streams of code greedy, main/this/this/main) shows the same GPU work per decode round: busy time pertf_q35_argmaxlaunch was 4.83 / 4.78 / 4.80 / 4.83 ms. The rest is idle time between steps, and it varies with the server, not with the binary.TF_QWEN_KV_PAGES=256 TF_QWEN_KV_PAGES_ALL=1(opt-in):Under
_ALL, a lone stream is now the engine's own stream on pages, where main ran it on the reserved window. The 27B's 1-stream cells came out 0.8-1.0 % lower in their medians, but no cell held its sign in all three rounds. I did not trace that case. The 35B's third_ALLmain arm was rerun later, because the first run was lost when its loop was stopped.Checks
zig build test test-kernel-contract test-golden test-server-security test-pull-security fuzz-cortheonandgit diff --check: pass on this head. They also pass on this head merged into main 94b90c9. The branch merges cleanly there and into e5b50c8 too, so it was not rebased.Whether pages should be the default for qwen3_5, as #1619 and #1620 propose for their families, is left open here.