Related: #142 (system-frontier write candidate). This is a later capacity idea, not a substitute for that serve-layer fix.
What we are asking
Would you consider, after the current Device + pinned-Host catalog is settled, a cold NVMe tier under the same planner — not a second cache product.
Today the degradation graph is already monotonic:
Device replica → pinned Host State/KV → drop checkpoint → evict owner
A natural extra step is:
Device (hot) → pinned DDR5 Host (warm, --host-kv-mib) → NVMe (cold) → evict
vLLM/LMCache, TensorRT-LLM host offload, and NVIDIA ICMSP all use this shape for parked context. NInfer is stricter (exact frontier + full StateImage + GDN recurrent bundle), so a disk tier only makes sense if it stores the same checkpoint object the Host extent store already knows, not raw KV pages alone.
What it would help, and what it would not
Measured on this box (RTX 5090 32 GiB, WSL2 64 GiB DDR5, C=2, INT8, Qwen3.8-27B NVFP4):
| already true today |
SSD/DDR5 would not change |
| Live decode stays on Device |
Tokens/s of an active lane |
--max-concurrency 2 is the GPU lane cap |
Two 150k chats decoding at once (KV pool is still one 245k Device pool) |
Same-turn private_turn_closure is already ~90–125 ms |
First-token of a hot continuation |
| gap |
why a cold tier might help |
| Returning to a parked 80–120k agent chat after other sessions filled Device+Host |
Avoid 20–50 s root re-prefill. Fork #73 already showed 118k Device miss → host restore 422 ms vs 53 s. NVMe would be slower than pinned DDR, but still far cheaper than prefill if sequential restore is ~1–3 s for a few GiB. |
| More retained session count at C=2 |
C=2 only has 2 active + a handful of Device/Host checkpoints. Extra cold slots raise the chance the next Hermes/OpenCode window is a restore instead of root. That is reuse probability, not live batch width. |
| Shared system prefix once #142 exists |
One published 8–30k shared_stable_prefix could sit in Host or NVMe and seed many siblings without occupying Device KV. |
So: more parked conversations survive, not higher simultaneous decode concurrency. Worth saying explicitly so this is not read as “SSD makes C=8 on 32 GiB”.
Constraints that match current contracts
From docs/serving.md and resource-scheduling-and-context-cache.md:
- A reusable checkpoint is KV and complete continuation state (Linear Attention image, MTP watermark, boundary hidden). Disk must round-trip that bundle or the restore is unsound (this is exactly the class of bug
#73 hit when only part of the slot was restored).
- Pressure already compares immediate transfer work vs later recovery / re-prefill. A disk target is another cost coefficient (
context-cost-transfer), not a new policy language.
- Reads stay exact-identity. No approximate / block-hash prefix cache.
- Live decode must never stream KV from NVMe. Cold tier is admission-time materialize-to-Device/Host, then run.
- Opt-in, default off:
--cold-kv-dir PATH --cold-kv-gib N. Empty path = current two-tier behavior.
- On WSL2, the directory must be Linux ext4 (
~/…), not /mnt/c NTFS.
Suggested shape (if you ever do it)
Keep one catalog. Add one placement:
| tier |
media |
role |
| Device |
GPU HBM |
active + hottest checkpoints |
| Host |
pinned DDR5 (--host-kv-mib) |
warm park, sub-second restore |
| Cold |
NVMe files / extent log |
overflow of Host, sequential dump/restore of sealed checkpoints |
Evict Host → Cold as a planner successor of “Device → Host-only”. Restore Cold → Device (or Host) as NeedsTransfer. If restore cost ≥ predicted prefill, skip and root (same degrade-instead-of-crash rule as #73 after the stale-plan fix).
Do not bolt on #73’s separate content-addressed store next to HostKVArena. Same axis, two LRUs.
Why we are filing this now
Single-user C=2 agent serving (Hermes / OpenCode / Pi) already wants more than 2–4 retained 100k histories. Pinned 16 GiB Host is the right warm tier; consumer NVMe is the only place left once that fills. Happy to prototype measurements on 5090 if a disk placement exists; not asking for it before #142.
No local numbers for NVMe restore yet — we only have Device/Host. This is a design vote, not a perf claim.
Related: #142 (system-frontier write candidate). This is a later capacity idea, not a substitute for that serve-layer fix.
What we are asking
Would you consider, after the current Device + pinned-Host catalog is settled, a cold NVMe tier under the same planner — not a second cache product.
Today the degradation graph is already monotonic:
Device replica → pinned Host State/KV → drop checkpoint → evict owner
A natural extra step is:
Device (hot) → pinned DDR5 Host (warm,
--host-kv-mib) → NVMe (cold) → evictvLLM/LMCache, TensorRT-LLM host offload, and NVIDIA ICMSP all use this shape for parked context. NInfer is stricter (exact frontier + full StateImage + GDN recurrent bundle), so a disk tier only makes sense if it stores the same checkpoint object the Host extent store already knows, not raw KV pages alone.
What it would help, and what it would not
Measured on this box (RTX 5090 32 GiB, WSL2 64 GiB DDR5, C=2, INT8, Qwen3.8-27B NVFP4):
--max-concurrency 2is the GPU lane capprivate_turn_closureis already ~90–125 msrootre-prefill. Fork#73already showed 118k Device miss → host restore 422 ms vs 53 s. NVMe would be slower than pinned DDR, but still far cheaper than prefill if sequential restore is ~1–3 s for a few GiB.root. That is reuse probability, not live batch width.shared_stable_prefixcould sit in Host or NVMe and seed many siblings without occupying Device KV.So: more parked conversations survive, not higher simultaneous decode concurrency. Worth saying explicitly so this is not read as “SSD makes C=8 on 32 GiB”.
Constraints that match current contracts
From
docs/serving.mdandresource-scheduling-and-context-cache.md:#73hit when only part of the slot was restored).context-cost-transfer), not a new policy language.--cold-kv-dir PATH --cold-kv-gib N. Empty path = current two-tier behavior.~/…), not/mnt/cNTFS.Suggested shape (if you ever do it)
Keep one catalog. Add one placement:
--host-kv-mib)Evict Host → Cold as a planner successor of “Device → Host-only”. Restore Cold → Device (or Host) as
NeedsTransfer. If restore cost ≥ predicted prefill, skip androot(same degrade-instead-of-crash rule as#73after the stale-plan fix).Do not bolt on
#73’s separate content-addressed store next toHostKVArena. Same axis, two LRUs.Why we are filing this now
Single-user C=2 agent serving (Hermes / OpenCode / Pi) already wants more than 2–4 retained 100k histories. Pinned 16 GiB Host is the right warm tier; consumer NVMe is the only place left once that fills. Happy to prototype measurements on 5090 if a disk placement exists; not asking for it before #142.
No local numbers for NVMe restore yet — we only have Device/Host. This is a design vote, not a perf claim.