Repository navigation
glm cuda: TF_GLM_CHUNK_SOLO takes two grid chunks in one pass while no other stream decodes - #1823
Conversation
|
Thanks @Bizuayeu, this is the shape we hoped for. Unset holds nothing extra and keeps the 2,048 grid, the other ranks |
(comment) Done in |
…o other stream decodes Prompt chunks of 4,096 rows read the weights cheaper, but a fixed 4,096 slows warm turns and the streams decoding beside a long prompt (ashhart#1576). With the setting on, a pass widens only when nothing else decodes; the grid, the rings and prompt_rows stay at 2,048, so resumes land where main's do, and decoding streams see main's passes. Unset, the prompt buffers stay at 2,048 rows and every step is main's.
a27444e to
858f2df
Compare
|
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. |
Option C from #1554 on GLM, as asked on #1576: a prompt step takes two grid chunks in one pass while no other stream is decoding. Unset, it holds nothing extra and keeps the 2,048 grid, so warm turns and decoding streams are untouched.
On GB10 (GLM-5.3-Flash XSFP4, one binary, unset against
TF_GLM_CHUNK_SOLO=4096,--parallel 4 --context 524288,TF_KV_PAGES=on, MTP drafts on):=4096=4096The cold row is at
--prompt-cache-gib 0, on Python source of 8,192, 32,768 and 131,072 tokens (bench_cache.py --require-cold, three rows a launch). A repeated filler line gains less, as on #1576. At about 7,820, 32,450 and 136,170 tokens, also at cache 0, it goes from 5.74 / 22.88 / 97.05 to 5.57 / 22.15 / 94.72 s at TP=2, and from 4.73 / 18.79 / 79.69 to 4.52 / 17.89 / 76.14 s at TP=3. The other rows have the prompt cache on: the default at TP=2, 2 GiB at TP=3. Each cell is the mean of two launches of a setting, but TP=2's cold row, which is one launch each. Three rows that waited on the heat guard are left out (below).What this changes
TF_GLM_CHUNK_SOLO=4096(opt-in) on every rank. The value is rows, as in Flash Next's. Unset and2048are main's path and any other value is refused at load. 4,096 is the only wide size because a pass has to fit the index ring, which is 4,096 rows.Lanes.stepasksLeader.chunkfor a solo pass while no other lane is past its prompt pass, andprompt_solo.atallows it when the next grid point has at least two rows past it and no kept-state mark at it, and the pass rebases the rings where chunks one at a time would. The other ranks read the step from the part's length, as they read every step, and refuse a part thatprompt_solo.alloweddoes not.--drafterbeside this is refused by name before the weights load, andMAX_CTXstays out of this PR. The grid, the rings andprompt_rowsstay at 2,048, so a resume lands where main's does.prompt_solo.mtpRows), because its ring holds a window more than a pass. That is the same rebases and the same state as chunks one at a time, and it takescuda_engine.zigfrom 590 to 584 lines.prompt_solo.bufferRowskeeps them at 2,048 rows.Fingerprintcarriessolo. That takes layout 14, which glm cuda: a prompt step takes two chunks while no other stream decodes, each one's exchanges under the other's sites #1423, glm cuda: TF_GLM_L2PF reads a decode window's next weights into L2 on a side stream, on by default on a GB10 #1580, glm cuda: TF_GLM_KV_HOST keeps the KV pages' latent rows in pinned host memory #1795 and glm cuda: TF_GLM_KDA_PAD packs the fused KDA input at TP=3 (opt-in, default off) #1545 also claim. Whichever lands later takes the next one.glm: prompt passes of 4096 rows, 2048 while another stream decodes.## Requestsbullet and a## Prompt chunk sizesection with the table above.Receipts
5c7eeaf33on main72cc3ea89, built withzig build nativefor sm_121 and served as one binary at both settings and both TPs. The commits on top are the recipe and the--drafterrefusal, which drops a condition that was false in every run here. GLM-5.3-Flash XSFP4. TP=3 on three GB10 cabled in a ring of three QSFP cables with no switch, TP=2 on two GB10 joined by one QSFP cable. Launches alternate unset, set, set, unset, then again at--prompt-cache-gib 0(TP=2: unset, set).heat_wait_s), one unset and two set, and the table leaves out the rows they fell in: one arrival run's long prompt at each setting, the short request beside the set one, and one of the three 128K rows. With them in, the 128K cell is 91.98 s, the short request 2.68 s (highest 4.05) and the long prompt 23.79 and 23.52 s.gpu-chat-no-thinkreads 44.67 to 44.72 tok/s at TP=3 and 35.60 to 35.79 at TP=2, andfibonacci-raw57.34 to 57.46 at TP=3, with one set launch at 56.20, and 43.48 to 43.62 at TP=2.prefill_secondsrises from 0.62 to 1.00 s at TP=3 and from 0.78 to 1.25 s at TP=2. As I read it, that is the end of the long prompt's pass, still on the GPU when their step begins, so it belongs to the same wait and isn't their own rows running slower. I haven't timed that split. Once the request decodes, the long prompt's passes drop to 2,048 rows, and its own first token still comes sooner than unset.kv_pool.windows, 38.0 against 39.55 GiB).--parallel 4still started there.glm-solo-checkruns eight prompts on one engine, each a step at a time and solo where it can, with a mark at chunk 1 in one of them. The first token, the next window's logits and tokens, the rings' bases and every byte of the state equal their twins, on every rank at both TPs. With=4096,glm-lanes-concurrentpasses at both TPs, and its streams of about 4,170 rows filled a step at a time equal their whole passes.glm-lanes-coverpasses at TP=2 and fails only "copy drafts, sampled" at TP=3, as main's runner does; it fills whole passes, so it shows that path left alone. Twins of 8K, 32K and 64K prompts, greedy and sampled, each fresh, again and twice at once, give one hash a set across unset and=4096(6 sets of 8 replies at each TP), and again withTF_GLM_KV_SHARE=16beside=4096at TP=3. The three cold prompts hash the same in every launch. At TP=2 with=4096and--prompt-cache-gib 0, the 8K, 32K and 64K prompts, greedy and sampled, each filled cold and alone, give one hash over 256 tokens between"draft": falseand drafted (6 of 6 pairs, 1,200 rows drafted).a27444ebb):test-cuda-host276/276 steps (4,183 of 4,192 tests, 9 skipped),zig build test451/451 steps (1,879 of 1,897 tests, 18 skipped),test-kv-pool33/33,compile-cuda-tests10/10 (the CUDA runner, which CI does not build),compile-config-server7/7,zig fmt --check, andtools/zig/lean_check.pyon the merge with main57186386d(424 against main's 424, 0 new). Every touched file is at or under 600 lines on that merge (cuda_lanes.zigis at 600 on main and stays there).othersDecode. Merging this with glm cuda: a prompt step takes two chunks while no other stream decodes, each one's exchanges under the other's sites #1423 today conflicts in 8 files, and with glm cuda: TF_GLM_L2PF reads a decode window's next weights into L2 on a side stream, on by default on a GB10 #1580 in 2, keeping both sides. glm cuda: TF_GLM_KV_HOST keeps the KV pages' latent rows in pinned host memory #1795 edits the same lines ofcuda_ranks.zig, its test,cuda_native.zigand the recipe's## Requestslist, and glm cuda: TF_GLM_KDA_PAD packs the fused KDA input at TP=3 (opt-in, default off) #1545 the field list in that test; keeping both sides and taking the next number resolves those. Against main57186386dthis merges clean.Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. (The twins above cover resumed and concurrent, and the six pairs after them cover drafted against"draft": falseon a solo pass, at TP=2.)glm-solo-checkcompares the bytes.)SUMMARYline is in the receipt. (No kernel changes.)takesTwo,ringsAgree,bufferRows,othersDecode,refuseandSettings.solo, which main does not have;glm-solo-checkneeds a GPU and a checkpoint.)