Should a GB300 Prefetch Its Cold Experts? Mostly No, and What to Build Instead
1. Where an expert can live
DeepSeek-V4.1-Flash is a mixture-of-experts model. Each of its 40 MoE layers has 384 small sub-networks ("experts"), and for each token the layer's router picks 6 of them. In the MXFP4 checkpoint one expert is 17.92 MiB and one layer's full set is 6.72 GiB, so all of them don't fit in GPU memory next to a 1M-token KV cache. Our recipes split each layer's experts: the most-used ones stay in GPU memory ("hot"), the rest live somewhere slower ("cold").
Figure 1. The three places an expert can sit. Expert-copy times are arithmetic: 17.92 MiB ÷ 340 GB/s ≈ 55 µs (C2C, measured ~340 GB/s for pinned host memory on this box); ÷ 10–12 GB/s ≈ 1.6–1.9 ms (RAID0 array, sequential).
Two facts about this box shape everything below. First, the fast way to use Grace memory is to read it in place over the chip-to-chip (C2C) link at ~340 GB/s. The tricks that would let the GPU "adopt" a Grace page without copying it (remapping it through the GPU's page table, or managed memory) measured at ~90 and ~155 GB/s here, so they're slower. That means prefetch on a GB300 has to be a real copy into reserved HBM. Second, the SSD is two orders of magnitude slower than C2C. It's a place to store a model, not something to read from while generating a token.
2. What "prefetch" means
Today's Grace-offload recipes do a demand read: the router picks its experts, and if one is cold the expert kernel reads it straight out of Grace memory while it runs. Prefetching means guessing that choice before the router makes it, during the previous layer, and copying the guessed expert into a spare HBM slot so it's already local when the layer runs.
Figure 2. Prefetch hides the cold read behind the previous layer, if it guessed right. A wrong guess falls back to today's demand read, so correctness never depends on the guess; only speed does.
3. How much is left to win
This is where the hunch runs into our own earlier result. In September we stopped choosing cold experts by position (whole layers' worth, in load order) and started choosing them by measured usage: keep the 295 most-used experts of each layer in HBM, and send only the 89 least-used to Grace. On the same box in the same window that took one user from 88.7 to 153.2 tok/s (+73%), eight users from 305 to 704 (+130%), and sixteen from 385 to 953 (2.3×), with greedy output unchanged (44/44). The reason was bytes: the usage map cut the share of routed picks that land on a cold expert from about 24% to 2.7%.
Figure 3. Bars are arithmetic, not measurements, and simplified (one token, six picks per layer, no overlap with compute). The measured anchor is the September v14 → v15 same-window pair. Purple bars are hypothetical models, not anything we serve.
So on today's map the cold reads left over are about 0.36 ms of a 14.6 ms step, roughly 2.5%. That's the ceiling for a perfect prefetcher, and the real number is lower, because a demand read already overlaps with the expert math that's using it. The research put the realistic ceiling at about 1% for one user, which is smaller than this lane's ordinary day-to-day drift (~3%). At eight or more users there's nothing to collect: the union of experts in use is already resident.
Put plainly, a usage map and prefetch go after the same bytes, and the map is the cheaper of the two: no guessing, no copies, no slots, no new graph risk. The better the map, the less prefetch is worth.
4. What it would cost
Prefetching needs somewhere to copy to. A modest bank of 3 spare slots per layer is 120 experts × 17.92 MiB = 2.1 GiB of HBM. On this lane, HBM that isn't weights is KV cache, at about 0.518 M tokens per GiB.
Figure 4. 120 experts × 17.92 MiB = 2.1 GiB; 2.1 GiB × 0.518 M tokens/GiB ≈ 1.09 M tokens; 1.09 / 2.54 ≈ 43%. That's a bad trade on a lane whose whole point is a 1M-token context.
5. The real wall: guessing
Even if bytes and slots were free, a prefetcher is only as good as its guess. The guess has to pick 6 of 384 experts in a layer before that layer's router runs. Here is every cheap guesser we've measured on this model family, plus what the literature reports:
| Way to guess | Result | Source |
|---|---|---|
| Use the previous layer's choices | 8.4% precision (bar was 50%) | our September campaign |
| Use the speculative-decoding draft's choices | 0.0316 overlap vs 0.0312 for pure chance; 0 of 75 layers above 2× chance | our September campaign |
| Use the previous step's choices, same layer | 0.000 extra coverage (the cache already holds them) | our September campaign |
| Perfect-hindsight cache, 3× top-k slots | 0.68 hit rate: a ceiling, not a predictor | our routing histogram |
| Small trained head per layer, run before attention | 93–97% top-k accuracy on DeepSeek-V2-Lite, Qwen3-30B, Phi-mini-MoE | arXiv 2511.10676 |
The free signals are noise on this model. The one guesser with real evidence behind it is a trained two-linear-layer head per layer, and it has only been tested on smaller MoEs, never on a 384-expert, top-6 router like this one. The published systems that win big with prefetch (ProMoE, ExpertFlow, MoE-Infinity) all use a model-specific trained predictor and run where a miss costs a PCIe round trip. On a GB300 a miss costs a fraction of a millisecond.
6. What vLLM has, and the open PRs
vLLM already ships the plumbing, just at the wrong grain. The PrefetchOffloader in our serving image (vLLM af7f9488) copies the next layer's weights into fixed GPU buffers on a side stream, one layer ahead, and it works inside CUDA graphs. Its unit is a whole parameter, though. Pointed at the experts, it would copy all 6.72 GiB of a layer every step: about 20 ms per layer at 340 GB/s, against a 14.6 ms whole-model step. That suits prefill, not decode.
Per-expert, graph-safe residency isn't in vLLM main. It's spread across open PRs, which we fetched and applied to our serving commit on October 23:
| PR | What it is | Applies to our commit? | Worth it to us? |
|---|---|---|---|
| #56177 shared GPU expert pool | device-side expert table + in-graph row copies (NVFP4/Marlin only) | package cleanly; 3 files need hand fixes | Yes, the table and copy code |
| #62060 stage offloaded experts for big steps | copy a layer's offloaded experts into VRAM for prefill-sized steps only | 1 conflicting hunk + 1 hunk for a file we don't have | Only on a Grace-offload lane, for long prompts |
| #57943 host-bank primitives (RFC #57794) | pinned host rows with a device view | clean | Nothing imports it yet |
| #41474 batched prefetch copies | cheaper launch of many small copies | clean | Not until copies are small and many |
| #37190 LFRU expert cache | sync copies, eager mode, BF16/FP8 | no, 6 files | No |
| #51710 MoE prefetch offloader | layer-grain prefetch with a planner | no, 4 files | No; rewrites the offloader we use |
So "use the stack of open PRs" doesn't work as a stack. It's three competing designs plus two utilities, and several of them are mutually exclusive on the same tensors. You pick one path. The most valuable piece isn't a prefetch PR at all: it's #56177's device-side table, which tracks which experts are being used without ever stopping to ask the CPU.
7. What to build instead
The September win came from a static map: measure usage once, choose 295 hot experts per layer at boot, done. Its weak spot shows up in Figure 3, row 3. When traffic changes (a map built on agent traffic, then fed prose) the cold share jumps from 2.7% to 20.5%, and today the only fix is to reboot with a different map. We parked an adaptive version in September because every way of watching routing inside the CUDA graph cost 3.7–9.6% of a one-user step, and the bar was 1%.
The design that came out of this round, which we're calling the "dynamic two-bank", keeps everything that works today and adds one cheap observation:
Figure 5. The "dynamic two-bank" design. Counting happens inside a kernel that already runs every layer, so there's no new launch and no CPU round-trip. Decisions and swaps happen between forwards, never on the critical path.
What we borrow from #56177 is its device-side table and its graph-safe row-copy kernel. What we leave out is its copy-on-miss policy (copy an expert into HBM the moment it's needed). That policy is right on the PCIe box the PR was measured on. Here it's wrong at small batch: the copy uses the same 340 GB/s link a demand read would, and then the GPU still has to read the copy out of HBM. Estimated cost of the two-bank port: 6–8 working days, 2 boots, ~18 MiB of HBM, no KV loss. Expected payoff (an estimate, not a measurement): recovering the roughly 15–20% one-user speed we lose whenever traffic doesn't match the boot-time map, without a reboot per traffic class.
8. First probe results
Two cheap experiments could change that design, so we wrote both as standalone probes that don't touch the serving lane.
E1: does the counter cost too much? The bar was ≤1% of a step, ideally ≤0.5%. We ran the existing split kernel with and without one atomic add per routed pick, 40 layers, captured in a CUDA graph:
| tokens per step | picks per layer | without counter | with counter | added | % of 14.6 ms |
|---|---|---|---|---|---|
| 6 | 36 | 57.5 µs | 77.9 µs | 20.5 µs | 0.14% |
| 16 | 96 | 45.2 µs | 67.7 µs | 22.5 µs | 0.15% |
| 32 | 192 | 45.1 µs | 84.1 µs | 39.0 µs | 0.27% |
That's about half a microsecond to a microsecond per layer, 2–3× inside the stricter bar. Caveat: this ran on the Station's RTX PRO 6000 (sm_120), because the GB300 had only 0.51 GiB free while serving, about what a bare CUDA context takes. The order of magnitude is settled. The GB300's exact percentage still needs a run during a lane window.
E2: does one copy save several reads? This decides whether copy-on-miss can ever win over C2C. It's built and validated, but blocked on hardware, and the blocker turned out to be useful to know: the TRT-LLM MXFP4 MoE kernel has no sm_120 code at all (FlashInfer ships it for sm100, sm103 and sm107), so it can't run on the RTX PRO 6000. That's also why the sidecar lane uses a different FP4 kernel on that card. E2 runs on the GB300 in about a minute (after a one-time 20–30 minute kernel compile) the next time the lane is stopped for something else.
Reading FlashInfer's launcher sharpened the question. The kernel launches one thread block per 8 tokens per expert, so a busy expert can be loaded several times in one call. Whether those repeat loads go back over C2C or hit the GPU's ~126 MB L2 cache depends on how many cold bytes a layer touches: about 25 MiB at one user, which fits in L2, versus about 600 MiB at eight users, which doesn't. E2 measures exactly that crossover.
9. When prefetch becomes right
James's instinct isn't wrong. It's early for this model. Any one of these would reopen it:
- A bigger, colder model. If a successor still has ≥30% of picks landing on cold experts after a good usage map, Figure 3 says cold reads are 25–45% of a step, and prefetch becomes the main lever.
- A guesser that works here. The gate is a one-day offline test with no boot: capture hidden states and routing on real traffic, train the small pre-attention head per layer, and measure top-6 recall. Below 85% and the branch is dead for this model family.
- Upstream lands per-expert residency. If vLLM merges graph-safe per-expert copies, trying prefetch becomes a config flag, and the answer becomes "measure it".
The build order matters: pool first, prediction second. Once a device-side table and a graph-safe row copy exist, prefetch is a small change: issue the same copy one step earlier, gated on a guess. Built in the other order, you'd have a predictor with nothing to drive.
Next steps
- Run E1 and E2 on the GB300 in the next lane window.
- If E1 holds there: port #56177's table and copy code into the dynamic two-bank (6–8 days, 2 boots).
- Separately, and only if long-prompt first-token time is the product: #62060's prefill staging on a Grace-offload lane.
- Keep watching #56177, #57794/#57943, #62060 and KV-side prefetch (#58198).
Credits
- The authors of vLLM #56177, #57943/#57794, #62060, #51710, #37190, #41474 and #58198, and everyone in RFC #38256, including yasinyaman's routing-locality and SSD read-path measurements.
- Papers: pre-attention expert prediction, Pre-gated MoE, ProMoE, ExpertFlow, MoE-Infinity.
- FlashInfer and the TRT-LLM kernel team for the MXFP4 MoE kernel; DeepSeek for the model.