Repository navigation
glm cuda: TF_GLM_KV_SHARE keeps prompts as the pool's pages in prompt_radix's store - #1732
Merged
Merged
Conversation
Contributor
This was referenced Oct 31, 2026
Bizuayeu
force-pushed
the
pr/glm-prompt-pages
branch
from
October 31, 2026 15:11
de41646 to
3495cda
Compare
…_radix's store With TF_GLM_KV_SHARE=n and TF_KV_PAGES=on, GLM keeps a pass's states at its marks on the planned grid (2,048 rows, the prompt step) over 512-row pages, with a lookahead of 1 (the MTP head's row at a mark reads the token after it), in the core's radix store, at most n states past the pages. A state holds its prefix's pages by reference; its snapshot keeps only what lies past them (Plan.shared): the arena's head, the rings, the two pooled-key rows each paged cache has past the mark, and the MTP head's rows past it. A resumed pass writes nothing below its mark, since the pooled keys are written in whole pools from the step's head, so nothing is copied on write. A resume adopts the deepest state's pages at the head of the stream's lease (Pages.openWith, where TF_KV_POISON's NaN spares them) and restores the rest through the prompt pass's Resume. With it on the server makes no flat store for GLM (own_prompt_cache), as for the Qwen hybrids. One rank here; unset, every path is as before.
…s pages, its snapshots step their absence The tree and the pages stay rank 0's. The begin step carries how many of the table's first pages are the cache's, so another rank's map leaves their rows out of TF_KV_POISON's fill and refuses a count past the table. The snapshots step carries whether states leave the pool's pages out, so every rank's snapshot has rank 0's shape. Rank 0 sends its drops before the begin step that maps a freed page, as beginOn already flushes first. The one-rank refusal goes.
Six 8k conversations sent twice at --parallel 4 resumed none at n=4 and all at n=16, with pages to spare: the store limits states as well as pages, and each new conversation evicted the state the next turn wanted. The server now logs a warning below 4 x --parallel and names the value to set, as ashhart#1357 does for TF_QWEN_KV_SHARE.
ashhart
force-pushed
the
pr/glm-prompt-pages
branch
from
October 31, 2026 18:13
3495cda to
682cbd2
Compare
Owner
|
Thank you @Bizuayeu. This is merged into main with your commits under your own name, so you're listed as a TensorFold contributor. It ships in the next release, credited to you in the changelog and the release notes. |
9 tasks done
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.

TF_GLM_KV_SHARE=nwithTF_KV_PAGES=onkeeps GLM's prompts as the pool's pages inprompt_radix's store, the storeTF_QWEN_KV_SHAREuses, with at most n states past them. Unset, every path stays as it was. This is the GLM half of #1510's option B, on the rules #1659 landed. On GB10 at TP=3 with the 1M window, the pool leaves main's flat store about 450 MiB at the default prompt cache, less than a 64k state's 922 MiB, so a message sent again prefills from the start:TF_GLM_KV_SHARE=16bench_openai)At TP=2 with the 524k window main's flat store has room, so unset resumes the chats too and the two match. Only token-id prompts gain, as the flat store keeps no marks for them:
TF_GLM_KV_SHARE=16bench_openai)What this changes
Three commits in
families/glm, with their build and host-test glue, on the rules #1659 gaveprompt_radix.Resumeevery rank takes.TF_KV_POISONon the other ranks leaves their rows alone, and the snapshot step says whether states leave the pages out, so every rank's snapshot has rank 0's shape. Rank 0 sends its drops before the begin step that maps a freed page, asbeginOnalready flushes first.own_prompt_cache), as for Qwen. Set withoutTF_KV_PAGES=on, the engine refuses before the weights load.--parallelstates the server warns at start and names the value to set, asTF_QWEN_KV_SHAREdoes.Choosing n. n bounds the states the tree keeps, whatever pages are free, and start-up takes n times the state at the window's last mark for their snapshots. More conversations going back and forth than n miss: on an earlier head of this branch, six 8k chats sent twice at TP=2 resumed none at n=4 (5.5 s each), and all six at n=16 and on the flat store (1.2 s each), and at TP=3 n=16 resumed the six in 1.04 s against 4.65 s fresh. Over the launches above, the lowest
MemAvailableby rank was 9, 10 and 15 GiB at n=16 against 11, 11 to 12 and 17 GiB unset at TP=3, and 13 and 14 GiB against 11 to 12 and 12 GiB at TP=2, where the flat store takes 4.7 GiB. Kept pages do not hold streams back: on that earlier head at n=4 and TP=2, with four 128k chats filling the tree to 992 of 1,028 pages, a fifth started at once and matched unset's ttft (86.43 and 86.48 s against 86.67 s), a chat the reclaim had evicted missed cleanly when sent again (cached 0), and decode with the tree that full stayed within the runs' spread (four launches against four, −0.15%, the ranges overlap).#1411. Its disk images hold a snapshot's bytes, and a state here leaves its pages out, so the two do not combine until an image carries the pages. They also conflict in
cuda.zigandcuda_follow.zig: whichever lands second rebases.Receipt
fb84de61c, these three commits on main19372fb36;de41646f9is the same ond80e5f2efbut for the two lines that met glm cuda: at three ranks or more, TF_GLM_ROCE_MULTI=1 sends the small all-gathers over fabric/tp's multirank RoCE #1524's. GLM-5.3-Flash XSFP4 at88736f916f89, PARALLEL=4, KV pages on, the drafts on; three GB10 in a ring on NCCL (TP=3, 1M window) and two (TP=2, 524k window). Launched unset, on, on, unset at each TP.tools/bench_concurrent.py --alone --serialon two prompts at 1 and 4 streams, four launches at each TP: 40 of 40 equal alone and 16 of 16 equal"draft": falseat both. One more launch at each TP, n=16 underTF_KV_POISON=1on every rank, gave the same hashes on its 35 replies, 9 of them resumed, and its concurrent cells were equal too, so no rank read a row before its write.tools/bench_openai.py: the tables above. Eight more launches at TP=2 on an earlier head of this branch (n=4 against unset, four of each, 40.424 against 40.349 tok/s with nothing kept, 40.195 against 40.140 with a 64k state held): −0.19% and −0.14%, with standard errors of 0.12% and 0.13%. The ranges overlap, and holding a state does not change the gap.ttft_sfromtools/bench_cache.py --require-coldon 136k tokens: 83.40 and 83.46 s unset, 83.39 and 84.13 s on at TP=3; 101.01 and 100.82 s unset, 100.94 and 100.91 s on at TP=2.de41646f9):test-kv-pool28/28,test-qwen35-share-faults-host14/14,compile-cuda-tests10/10,compile-config-server7/7,zig fmt --check, andtools/zig/lean_check.pywith nothing new (426 against main's 426).test-cuda-host(3,987 tests passed, 9 skipped) andzig build test(1,808 passed, 18 skipped) pass but forcuda_cost_identity's stable-reads drafter test, outside these files: run 40 times, it fails 11 times here and 11 times on main, as two same-sized writes on this Linux often share a 4 ms clock tick and leave one stamp. Under CPU loadzig build testpassed whole, 445/445 steps.Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. (bench_concurrent.py --alone --serialat 1 and 4 streams and the done-line hashes, at TP=3 and TP=2, on and unset, as above.)SUMMARYline is in the receipt. (No GPU kernel is added or changed.)openWith,Plan'ssharedandPrefixare not there. With their property taken out here, one at a time, the test named for it fails: the poison reaching the adopted pages on rank 0 or on a follower, a follower taking more kept pages than its table, a refused resume keeping the cache's pages, a snapshot ignoringshared, the store told one page too many, a lookahead of 0, and the warning's factor at 3. The last run with all of them back passes. None needs a device.)