Repository navigation
flashnext cuda: prompt passes with the same bits and less work, and a prompt scratch sized by use - #1764
Conversation
c036db0 to
69c4cc4
Compare
|
Thanks @Arminova. Our GB10 checks are in, base, new, new, base on each:
This lands now. Your branch carries #1763's pre-squash commit under its merge, so we landed your own change, On the overlap with @laudney's #1846 and #1847 (the same 128 x 128 BF16 prompt tile and the same writeback-and-normalize fuse): we're landing this one first. It's measured on both checkpoints, it runs on any SM behind its switches, and it covers six parts theirs doesn't. We'll ask them to rebase what's left onto it. |
|
Thanks, Ash, and for checking it on both checkpoints. One heads-up for the cherry-pick: with #1739 in |
… prompt scratch sized by use Seven changes to prompt passes. Each keeps the bits of main: - BF16 projections' prompt passes of 1,024 rows or more run on prompt16's 128 x 128 tile with the lane's sums (TF_FLASHNEXT_PROMPT_ROWS sets the row count; 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.
3a3f6b6 to
b868261
Compare
|
Thank you @Arminova. 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. |
Mix paired BF16 values in five blocks per row while keeping dense_mix8's FMA order, rounding points, output bytes and ascending FP32 group sums. Glue.hcDenseMix takes the vector kernel from 512 rows of Flash Next's 2560 x 4 streams, so ashhart#1764's native read-out uses it with no new branch at its call site, and fewer rows keep dense_mix8. Add replacement gates, resource records and timing.
89a6600) Conflicts: cuda_batch.zig / cuda_batch_hc.zig take main's ashhart#1764 (its 600-line trim 9693706 instead of our move); cuda_lanes.zig keeps first_before_draft with main's comptime ranked vtable. b5c96c5 (the MTP head's experts on the call's last row only) moves into cuda_mtp_pieces.zig's Piece, which this branch runs forwardHead's pieces through: a piece knows whether it is the call's last (`last`, also in the graph's HeadKey) and only that one runs the experts, the write-back and the copy out, on row 0. 89a6600's FP8 table rows: the opt-in warm-up reads their codes.
What this changes
Seven changes to prompt passes on one GPU. Each keeps the bits of
main:prompt16's 128 x 128 tile with the lane's sums (TF_FLASHNEXT_PROMPT_ROWSsets the row count;TF_FLASHNEXT_PROMPT_BF16=0: the lane). Below 1,024 rows the lane is faster on a GB10 (cold single passes, three rounds: 512 rows +3.6 % on the tile, 768 level, 1,024 -0.8 %, 1,536 -2.0 %).TF_FLASHNEXT_HC_FUSE=0: two).tf_route_logits_widewalks the expert blocks first, so a row tile's input rows are read once (its contract test launches the new grid).fn_qsa_selectkeeps 8 keys in flight a pass and places its picks by warp runs: the same ids, ties included.head_local,native_part,hc_partandpartby what reads them; the prompt cache gets the rest.The default chunk stays 1,536. Five new kernels (
fn_hc_writeback_norm0/_moe/_slices,tf_prompt_bf16/_f32): the writeback-and-normalize ones registered as bit-equal replacements of the two launches, the BF16 tile under the projection contract's FP64 reference.fn_qsa_selectandfn_gdn_fusedtake more registers; their nvcc 13.3 records are updated.#1763 is in
main.main088cfbd35is merged into this branch (a merge commit on top, nothing rewritten), so the diff is this PR's own change, commit69c4cc49e. 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), onmainaf9d7cde7. Base: flashnext cuda: pending DeltaNet rows, reused lane buffers and the shared expert on a side stream #1763's commit (890c4e6b1); this change69c4cc49e. Every server takes one warm-up prompt before the timed ones.Exactness: every reply's
token_sha256equals the base's at 1, 4 and 16 streams, greedy and seeded sampled, code and chat, and on every cold prompt below (with the prompt cache on and off, and withTF_FLASHNEXT_CHUNK=8192 TF_FLASHNEXT_DRAFT_HEAD=affine4).bench_concurrent --alone --serialat 1 and 4 streams (3 reps) and at 16 streams (--context 32768 --parallel 16): every reply equals its solo and serial run. Drafted replies equal"draft": falseon four prompts (300 to 15K tokens). A 32K prompt repeated (resumed from 32,767 cached tokens) and sent concurrently equals the first.Prompt speed, base → this change, tok/s, cold prompts (
bench_cache --require-cold, 0 cached tokens; exact token arrays:main'sdocs/**/*.mdtokenized by the server), mean of two alternated rounds:--prompt-cache-gib 0TF_FLASHNEXT_CHUNK=8192 TF_FLASHNEXT_DRAFT_HEAD=affine4(base once, this change twice)Decode speed at default settings, base → this change, tok/s, mean of two alternated rounds:
bench_openaicode / chat (256 tokens, 3 reps)bench_concurrentcode x1 / x4bench_concurrentchat x1 / x4--context 32768 --parallel 16) code / chatThe 16-stream greedy code cell moves 272-286 tok/s between runs of one build (this change alone: 272.2, 278.2, 281.6 and 285.1 in four runs); the other cells stay within 1 %.
Memory: with 8,192-row chunks the prompt scratch is 3.2 GiB smaller, so the prompt cache gets 933 → 4,221 MiB; at default settings the difference stays within the run-to-run spread of the host's free memory.
Tests on the head:
zig build test456 / 456 steps andtest-cuda-host276 / 276 steps, 0 failures.tools/zig/lean_check.py: 424 problems, the same asmainaf9d7cde7(0 new).Kernel contract (nvcc 13.3.73, GB10), on this change: every gate line of this change's kernels passes.
SUMMARY 535 kernels: 535 pass gates 1-4, 0 fail, 6 known findings; 344 controls: 344 red as planted, 0 missed; 229 limit problemskernel-contract-limitson fatbins for sm_80 / 86 / 89 / 120 / 121: none of this change's records stale, no launch over a limit; the 274 stale records and the 229 limit problems above aremain's own 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.