Repository navigation
Conversation
…ared expert on a side stream Three changes to a shared pass's rounds on one GPU. Each keeps the bits of main and has its own switch: - A partly kept window's DeltaNet rows stay pending in a per-stream log instead of being replayed; the next window's chain applies them first, so a rollback only moves the conv windows and the n-gram tail. TF_FLASHNEXT_KEEP_LATE=0 replays as before. - A contiguous lane's fixed-size buffers are reused across streams instead of allocated for every request. TF_FLASHNEXT_LANE_PARTS=0 allocates them as before. - A decode or verify pass's shared expert runs on a side stream beside the routed experts. TF_FLASHNEXT_SHARED_SIDE=0 keeps it in line. Three new kernels (fn_gdn_front_log, fn_gdn_rows_late, and fn_late_roll for a rollback's windows in one launch), each registered with the kernel contract as a bit-equal replacement of the kernels it stands for (zig/tests/cuda/contract_flashnext_late.zig, contract_flashnext_roll.zig; one set in contract_flashnext_more.zig, registered with the family sets). One launch for all streams' DeltaNet steps is left to ashhart#1737 / ashhart#1740. Off or refused with tensor parallelism. Code moved into new files where a file would pass 600 lines (cuda_batch_late, cuda_batch_side, cuda_lane_parts, cuda_seq_parts, cuda_lanes_snap, cuda_mtp_roll).
… prompt scratch sized by use Seven changes to prompt passes. Each keeps the bits of main: - BF16 projections' prompt rows run on prompt16's 128 x 128 tile with the lane's sums (TF_FLASHNEXT_PROMPT_BF16=0: the lane). - A layer's writeback and its read-out's normalize run in one launch (TF_FLASHNEXT_HC_FUSE=0: two launches). - A native projection asked for K slices returns its reduced slice and one zero slice (the old sums' bits, -0 to +0); the other slices are never zeroed. - tf_route_logits_wide walks the expert blocks first, so a row tile's input rows are read from DRAM once (its contract test launches the new grid). - fn_qsa_select keeps 8 keys in flight a pass and places its picks by warp runs: the same ids, ties included. - The fused prompt DeltaNet kernel runs its batch's gated norm on the chain warps. - The prompt scratch sizes head_local, native_part, hc_part and part by what reads them; the prompt cache gets the rest. Five new kernels (fn_hc_writeback_norm0 / _moe / _slices, tf_prompt_bf16 / _f32): the first three registered with the kernel contract as bit-equal replacements of the writeback and normalize launches (contract_flashnext_wbnorm.zig), the BF16 tile under the projection contract's FP64 reference (contract_projection_f32.zig). The default chunk stays 1,536. Off with tensor parallelism where noted in the code. The read-out helpers moved to cuda_batch_hc.zig and the scratch sizes to cuda_scratch_sizes.zig.
…ent, deeper greedy drafts, CUDA graphs Seven changes to drafted decoding. Replies keep the bits of main (drafts change, accepted tokens do not): - A drafted stream's first token is sent before its first drafts (TF_FLASHNEXT_FIRST_EARLY=0: after). - The n-gram table is read ahead into the page cache and loaded weight shards are dropped from it (TF_FLASHNEXT_TABLE_WARM=0, TF_FLASHNEXT_DROP_LOADED=0). - The draft chain stops on the running product of its probabilities; the core gets the chain's chances. - Greedy streams draft up to 8 deep; sampled streams keep 6. - Sampled draws read a row's top_k candidates from the GPU instead of the whole row (fn_row_topk, its candidates in column order, registered with the kernel contract against a host oracle; TF_FLASHNEXT_GPU_TOPK=0: the whole row). - A drafted verify window leaves its scores on the device (TF_FLASHNEXT_VERIFY_HOST_LOGITS=1: copied). - Drafted windows, draft-head pieces and rollbacks run as CUDA graphs on one GPU (TF_FLASHNEXT_WINDOW_GRAPH=0: plain launches). Off with tensor parallelism. New files cuda_mtp_draw, cuda_mtp_pieces, cuda_window_graph.
Arminova
force-pushed
the
flashnext/draft-round
branch
2 times, most recently
from
November 1, 2026 09:52
dcf28f5 to
4380166
Compare
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.
What this changes
Seven changes to drafted rounds on one GPU. Replies keep the bits of
main; drafts change, accepted tokens do not. Each has its own switch:TF_FLASHNEXT_FIRST_EARLY=0: after).TF_FLASHNEXT_TABLE_WARM=0,TF_FLASHNEXT_DROP_LOADED=0).top_kcandidates from the GPU instead of the whole row (TF_FLASHNEXT_GPU_TOPK=0: the whole row).TF_FLASHNEXT_VERIFY_HOST_LOGITS=1: copied).TF_FLASHNEXT_WINDOW_GRAPH=0: plain launches).One new kernel,
fn_row_topk(a row's K best in column order, ties to the lowest columns), registered with the kernel contract against a host oracle; its set joins the family sets. Off with tensor parallelism. New filescuda_mtp_draw,cuda_mtp_pieces,cuda_window_graph.#1445 adds CUDA graphs on the EXL3 path; this PR's graphs are the FP4-Local path's drafted windows, in their own file. Glad to line the two up if you prefer one graph cache.
Depends on #1764: its first commit is #1763's, its second #1764's change rebased onto #1763's current head; this PR's own change is the third commit. Best reviewed after #1764. Part of #1762.
Receipt
Environment: as flashnext cuda: pending DeltaNet rows, reused lane buffers and the shared expert on a side stream #1763 (GB10, driver 580.173.02, nvcc 13.3.73,
nvidia/Qwen3.8-Flash-Next-FP4-Localatb9ce18a6,--context 262144 --parallel 3, bf16 KV, prompt cache at its default size, a fresh server for every run). Base: the second commit here (flashnext cuda: prompt passes with the same bits and less work, and a prompt scratch sized by use #1764 on flashnext cuda: pending DeltaNet rows, reused lane buffers and the shared expert on a side stream #1763's head). The runs useddcf28f53a; the head adds one line todraft_sources_cuda_test.zig(itsCudasets the newdepth_greedy) andfn_row_topk's launch record measured in the contract run below, neither part of the server build.Exactness: every reply's
token_sha256equals the base's at 1, 4 and 16 streams, greedy and seeded sampled, code and chat, at default settings, and at 1 and 4 streams withTF_FLASHNEXT_CHUNK=8192 TF_FLASHNEXT_DRAFT_HEAD=affine4.bench_concurrent --levels 1,4 --alone --serial: every reply equals its solo and serial run. Drafted replies equal"draft": falseon four prompts (300 to 15K tokens).bench_cacheon cold 512 / 2,048 / 16,384-token prompts gives the base's replies, and a 32K prompt repeated (resumed from 32,767 cached tokens) and sent concurrently equals the first.Decode speed at default settings, base → this change, tok/s, mean of two alternated rounds (base, this change, this change, base):
bench_openaicode / chat (256 tokens, 3 reps)bench_concurrentcode x1 / x4bench_concurrentchat x1 / x4--context 32768 --parallel 16) code / chatWith
TF_FLASHNEXT_CHUNK=8192 TF_FLASHNEXT_DRAFT_HEAD=affine4(one round):bench_concurrentcode x1 / x4 76.2 → 81.6 / 133.6 → 143.0, chat 47.1 → 49.7 / 85.9 → 90.4.First token, ms (lower is better), same rounds: a new ~90-token prompt, one stream, 233.8 → 229.4; the same prompt resumed 71.3 → 63.5; after cold 512 / 2,048 / 16,384-token prompts (
bench_cache --require-cold) 420 → 379 / 1,260 → 1,165 / 9,379 → 9,028.Memory: unchanged. Both builds hold the same fixed use within the log's 0.1 GiB rounding; the prompt cache's size follows the host's free memory at start on both.
Tests on the head:
zig build test449 / 449 steps andtest-cuda-host274 / 274 steps, 0 failures.Kernel contract (nvcc 13.3.73, GB10), run with upstream's
fbbc20d0fapplied (the brace incontract_controls.cu;main20705d604does not build the runner without it):SUMMARY 518 kernels: 518 pass gates 1-4, 0 fail, 6 known findings; 342 controls: 342 red as planted, 0 missed; 226 limit problemsfn_row_topk's gate lines all pass.kernel-contract-limits: its record in this push is the run'sRECORDline (sm_121: 31 registers, 9,228 static shared bytes); the run itself still had the estimate, which is the one limit problem of this PR's. The others aremain's own records on this nvcc build.Not run: TP2 (one GB10; every change keeps today's path with tensor parallelism), Metal and HIP (CUDA-only change), CUDA chips other than GB10 (launch records only).
Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo.SUMMARYline is in the receipt.