Repository navigation
qwen3_5 cuda: the mixers' and the dense MLP's scratch rows share one region - #1476
diwakergupta wants to merge 1 commit into
Conversation
|
Thanks @diwakergupta. The union is careful, and we agree with your reading of it. We went through every user of the shared rows: the forward's mixers and dense MLP, the prompt attention and delta helpers,
After the rebase we'll A/B the union on a GB10: the MLX 27B and a MoE MLX checkpoint against main (token hashes, concurrent == solo, drafted == plain, prefill and decode speed), and the dense EXL3 pack against #1465 by token hash. On a GB10 the mapped rows free nothing, because host and device share one pool, so there we'll only check that prefill isn't slower. |
a8de132 to
34015dc
Compare
|
Thanks @diwakergupta. The rebased commit is line for line the one we reviewed, and the description now says the mapped embedding covers the MoE EXL3 packs as well. Merged onto current main, fmt, lean (no new findings), One small thing: the title still says "stacked on #1474"; please make it #1465. Next we'll A/B it on a GB10 against main: the MLX 27B and a MoE MLX checkpoint (token hashes, concurrent == solo, drafted == plain, prefill and decode speed), and the dense EXL3 pack against #1465 by token hash, with prefill and decode speed, since every round's embedding rows now come from mapped host memory. |
|
Thanks @diwakergupta, nothing else is open here. After #1465 we'll A/B it on a GB10:
We've started the CI runs that were waiting on our approval. |
|
Thanks @ashhart. One note on CI: |
|
Thanks @diwakergupta, you're right. That's the Windows timing flake in |
|
Hi @ashhart, checking in. The rerun of |
|
Thanks @diwakergupta. We ran this on a GB10 (sm_121) against main, with Qwen3.8-27B EXL3 3.50bpw, fresh servers per arm and alternating base/new rounds. The output is exact: 0 of 12 prompt-test rows differ from main. Speed came out slightly but consistently lower, though. Every candidate run in each of these cells was below every main run:
Prefill is unchanged (within 0.6%). We don't land changes that slow the default path, so we're parking this for now. A likely suspect is the host-mapped embeddings, since every decode step would read them over the host link. If the shared mixer/MLP scratch on its own is neutral or faster, splitting that out would let us land it straight away. |
… region A layer's mixer, then its MLP, pass only h, x, xs and r between them, so the delta mixer's rows, the attention mixer's rows and the dense MLP's gate, up and act start at one offset of the arena, which takes the largest of the three. The attention mixer's y and mix are the delta mixer's. cuda_scratch.zig carves them; Engine.scratch is its function.
34015dc to
f33ed2d
Compare
|
Thanks @ashhart. I split it as you suggested. Pushed
The host-mapped embedding is now #1678. It maps only when a discrete card has no room for the weights, one stream at the asked window and the drafter. On a 24 GB card that lets the 27B serve a 98k or 128k window that |
|
Thanks @diwakergupta for splitting it. We ran the shared-scratch version (f33ed2d) on a GB10 against main, Qwen3.8-27B EXL3 3.50 bpw, fresh servers per arm, alternating base/new/new/base. Tokens are equal to main (0 of 12 prompt-test rows differ), and almost everything is flat: 8k and 32k prompts within 0.3%, and 1, 2, 4 and 8 streams within 0.2%. One cell is consistently slower, though. Cold prefill on the 2,048-token prompts is 495.0 to 490.5 tok/s (-0.9%), and every run of this PR came in under every run of main:
Decode right after those prompts is -0.6% the same way. It only shows at the shortest prompt, so it looks like a fixed per-prompt cost rather than per-token work. A first touch of the shared region, or an extra clear or reservation when a prompt starts, would fit. We don't land a slower default path, so we're holding this for now. If that cost goes, the 0.46 GiB saving lands as it is, and we'll rerun the same cells. |
What this changes
The
qwen3_5engine's scratch rows for the two mixers and the dense MLP now share one region of the arena. A layer runs its mixer, then its MLP, and onlyh,x,xsandrpass between them, so the delta mixer's rows, the attention mixer's rows and the dense MLP'sgate,upandactcan start at the same offset. The region takes the largest of the three.cuda_scratch.zigcarves the scratch:Takegainsmark,rewindandpastto lay the three regions over one another. The attention mixer'syandmixare the delta mixer's rows.Engine.scratchis now this file's function.This is #1476 cut down, as @ashhart suggested: the host-mapped embedding is dropped from this PR. It slowed decode on the GB10, and it now loads only when the card has no room for it, in its own PR.
Receipt
Environment. RTX 3090 Ti (24 GB,
sm_86).turboderp/Qwen3.8-27B-exl3branch3.50bpw(rev8351c54e),z-lab/Qwen3.8-27B-DFlash2(rev50307d4c) at 4 bits, bf16 KV cache,--context 32768. Both binaries came fromzig build native -Dsm=86, one frommain(a0d24896) and one from this branch. Each ran twice, alternating (main, this,main, this), on a restarted server.Exactness.
tools/bench_concurrent.py --tokens 384 --reps 3 --alone --serial, the default code and chat cells (greedy and sampled) at--levels 1,4, and--levels 1with--promptsof two long prompts (5,080 and 2,278 tokens):"draft": falsein every cell on both binaries: 0 unequal, 0 failed.token_sha256of this branch equalsmain's in 528/528 replies.Decode speed. Per-stream tok/s, runs 1 / 2 (each a median of 3), with tokens per round:
mainmainmaintoo (5.26 / 5.30), and in long greedy run 2 this PR's round count (4.57) is below both ofmain's.Prompt speed. Three distinct cold ~8,145-token prompts per run (
cached_tokens0,max_tokens1),prefill_secondsfrom the reply:main14.648 s mean, this PR 14.654 s.Tests. The full checklist suite (
zig build test test-kernel-contract test-golden test-server-security test-pull-security fuzz-cortheon test-cuda-host) plustest-qwen35-formats-host: 478/481 steps succeeded. The one failure iskeepalive_test"a silent engine's stream gets keepalives before its first token", which crashes the same way onmain(a0d24896) on this machine.lean_new.pyagainstmain: 0 new problems. New host test:format coexistence: disjoint mixer and dense MLP scratch regions share one arena union(qwen35_formats_host.zig). It fails onmain, whereyandgateare separate rows.Not run. GB10 /
sm_121. Metal (not affected). A MoE checkpoint served: its routed scratch still follows the shared region, but no MoE run was made.Checklist
"draft": false, concurrent equals alone, and this branch's tokens equalmain's.sm_86only.