Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 34 additions & 5 deletions docs/moe-streaming.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,17 +452,46 @@ Decode speed, Qwen3-Coder-30B-A3B Q4_K_M (48 layers x 128 experts = 6,144; `llam
| streamed, 1,536 slots (25%) | 8-10 |

Through `1bit serve` (a 128-token chat answer, three requests): 18.9, then 28.3 and 27.1 tok/s
at 4,608 slots; 7.1, 6.6 and 6.0 at 1,536. The answers match the resident model's.
at 4,608 slots; 7.1, 6.6 and 6.0 at 1,536. The answers match the resident model's. With the
prefetch moved off the decode path (below), 4,608 slots gives 17.1, then 38.9 and 39.0.

A model that fits in memory decodes fastest resident. Streaming is for the ones that don't:
at a quarter of the experts in memory, Coder-30B still decodes 8-10 tok/s.

### Where streamed decode spends its time

`ONEBIT_MOE_STATS=1` prints, at exit, the time spent in the remap op, the part of it spent
waiting for reads, and the time between one layer's remap and the next (the GPU's work plus
the round trip to the host). Coder-30B, `-n 64 -r 4`, per MoE layer (the numbers include the
cold first repetition):

| Slots, prefetch depth | Warm tok/s | In remap (waiting) | Between remaps | Demand misses |
|---|---|---|---|---|
| 6,144, off | 48-53 | 0.36 ms (0.36) | 0.37 ms | 4.8% (the cold fill) |
| 4,608, off | 42 | 0.41 (0.40) | 0.37 | 5.4% |
| 4,608, 1 | 43.5-43.8 | 0.34 (0.34) | 0.37 | 1.3% (+4.4% prefetched) |
| 4,608, 2 | 43.0-44.8 | 0.30 (0.30) | 0.38 | 1.1% |
| 1,536, off | 9.6-10.5 | 1.59 (1.58) | 0.59 | 22.9% |
| 1,536, 1 | 9.2-10.2 | 1.68 (1.67) | 0.61 | 7.0% (+18.7%) |

- **The round trip caps streamed decode.** 0.37 ms between remaps x 48 layers is 17.6 ms per
token, about 57 tok/s, against 12.5 ms (80 tok/s) resident. Each layer's routed ids go to the
host and its slot indices come back before the expert matmuls can run.
- **Prefetch now pays a little.** Its router scoring first ran inside the remap op, scalar, at
about 0.15 ms per layer: prefetch cost 4,608 slots a third of its speed (28 against 42
tok/s). A worker thread now scores the next `ONEBIT_MOE_PREFETCH` layers (default 1) off the
decode path.
- **At 1,536 slots the drive is the limit.** About 88 misses x 2.1 MB per token is 185 MB, and
at 10 tok/s that is about 2 GB/s through `O_DIRECT` on a drive shared with other tenants. More
reads in flight (`ONEBIT_MOE_IO` 4 to 32) didn't help, and prefetch trades demand misses for
wasted reads (80 against 61 GiB over the run). What helps here is reading fewer bytes: a
better hit rate (item 2 below) or smaller experts.

## Next

1. **Faster streamed decode.** Streaming runs in the inference path (below), but at 1,536
slots it decodes 8-10 tok/s where the experts' reads alone would allow more. The gate-ahead
prefetch slows it down there, so the reads need queueing further ahead (the replays above),
and 6,144 slots (of 6,144 experts) runs erratically on the shared box.
1. **Fewer host round trips.** The remap per layer caps streamed decode at about 57 tok/s on
Coder-30B ("Where streamed decode spends its time"). 6,144 slots (every expert) runs
erratically on the shared box.
2. **A smarter eviction policy.** Belady's bound is 5-16 points above the shared LRU at small
caches. Candidates: frequency with decay per layer, and hints from the router's scores.
3. **Flash-Next's gate-ahead prediction.** Its layers keep four 2560-wide residual streams
Expand Down
2 changes: 1 addition & 1 deletion docs/serve.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ as the router picks them. The rest of the model loads on Vulkan0 as usual.
1bit serve -m Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf --moe-slots 4608 --ctx-size 8192
```

Qwen3-Coder-30B has 6,144 experts; at 4,608 slots it decodes 27-28 tok/s warm, at 1,536 about
Qwen3-Coder-30B has 6,144 experts; at 4,608 slots it decodes 39 tok/s warm, at 1,536 about
6-7 (docs/moe-streaming.md, "Streaming in the inference path"). A model that fits in memory is
faster without it (79-91 tok/s resident). It works with the Vulkan pin's llama-server only, not
with `--prefill-device`.
Expand Down
2 changes: 1 addition & 1 deletion third_party/llama.cpp
Submodule llama.cpp updated 52 files
+0 −8 conversion/__init__.py
+1 −1 conversion/bert.py
+0 −10 conversion/cambrian.py
+1 −1 conversion/chatglm.py
+0 −46 conversion/codegen.py
+1 −1 conversion/command_r.py
+2 −2 conversion/deepseek.py
+1 −1 conversion/falcon.py
+4 −4 conversion/gemma.py
+1 −1 conversion/gpt2.py
+1 −1 conversion/gpt_oss.py
+0 −46 conversion/gptj.py
+0 −34 conversion/gptneo.py
+1 −1 conversion/gptneox.py
+2 −2 conversion/lfm2.py
+1 −1 conversion/llada.py
+1 −9 conversion/llama.py
+1 −1 conversion/mamba.py
+1 −1 conversion/mpt.py
+2 −2 conversion/olmo.py
+0 −39 conversion/opt.py
+3 −3 conversion/phi.py
+0 −38 conversion/pico.py
+5 −5 conversion/qwen.py
+1 −1 conversion/rwkv.py
+1 −1 conversion/stablelm.py
+2 −2 conversion/starcoder.py
+2 −2 conversion/t5.py
+3 −297 conversion/zaya.py
+1 −1 convert_hf_to_gguf.py
+5 −5 ggml/src/ggml-hrx/dispatch_registration/common/dispatch-flash-attention.cpp
+156 −4 ggml/src/ggml-hrx/kernel-corpus/kernels/loom-libs/ops/flash_attention_decode_split_f32_f16_wmma.loom
+1 −1 ggml/src/ggml-hrx/kernel-corpus/kernels/qwen_moe/qwen3_moe/router_projection_top8_fused_f32.loom
+0 −87 gguf-py/gguf/constants.py
+0 −3 gguf-py/gguf/gguf_writer.py
+0 −31 gguf-py/gguf/tensor_mapping.py
+0 −33 src/llama-arch.cpp
+0 −20 src/llama-arch.h
+1 −12 src/llama-model.cpp
+0 −15 src/llama-model.h
+0 −136 src/models/codegen.cpp
+0 −144 src/models/gptj.cpp
+0 −139 src/models/gptneo.cpp
+0 −57 src/models/models.h
+0 −139 src/models/opt.cpp
+33 −132 src/models/zaya.cpp
+1 −1 tests/test-llama-archs.cpp
+0 −1 tools/mtmd/clip-impl.h
+0 −1 tools/mtmd/clip-model.h
+0 −6 tools/mtmd/clip.cpp
+0 −3 tools/mtmd/clip.h
+1 −2 tools/mtmd/mtmd.cpp
Loading