Repository navigation
Conversation
item 3) qwen3_5/draw_topk.zig moves unchanged to core/lanes/sampling_row_topk.zig (lanes imports become sampling.zig/grammar.zig, the Qwen error names become NonfiniteLogits/NoAllowedToken, the parameter `sampling` is `settings`). sampling_row.draw tries it first for a sampled top_k of 1..128, as qwen3_5/draw.zig did, so qwen3_5/draw.zig is core's draw with the errors mapped back to the Qwen names. The three selection tests move with the code; a core test pins the heap-free path through sampling_row.draw.
|
Thanks @jschmied, this is a clean next step for #2460 item 3. The bounded top-k draw moves into It's queued to land. It's safe because on today's main only Qwen 3.5 calls Optional: the three moved selection tests now run only in the full
|
|
Thanks. So the queued head doesn't change, I'll do the filtered host step for the three moved selection tests as a small follow-up PR after this lands, rather than pushing it here. |
What this changes
The next step of #2460 item 3 (one sampler in
core/lanes), after #2606 moved Qwen 3.5's general host row draw intocore/lanes/sampling_row.zigand #2507 (mrv777) gave Qwen's bounded top-k draw its 32-logit block skip. That boundeddraw now lives in core too:
families/qwen3_5/draw_topk.zigmoves tocore/lanes/sampling_row_topk.zig(git mv, same code). The only editsare names:
lanes.grammar/lanes.samplingbecome the siblinggrammar.zig/sampling.zigimports, the errorsbecome core's
NonfiniteLogits/NoAllowedToken, the parametersamplingissettings(it would shadow theimport), and the last line is split in two to stay under 120 columns. Normalized diff in the receipt.
lanes.sampling_row.drawtries it first, in the same orderqwen3_5/draw.zigdid: a sampled top_k of 1..128draws from the bounded, heap-free path; greedy, top_k 0 and top_k > 128 fall through to the general path, as before.
qwen3_5/draw.zigdrawis core's draw with the errors mapped back toNonfiniteQwenLogitsandNoAllowedQwenToken(as since lanes: the host draw over a bf16 row moves into core, Qwen 3.5 first (#2460 item 3, step 1) #2606), so every Qwen message stays the same.zig/build/qwen35_cache_host.zigdrops their names from itsfilter list: they run in core's lane tests now). A new core test pins the wiring: top_k 1, 20 and 128 through
sampling_row.drawallocate nothing and pick the full-rowchoosetoken.Core vs family-only:
choose)core/lanes/sampling_row.zig(unchanged)chooseOrdered)core/lanes/sampling_row_topk.zig(moved)mask_wordsfrom the Qwen vocab, Qwen full-vocabulary draw testsqwen3_5/draw.zigNot moved: HIP (
hip_serve/sample.zig) and XPU (native/xpu*.zig) keep their own top-k-then-choose code. Neither isa byte copy of this file (no bf16 key order, no block skip: f32 rows and a top_k + margin cut), so they are a later
step, not this PR.
Who else reaches the bounded path: on main only Qwen 3.5 calls
sampling_row.draw. #2679 (open, step 2) movesLFM3's draw and Flash Next's host reference onto it; once both land, their sampled top_k 1..128 rows take the same
bounded path. Its tests show the same token as the general path, so their tokens do not change.
ghon all 367 open PRs, thengit merge-treeagainst this head): three open PRs touchthese files.
sampling_row.zigandqwen3_5/draw_topk.zig, the file this moves,so the two conflict. Since this PR only moves code, Host draw: greedy and masked rows scan 64-logit blocks and skip mask words that allow nothing #2846 should land first; I then redo the move on top of it,
so its block skip moves along unchanged, and rerun the checks below.
zig/build/qwen35_cache_host.zigonly (the test filter list).qwen3_5/draw.zigand merges with this head without conflict.Checks on this head
python3 tools/zig/lean_check.py, on the base and on this head: 341 on the base (223da76), 341 onthis head, 0 new.
zig build -Dfixed-cpu test test-golden test-kernel-contract test-server-security test-pull-security fuzz-cortheon check-release-paths: 728/728 steps, 9179 of 9246 tests passed,67 skipped.
zig build check-native-cuda-host compile-cuda-tests: 16/16 steps.python3 tools/pr_check.py: 0 errors.zig fmt --check build.zig zigandgit diff --check: clean.zig fmt --check,git diff --checkand the lean checker clean;zig build native -Dgpu=sparkfor head and base.test-qwen-draw-host: 13 of 13 turn red (a greedy tie taken>=, the top-k tie order, the mask ignored in either path, the position shifted in either path, three ways of breaking the 32-word block-skip bound, the block non-finite check removed, the fast path unwired, and the two Qwen error names swapped). The clean copy is green.test-qwen35-metal-hostruns on Linux).Receipt
zig build nativeon the GB10 for head and base in the same path. Every embedded fatbin is identical (114 of 114), so no device code changed; the host binary differs (md5 head277f3218, base369e7eac).--parallel 8 --context 16384 --no-thinking, page cache dropped before each server: 11 sampling cases (greedy; top_k 1, 20 and 128 on the bounded path; top_k 0, 129 and 200 and a hot top_k 0 on the general path; JSON-schema output greedy, top_k 0 and top_k 20, where every masked row is a host draw) x 4 prompts x drafted and plain x one at a time and four at once, 48 tokens each: 176 of 176 token arrays identical, 0 differ, 0 errors.lanes.sampling.chooseover the full row, masked and unmasked, every finite bf16 word, and ties.
Proposed CHANGELOG line (Unreleased, for the maintainer to place):
- Core's host row draw (lanes.sampling_row) takes Qwen 3.5's bounded top-k path; the code moved to core/lanes/sampling_row_topk.zig (#2460 item 3). Thanks to @jschmied and @mrv777.