Repository navigation
Conversation
…KEN_MOE_PREFETCH Stage A of cross-layer expert prefetch: in GPU decode, layer L-1's router input times layer L's router predicts layer L's experts on a dedicated stream forked after ensure(L-1); the first BUDGET non-resident candidates of the top-K are joined and counted against layer L's routing after its ensure. No copies and no cache writes; off by default and launch-identical when off. Assisted-by: Claude Opus 5.5
…d its measure mode Assisted-by: Claude Opus 5.5
Assisted-by: Claude Opus 5.5
…gh layer l's router The counter test scores the spied logits, so it cannot see a wrong router or input; this one feeds distinct per-layer inputs and recomputes each prediction's logits on the host. Assisted-by: Claude Opus 5.5
…FREETOKEN_MOE_PREFETCH=on The predictor stream installs layer L's kept candidates with a prefetch mode of the scored ensure kernel (no clock bump, usage == step stays pinned, usage 0 marks the slot low priority) and a third dedicated stream slim-copies them after copy(L-1). The compute stream joins the install before ensure(L) and the copy before copy(L); ensure(L) counts useful hits, calls, misses and late copies. LRU runs the vendored kernel while prefetch is on. Assisted-by: Claude Opus 5.5
…der delayed streams A delayed install that lands after ensure(L) changes no output, so the race test now also compares the delayed run's slot maps and counts with an undelayed run's. Assisted-by: Claude Opus 5.5
…a cache frees its banks The prefetcher's back-reference made a cycle, so a dropped cache kept its slot banks in VRAM until the next gc pass. Assisted-by: Claude Opus 5.5
The slim copy is an SM kernel. At default priority a copy that starts even 50 us late waits for SMs behind the next compute grid while the compute stream waits on it: +13.7% per step vs off at bs 1 in bench_moe_prefetch --on, against -16.3% at high priority. No measurable cost when nothing is late. Assisted-by: Claude Opus 5.5
…the prefetch bench Assisted-by: Claude Opus 5.5
…ls nothing Assisted-by: Claude Opus 5.5
…d graph interleaving Adds a stall before each decode GEMM (copy(L+1) lands before GEMM(L) reads; flood candidates reach the pinned slots even under lru), prefills between decodes on every prefill path (materialize, overlap, overlap + hit-D2D, small ensure), bs 1/2 graphs in one pool replayed between eager steps, a per-layer delay fuzz over all four streams, the per-bank copy fallback, and the kernel against the reference at 48 x 512 experts, 1480 slots and 8 rows. Assisted-by: Claude Opus 5.5
prefetch_ensure(L) scored slots as if layer L had just run, so L's own residents looked a whole pass away and were the first residents it evicted, right before L routed them. On the steady-state trace bench this cost +0.18 (bs 1) and +0.42 (bs 2) extra demand misses per layer; scored from layer L-1 the excess is gone and on-mode steps are 1.6-2.5 pts faster. Assisted-by: Claude Opus 5.5
--steady replays a recorded routing trace with no cache restore, a noisy copy of each layer's traced logits as the lookahead and per-layer-kind fillers, and interleaves the arms step by step (each on its own copy of the cache state) so drift hits them alike. It reports pollution and the late fraction before GDN and QSA layers next to ms/step. Assisted-by: Claude Opus 5.5
…and relax the eager late bound Every offload cache under test makes dedicated streams and torch keeps a cuBLAS workspace per stream for the session (~16 MiB a prefetch stack): the prefetch suites grew one pytest process past 8 GiB and hit OOM beside another GPU user; now the peak is ~1 GiB. The eager delayed-copy case asserted late >= 0.9 of copies, which a loaded host misses (3 of 10 loops); replay keeps the exact late == copied check. Assisted-by: Claude Opus 5.5
…teardown Assisted-by: Claude Opus 5.5
… the gpu A process-wide FREETOKEN_MOE_PREFETCH made every hybrid or CPU-decoded cache raise at build (two hybrid-fetch and two overlap-flag tests failed under the flag). The flag now logs and leaves those caches off, as FREETOKEN_MOE_COPY_OVERLAP does; an explicit prefetch_mode still raises. Assisted-by: Claude Opus 5.5
…behind FREETOKEN_MOE_PREFETCH_VERIFY Debug detector for the prefetch-on nondeterminism. For every GPU decode layer call, on the compute stream and without any event or wait: the routed slots map to the router's experts (before and after the GEMM) and, with =1, every routed slot's bank rows equal the host rows before and after the GEMM (a 53 MiB scratch filled by the fused copy). Per-layer device counts and the first 64 offending records (with the slot owner, usage and which copy plan held the slot) are logged every 256 decode steps and at shutdown. =meta checks only the maps (~1% decode cost); =1 costs 2.4-3.3x. Assisted-by: Claude Opus 5.5
…een decode steps Assisted-by: Claude Opus 5.5
…d FREETOKEN_MOE_SLOT_AUDIT Assisted-by: Claude Opus 5.5
Assisted-by: Claude Opus 5.5
… sizes and eager steps Assisted-by: Claude Opus 5.5
…write has one writer The predictor stream ran prefetch_ensure(L), a slot map writer, guarded from the demand ensure(L) only by a cross-stream event; a production verify record shows the two overlapped. The predictor now forks at the start of layer L-1's MoE block and only computes the merged lookahead candidates (it reads no cache state); right after ensure(L-1) the compute stream waits for them and runs prefetch_ensure(L), which applies residency and the budget itself, so the installs equal the old ones and do not depend on stream timing. join_ensure is gone. Assisted-by: Claude Opus 5.5
… right after a prefill Assisted-by: Claude Opus 5.5
…-writer test At d6a0a99 the select assertion came first and raised AttributeError on _none_resident, so the writer-stream checks never ran against the old engine. Now it fails there on prefetch_ensure off the compute stream (16/16). Assisted-by: Claude Opus 5.5
…its negative control prefetch_ensure(L) runs on the compute stream before join_copy(L-1), so it can take over a slot copy(L-1) is still writing; count that on the device under late copies and check no bit changes. Ordering copy(L) only after its own install, on a second stream, corrupts the slot. Assisted-by: Claude Opus 5.5
Owner
Author
|
Deployed on
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #71/#72/#73 (branch base
5080deploy@ 6599710). Expert prefetch for the offloaded-MoE decode, behindFREETOKEN_MOE_PREFETCH=off|measure|on(default off), plus two debug detectors that were needed to make it lossless.What. While layer L-1 computes, predict layer L's routed experts and copy them over the otherwise-idle PCIe link. A decode step leaves the link idle about half the time, ~225 µs per layer in nsys.
ensure(L-1),prefetch_ensure(L)installs the first budget non-resident candidates into low-priority slots: held with usage 0, keyed between empty slots and every real resident, so a wrong guess is the next victim. It writes its own copy plan.copy_missing(L). A demand hit on a prefetched slot clears its low-priority mark.FREETOKEN_MOE_PREFETCH_BUDGET: default 3 before GDN layers and 4 before attention layers; 4 is the measured best.FREETOKEN_MOE_PREFETCH_K: candidates, default 16.measure: counts useful predictions without copying.Single writer. Every write to the slot maps (
slot_for_id,id_of_slot, usage, eviction mirrors) happens on the compute stream in program order. Only reads and byte copies cross streams. An earlier version ranprefetch_ensureon the predictor stream behind an event join. On the real model it corrupted greedy output in rare runs:A CPU model of both kernels proved the recorded bad state is reachable only if the two map writers overlap. nsys showed no violation in 400k samples, so the join failed only in some rare execution (first decode after a prefill). Rather than depend on that edge, the maps now have one writer.
Measured. RTX 5080, Qwen3.8-Flash-Next-NVFP4, 1650 slots, rule eviction + copy overlap (#71/#72), bs=1, interleaved ABAB, decode tok/s at 32K / 128K:
Measure mode on the real model: useful predictions 1.73–1.84 per layer at precision ~0.55, covering ~42% of demand misses.
Losslessness evidence on the real model (greedy, 256-token outputs, cold nonce-prefixed prompts, compared prompt by prompt with a prefetch-off reference that is identical across three server restarts):
FREETOKEN_MOE_PREFETCH_VERIFY=meta: 0/120, 0 verifier records. This is the config that amplified the old bug to 2–6/60.FREETOKEN_MOE_SLOT_AUDIT=64: 0/120; 444 full-cache audits byte-checked every held slot, 0 bad.Debug tools (default off, zero cost when off):
FREETOKEN_MOE_PREFETCH_VERIFY=meta|1checks every routed slot's maps (meta), plus its bytes before and after each expert GEMM (1).FREETOKEN_MOE_SLOT_AUDIT=Nrecords the last writers of every slot and byte-checks the whole cache every N decode steps.Tests: 75+ new tests, including:
Full not-slow suite: only the 4 known environment failures.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Bu6LgoxLR4wETqb7RPR2vt