Repository navigation
glm cuda: the startup plan counts TF_KV_SHARE's kept states, a slot each beside the pool's pages - #2358
Open
Bizuayeu wants to merge 1 commit into
Open
glm cuda: the startup plan counts TF_KV_SHARE's kept states, a slot each beside the pool's pages#2358Bizuayeu wants to merge 1 commit into
Bizuayeu wants to merge 1 commit into
Conversation
…ach beside the pool's pages With TF_KV_SHARE=n, GLM keeps a prompt's rows as the pool's pages and copies the rest of its state into a snapshot pool that share() allocated at load: n states at the window's last mark, outside the plan, which set the whole cache aside as copied rows that no store uses under share. Past the cache's size the pool came out of the reserve. GLM's layout now declares that state's bytes as its slot under TF_KV_SHARE, and the plan keeps the slots the cache holds, n at most, and makes the rest of the cache pages (Budget.slots_only). The family readies the plan's count (share_states), the store keeps that many, and the startup line names them; when the cache holds fewer than n, it names how many of the n fit and the --prompt-cache-gib that holds all n. A value past the 64 slots a plan holds is refused by name before any rank opens; the warning under 4 states a stream names 4 a stream and the --prompt-cache-gib their slots take, rounded the same way. TF_GLM_HOST_CACHE keeps the states in host memory, outside the device plan, as before. Unset, the layout declares no slot and the plan is main's.
Owner
|
Thanks @Bizuayeu. This applies cleanly to today's main. By reading, the slot it counts is the same size main's
If you have them, main-against-branch numbers with |
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.
On two GB10s at TP=2 (
--context 262144 --parallel 4),TF_KV_SHARE=16's kept states now take slots in the startupplan, where main allocated them at load outside it, and the startup line counts them. At the default prompt cache 13 of
the 16 fit, and the line and a warning name the
--prompt-cache-gibthat holds all 16; at that size all 16 fit. Eitherway the rest of the cache becomes pages, where main leaves it aside:
Every reply's tokens are main's, cold, resumed and two at once, and with
TF_KV_SHAREunset the head's startup line ismain's.
What this changes
With
TF_KV_SHARE=n, GLM keeps a prompt's rows as the pool's pages and copies the rest of each kept state into asnapshot pool that
share()allocated at load: n states at the window's last mark, outside the startup plan, while theplan set the whole prompt cache aside as copied rows that no store uses under share. Past the cache's size, that pool
came out of the reserve.
Under
TF_KV_SHARE, GLM's layout now declares that state's bytes as its slot (cuda_pages.shareSlot). The plan keepsmin(TF_KV_SHARE, cache / slot)slots and makes the rest of the cache the pool's pages (kv_pool.Budget.slots_only),so nothing past the slots is set aside. The family readies the plan's count (
share_states, called fromcuda_kv_pool.attach), and the store keeps that many. The startup line names the slots, and when the cache holdsfewer than
TF_KV_SHARE, how many fit of how many were asked and the--prompt-cache-gibthat holds them all. A valuepast the 64 slots a plan holds (
kv_pool.most_snaps) is refused by name before any rank opens. The warning under 4states a stream counts the states the cache keeps rather than the ones asked, says how many, and names 4 a stream
and the
--prompt-cache-gibtheir slots take, rounded as the startup line rounds (kv_pool.holdingGib).TF_GLM_HOST_CACHEkeeps the states in host memory, outside the device plan, as before. WithTF_KV_SHAREunset, thelayout declares no slot and the plan is main's. The GLM recipe's line says so.
TF_KV_SHAREsit outside the startup plan #2307 (option 1, the first reading: GLM CUDA: kept states underTF_KV_SHAREsit outside the startup plan #2307 (comment)).691fb4334, and it merges into main6433d511awithout conflicts.atc overlap --json: on this head against mainebb67e67e: 10 clean and 21 unknown, incomplete(
otherPullRequestsLimit,pullFilesUnavailable,timeLimit). Test-merged here, glm cuda: TF_GLM_GRAPHS=1 replays verify windows as CUDA graphs (#1490) #2279 conflicts with this branchalone, in
docs/recipes/glm-5.3-flash-cuda.md, where both add a bullet at the same place. glm cuda: windows to 32 rows, priced by rounds timed at load #2257(
zig/src/families/glm/cuda_native.zig) and lfm3: serve LFM3-1.7B on CUDA: NVFP4 and FP8 weight-only, MLX 4-bit (stacked on #1513, #1492 and #1503) #1508, lfm3 CUDA: serve the block FP8 export weight-only and the MLX 4-bit export as stored (stacked on #1508) #1634, lfm2_moe CUDA: attention pages from the shared KV pool, and the prompt cache (stacked on #1492) #1503, Muse Spark Open on CUDA: EXL3, DFlash2, two GPUs #1295 and lfm3-vl: chat-template thinking suffix, fitGrid geometry, and deployment recipe #2045 (zig/src/native/cuda.zig) conflictin this branch's files as they do with main itself. prompt cache: a state past the whole budget names TF_KV_SHARE where the family on pages could keep it #2333 and this branch merge without conflicts.
Checks on this head
8a2beb792, on main691fb4334.python3 tools/zig/lean_check.py, on the base and on this head: 252 and 252, 0 new.zig build test: 569/569 steps; 7,346 passed, 0 failed, 61 skipped.zig build test-cuda-host(318/318 steps),test-golden(5/5),test-cache-capacity-host(9/9 tests),test-kv-safety-host(26/26 tests),test-kv-merge-host(25/25 tests),test-glm-pages-host(4/4 steps),test-glm-startup-host(3/3),test-glm-image-cache-host(4/4),test-gemma4-shared-host(4/4),compile-cuda-tests(10/10, native and-Dtarget=aarch64-linux-gnu) andcompile-config-server(7/7): pass.zig fmt --check build.zig zig: clean.kv_pool.plan'sslots_onlybranch taken out,zig build testfails the new test and only it, in both testbinaries that hold it (7,344 passed, 2 failed, 61 skipped).
8a2beb792, 7 of 7 (zig,zig-windows,zig-macos-dev-tools,fmt,release-pathsandbenchmark-clientson Ubuntu and Windows).TF_GLM_HOST_CACHEwithTF_KV_SHAREon a device (its states stay in host memory, outside thedevice plan, as before); HIP and Metal, whose plans never set
slots_onlyand stay main's.Receipt
691fb4334and this commit, built with Zig 0.17.0 and nvcc 13.3.73 for sm_121 (binaries95e71cc28c5e860aand6666c9b694adbd72); two GB10s (128 GB unified memory each, Ubuntu 24.04.5, kernel7.0.0-1019-nvidia, driver 580.178.04) at TP=2 over RoCE;
Bizuayeu/GLM-5.3-Flash-XSFP4at88736f91;--context 262144 --parallel 4, on KV pages (the default at TP=2).TF_KV_SHAREat the default cache, at--prompt-cache-gib 3and at 2, the refusal past 64, and the plan with it unset, which stays main's. I ran all ofthem. Not run:
TF_GLM_HOST_CACHEwithTF_KV_SHARE, HIP and Metal.dcfb6c2929b3for all 72 requests, main and head, withand without
TF_KV_SHARE, cold, resumed and two at once. The replies are all thinking at 64 tokens, so their text isempty and not compared.
every arm.
every arm but m1a, the first launch of the second run (10.69 s), and in 1.05 to 1.08 s resumed from 14,336 tokens. Two
at once vary between runs on main as on the head (the table below).
Each arm is a fresh launch: m for main and h for the head; 0 with
TF_KV_SHAREunset (m0 came up cold, and m2 is mainagain after a warm launch), 1 with
TF_KV_SHARE=16, 4 with 16 and--prompt-cache-gib 3, 2 with 16 and--prompt-cache-gib 2, and 3 with 65. a and b are a second run that alternates main and the head. Every arm but h2 andh3 then takes a 3,200-line chat sent fresh, again, and twice at once (64 tokens); a and b take it twice. From rank 0's
log:
What is left after the weights moves by a step between launches (16.0 to 16.2 GiB above), and the cache and the pages
that take the rest move with it; m1b and h1b, and m4a and h4a, share 16.2 GiB. At
--prompt-cache-gib 3the pages hold3 full windows instead of 4 (
enough for 3 at a 262144-token window), on main (m4a) as on the head (h4a): that settingsets the cache aside first.
Two at once, the pair's later reply in seconds:
TF_KV_SHAREunsetTF_KV_SHARE=16With
TF_KV_SHARE=16, main's 7 pairs average 4.50 s and the head's 8 pairs 4.60 s, 4.52 without its slowest. m4a andh4a hold the same 16 states at the same cache and differ in the pool alone (35 more pages on the head): 4.38 and 4.56
against 4.37 and 4.60.
Checklist
kv_pool.plan'sslots_onlybranch taken out,zig build testfails the new test and only it; they have no dependency to skip on).lines.
bytes move between slots and pages; no compute path changes).
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo (thereceipt's 72 replies share one token hash, cold, resumed from 14,336 tokens and two at once; nothing here
touches tokens).
changes).
--drafter, noslower than without it, greedy and sampled (no compute path changes; one stream measures as main, and two at once vary
between runs on main as on the head, see Receipt).