Repository navigation
qwen3_5 cuda: serve dense EXL3 checkpoints with DFlash2, tensor-core prompt tiles, and host-mapped embeddings - #1407
diwakergupta wants to merge 4 commits into
Conversation
Admit non-MoE qwen3_5 EXL3 checkpoints in cuda_geometry.zig, load dense SwiGLU MLP projections (gate_proj, up_proj, down_proj) in cuda_exl3_weights.zig while guarding grouped-expert workspace allocation on g.moe(), register exl3 in cuda_native.zig formats, and allow attaching the 4-bit DFlash2 drafter to EXL3 targets.
…head spans Preload exl3_candidate during Dense.reserve and route Dense.prompt for rows > 16 to the 64-row tensor-core prompt kernel (tf_exl3_prompt_2) when compatible. Zero-fill split-K atomic counters once on allocation/growth since the kernel resets counters before exiting. Slice .x3 lm_head projections in cuda_draft_frame.zig across the two active vocabulary spans (0..98304 and 248064..248320).
…t scratch Pin BF16 embed_tokens.weight in mapped host memory via HostBuffer.allocMapped in cuda_exl3_weights.zig so embedRows gathers token rows over PCIe without occupying device arena memory, and overlap the sequentially executed DeltaNet mixer, full-attention mixer, and dense MLP scratch regions in Engine.scratch.
Set facts.copy_match to lanes.windows.long_match (20) alongside facts.root_copies on 27B dense (hidden == 5120, layers == 64, experts == 0) so short 5-token suffix matches do not preempt DFlash2 drafting.
|
Thanks @diwakergupta, this is a substantial piece of work and the speed and memory numbers on a 24 GB card are
A split would help: (a) dense EXL3 admission, DFlash2 on EXL3 targets and the head slicing; (b) the prompt tiles; |
|
@ashhart thanks for the feedback! I've split this up into 4 new PRs and addressed all the feedback. We can safely close this PR. |
|
Thanks @diwakergupta, agreed: we'll close this one now that it's split up. Each of the asks from our earlier comment has landed in one of the new PRs, which made this easy to follow. For the record, here is where each part goes. The dense EXL3 path continues in #1465, which makes the same change as #1474 and is already queued for our exactness receipts on a GB10. The prompt tiles are #1475, the memory changes #1476 and the copy policy #1477. We've left a note on each. The drafter's EXL3 head column views from #1474 would be welcome as a small PR on top of #1465. |
What and why
Enable dense
qwen3_5ExLlamaV3 (EXL3) checkpoints with the 4-bit DFlash2 drafter on the native CUDA engine, and close the prompt-prefill, VRAM-headroom, and speculative-decode gaps on 24 GB GPUs:qwen3_5EXL3 admission and DFlash2 attachment (cuda_geometry.zig,cuda_exl3_weights.zig,cuda_native.zig):qwen3_5EXL3 checkpoints (g.pocket == 0), guard MoE grouped-expert workspace allocation ong.moe(), load dense SwiGLUmlp.{gate,up,down}_projviadense(), and allowopenDrafteron EXL3 targets..x3lm_headspan slicing (exl3.zig,exl3_candidate.zig,cuda_draft_frame.zig):exl3_candidateduringDense.reserveand routeDense.prompt(rows > 16, BF16 activations) totf_exl3_prompt_2(64-row tensor-core tiles).Dense.countersonce on allocation/growth sinceexl3_matmul_kernelresets counters before exiting.Weightviews inDense.candidateWeight/candidate.launch(n_blocks = stride_k / (bits * 8)) and slice.x3lm_headincuda_draft_frame.zigacross the two active vocabulary spans (0..98304and248064..248320, 39.7% of the 248,320 vocabulary).embed_tokensand disjoint mixer/MLP scratch union (cuda_exl3_weights.zig,cuda_engine.zig):embed_tokens.weightin mapped host memory (HostBuffer.allocMapped) soembedRowsgathers token rows over PCIe without occupying 2.37 GiB of device arena memory.Engine.scratch, reclaiming 0.46 GiB of device arena memory (2.83 GiB total).root_copiesonlong_match(20tokens) (cuda_native.zig):facts.copy_match = lanes.windows.long_match(20) alongsidefacts.root_copies = trueon 27B dense (hidden == 5120, layers == 64, experts == 0) so short 5-token suffix matches do not preempt DFlash2 drafting.How it was tested
zig buildzig build test test-kernel-contract test-golden test-server-security test-pull-security fuzz-cortheon test-cuda-hostzig build test-kernel-contract -Dsm=80,86,89,120,121python3 tools/zig/lean_new.py(0 newproblems)sm_86, CUDA 13.0 driver) withturboderp/Qwen3.8-27B-exl3(3.50bpw) +z-lab/Qwen3.5-27B-DFlash(4-bit) +--kv-cache fp8:17.21 GiB->14.38 GiB(-2.83 GiB), expanding--context 32768capacity from 2 to 4 concurrent streams and single-stream capacity from147,456to237,568tokens (192k3-needle NIAH passes3/3at50.7 tok/s).retrieval-819215.08s->8.79s(-42%),cache_seed(3.6k tokens)6.90s->3.93s(-43%),vision0.462s->0.320s(-31%),retrieval-65536122.49s->89.46s(-27%).tool154.9->362.6 tok/s(2.34x),retrieval-8192122.7->223.5 tok/s(1.82x),cache_followup30.8->60.9 tok/s(1.98x), 6-task Quality suite6/6at170.8 tok/saverage (198.2 tok/sonsystemd,187.5 tok/sondebug-db_leak), Multi-Turn Agentic Stress4/4(100%, CAI92.4, 0 violations), andtool-eval-bench --short93/100(15/15pass).Checklist
zig build test test-kernel-contract test-golden test-server-security test-pull-security fuzz-cortheon test-cuda-hostpassespython3 tools/zig/lean_check.pyhas no new problems (tools/zig/lean_new.pyagainstorigin/main).cuor.metalfiles changed, the kernel contract was updated