cuda: COLI_CUDA_RESID=1 — expert-group results stay on device (#431 PR-C0) - #434
Conversation
|
Un-draft gate result: champion-regime A/B (1,024-token, usage-snapshot-controlled, late segment at hit 99.1%) measured 5.07 vs 5.11 tok/s — parity, gate not cleared. Staying draft. Full analysis and the roadmap pivot in #431 (comment) — the choreography this PR removes turns out to sit off the critical path on the 6-GPU pipe2 topology at every reachable operating point. The dataflow remains the graph-correct one; parking it until something puts the GPU side back on the critical path. |
88a8045 to
87c8369
Compare
…gg#431 PR-C0) Decode-time (S=1) expert groups without the host round-trip. Today each VRAM-tier group costs: host gather-memcpy of the input row, H2D, grouped kernels, D2H of every expert row, a per-device stream sync, and a host weighted accumulation — per device, per layer. Under this flag: issue input row P2P from the layer's home device -> broadcast -> grouped-W4 kernels -> per-expert weighting and a fixed-order reduce ON the group's device -> partial sum peer-pushed into a per-issue slot on the home device -> event. Fully async: zero host bytes, zero syncs. take after moe() returns, the home legacy stream waits every issue event and reduces the slots in issue order (deterministic, no atomics), then the accumulator joins the residual exactly where the routed upload used to. The CPU tier overlaps with the issued GPU work through moe() as before — this subsumes the overlap JustVugg#342 was after, with the take phase collapsed into a stream dependency instead of a collection pass. A failed take would silently drop routed experts (a wrong answer, not a slow one), so it is fatal by design; a failed issue falls back to the synchronous path per device. Buffers reserve at the 64-expert cap so re-issue never reallocs under a still-queued stream. Measured (6x RTX 5090, ROUTER=1 TC_W4A16=1, TEMP=0 DRAFT=0): parity at every operating point reachable in a cold-start A/B (96-token: 74.0 vs 74.3 s; 256-token warm segment t=128..256: 2.91 vs 2.89 tok/s) — at hit 94-97% the choreography this removes hides behind ~350-700 MB/token of disk misses. 256-token greedy text is byte-identical across the flag despite the accumulation-order change. The champion regime (hit 99-100%, where the removed syncs sit on the critical path) needs a matured-cache A/B and is the acceptance gate for un-drafting; either way this is the dataflow a single-graph decode (JustVugg#431 PR-C) requires — a graph cannot contain a host-side accumulation.
87c8369 to
0f8cbe2
Compare
|
Rebased onto current
|
…Windows CI) The rebase that renamed my PR-C0 entries to *_resident_* left two stubs in backend_loader.c with the new function name but the OLD field name in the availability guard, so the resident_issue stub kept the plain name and collided with JustVugg#342's coli_cuda_expert_group_issue on the MinGW CUDA-DLL build (conflicting types — JustVugg#342's take returns a host pointer, mine reduces on-device). Name and guard field now agree on the _resident_ variant in both stubs. MinGW syntax check clean; make check 105/105.
|
To merge this I need validation data I can't produce myself (no such GPU here). The bar every backend holds: (1) correctness first — a teacher-forcing token-exact check on a tiny model ( For COLI_CUDA_RESID=1 (expert-group results stay on device): the claim is a placement change, so a byte-identical proof (sha256 of a greedy completion with RESID on vs off, same as #474 did) plus the tok/s delta would let me merge fast. Thanks @ZacharyZcR. |
|
Validation data as requested — rebased onto current Byte-identical proof — 6× RTX 5090, driver 610.43.02, CUDA 13.3, GLM-5.2 int4, full champion config (
Perf, same runs (expert hit 100%, i.e. nothing hiding behind disk):
Parity, as the PR body states — this is a structural change (the dataflow a graph-captured decode needs), not a speed claim. On the red CI: the Engine/linux/macos jobs fail on anything that merges with current |
|
Merged. The flag-only A/B on the same binary with identical sha256 is the right way to prove a dataflow change, and calling the perf parity honestly instead of dressing it as a win is why this went in without further questions. You were also right about the red CI — and to be precise about blame: those 12 stray binaries were committed by my conflict resolution on #368 (a careless |
Third increment of #431. Stacked on #432 (shares the branch history — review the top commit).
What
Decode-time (S=1) expert groups without the host round-trip. Today each VRAM-tier group costs: host gather-memcpy, H2D, kernels, D2H of every expert row, a per-device sync, and a host weighted accumulation — per device, per layer. Under
COLI_CUDA_RESID=1:moe()returns, the home legacy stream waits every issue event and reduces the slots in issue order (deterministic, no atomics), joining the residual exactly where the routed upload used to.The CPU tier overlaps with the issued GPU work as before — this subsumes the overlap #342 was after, with the take phase collapsed into a stream dependency. A failed take would silently drop routed experts (a wrong answer, not a slow one) → fatal by design; a failed issue falls back to the synchronous path per device. Buffers reserve at the 64-expert cap so a re-issue never reallocs under a still-queued stream.
Measured — all three operating points, wall-clock parity everywhere
6× RTX 5090,
ROUTER=1 TC_W4A16=1 TEMP=0 DRAFT=0, same binary, flag-only:The matured-cache warm A/B this PR was gated on has now run — and it closed the question honestly: parity even at hit 100%. The profiler's summed API time was a mirage; with
COLI_CUDA_PIPE=2the choreography already overlaps the critical path (full analysis in #431). This PR is therefore not a speed change and does not claim one.Why merge it, then
COLI_CUDA_RESID=1opt-in), byte-identical output, and a fail-fast take path — no behavior change unless asked for.make check77/77; CUDA build zero warnings; oracle from #432 unaffected.