Prefill / decode through storage
A durable KV handoff needs more than a successful read: publication, reader ownership, exact continuation and a safe acknowledgement boundary.
Produce reusable KV state
The producer computes the prompt, stores its KV and returns the first output token. Storage publication is a separate barrier.
Use storage as the handoff
A decoder reads an advertised storage generation. This is different from copying KV directly over NVLink, RDMA or TCP.
Continue the same request
The decoder receives the producer's first token, validates/restores the promised prefix and releases its extent lease only after completion.
The handoff is an ownership protocol
Fence GPU gather
Flush + checkpoint barrier
Validate manifest + layout
Fence GPU consumption
Permit extent reuse
A prefill HTTP response alone does not prove storage is ready. A successful decoder response alone does not prove restoration: an ordinary cache miss may silently recompute. Native completions, cold-reader evidence, exact continuation and a deliberately failed-load control are required.
A failed or uncertain claimed read retains its lease. Lease expiry, client cancellation and a waiting-thread timeout do not prove that a device or reader stopped. Unclaimed publications have a distinct exact unread-release operation.
Why put the storage support in LMCache?
| Layer | Responsibility | Why it stays there |
|---|---|---|
| vLLM | Schedule prefill/decode, own engine KV blocks, expose connector lifecycle and report failed restores. | The engine must decide which tokens are computed and whether a request can continue. |
| LMCache | Key/layout identity, cache tiers, allocator and serde ownership, storage registration, publication, checkpoint adoption and extent leases. | The cache owner knows when storage bytes are durable and reusable. Offload and P/D reuse the same storage implementation. |
| NIXL, when selected | Move registered byte ranges through a selected transport/backend. | A byte-transfer library need not own model token keys or LMCache's eviction policy. |
| Dispatcher | Route requests, pass the first token and receipts, order MP controls and ACK completed handoffs. | The current MP API is callable plumbing; no automatic storage-P/D router is supplied. |
This is a division of responsibility, not a claim that vLLM should have no P/D support. LMCache integrates through vLLM's connector interface. The separate NIXL storage connector legitimately lives in vLLM because it supplies a direct NIXL path without LMCache. Its GPU qualification remains separate.
See vLLM's connector architecture and LMCache's P/D documentation . The latter legacy page redirects readers toward MP deployment; do not assume the two integration modes have identical controls.
Two LMCache integration modes
In-process storage P/D
The experimental
enable_pd=true
,
pd_data_path=raw_block
path extends LMCache's in-process P/D control, publication tracker, proxy and
LMCacheConnectorV1
integration. It is independently qualified in a pinned local CUDA/XFS profile. That configuration is not the MP launcher.
Multiprocess shared-storage controls
Independent MP writer and read-only reader servers open the same initialized target, geometry and namespace derivation. The HTTP API supplies prepare, publish, claim, adopt, ACK, cancel and unread release. A dispatcher calls them around prefill/decode. Use
LMCacheMPConnector
; full attention, group zero and TP=PP=1 are the initial token-addressed profile.
1. writer POST /storage-pd/prepare # before model stores
2. run prefill; retain the first output token
3. writer POST /storage-pd/publish # receive completed READY receipt
4. writer POST /storage-pd/claim # exact reader/session identity
5. reader POST /storage-pd/adopt # namespace, epoch, manifest, layout
6. run decode with producer token appended
7. writer POST /storage-pd/ack # after successful restore/consumption
Both servers configure
pd_derivation
from the actual
TokenHasher(chunk_size, "blake3")
. Equal tensor byte counts are insufficient: shape, dtype and logical size must match. Failed restoration must not ACK the original lease.
For a strict MP consumer, set
lmcache.mp.strict_prefix=true
,
kv_role=kv_consumer
and
kv_load_failure_policy=fail
. The fail policy alone is insufficient when prefetch fails before an external prefix is advertised. Strict mode requires all complete prompt chunks before the last prompt token and routes a miss through vLLM's real load-error path.
Move from a working NIXL deployment in stages
-
Preserve the current connector, backend and model-output baseline. Distinguish stock
NixlConnectornetwork P/D from LMCache using NIXL and from the separate experimental NIXL storage connector. - Choose which ownership layer you want. Existing NIXL applications can evaluate the new IO_URING plugin; LMCache applications can evaluate its direct backend. Neither choice requires deleting the existing baseline.
- Use a private initialized scratch target and staged host I/O first. Verify independent payload readback and checkpoint/manifest identity; do not share LMCache/NIXL metadata formats.
- Add classic registration, then DMA-BUF with a qualified kernel/exporter. A GPU payload route must demonstrate native DMA-BUF operations without a hidden host fallback.
- Run a no-cache model oracle, monolithic/split controls, fresh cold restoration, exact continuation and chosen-token likelihood checks with identical inputs and decode settings.
- Inject failed reads or corrupt owned test data and require strict rejection. Test mismatched receipts, duplicate ACK, unread release, pressure and cancellation before considering rollout.
- Qualify the actual deployment topology. Same-GPU success is useful contract evidence; it is not two-GPU, cross-host shared-NVMe or crash-recovery qualification.
For compatible native NIXL users, the parameter sequence is host → fixed → DMA-BUF. For LMCache users, changing
transfer_channel
alone does not supply the MP dispatcher or convert a network transfer into durable publication.
Did we test NIXL P/D?
Yes. Native IO_URING now passes a same-GPU host-staged P/D profile with the CUDA staging fix below. Historical two-GPU results remain separate. Results must follow the exact backend and connector revisions below.
| Source / profile | What ran | What it establishes |
|---|---|---|
Historical XNVME_NVM
7761470b
+ vLLM
8bca084d4b
; September 28
|
Two GPUs, host-staged and CUDA DMA-BUF. Per mode: 3 sequential fresh-reader, 3 concurrent 1P1D and 13 chunked/pressure comparisons matched token IDs after the partial-restore fix. | Historical two-GPU P/D evidence. Native source identity is reconstructed from deployed file hashes; that deployed NIXL tree lacked Git metadata. The pressure arm reuses resident prefix blocks and restores tails, so it is not 13 fully cold restores. |
Native IO_URING
1604a0c3
+ vLLM CUDA staging follow-up
2697fd5ead
|
Ordinary host, fixed host and host DMA-BUF staging: 19 exact model continuations per mode, comprising 3 fresh-reader, 3 concurrent-engine and 13 chunked/concurrency cases. Native payload/copy ordering and publication/ACK ledgers were independently checked. | One RTX 4090, two engines, initialized XFS file, BF16 and VLLM_BATCH_INVARIANT=1. This is host staging, not a GPU DMA-BUF exporter or independent-GPU result. Adapter suites pass 52 cases with four named device gates. The original be9c66a5 tip lacks the staging fix. |
LMCache MP; recorded published-source tests
10a941b54
|
CUDA GPU direct on XFS/ext4, CUDA staged and HIP staged: 52 continuations; 108 × 8 MiB reads; 9 evictions per arm; cold L1; overlapping work. Strict corruption controls reject with no tokens, then the same engines restore a valid handoff. | Local same-GPU shared-file contracts on the published Python source, with verified reuse of unchanged native builds. All 32 MP GPU matrix profiles also pass independent value, native-path and terminal-ownership checks. |
The native NIXL qualification uses the vLLM validation follow-up with the matching native NIXL branch. This qualification uses Llama-3.2-1B-Instruct, seed 1234, greedy output budgets 48/32/24 for the three case groups and concurrency 1/4/8 in the pressure group. All 57 continuations match; the staging correction and its regression are described below.
Final LMCache model profile: Llama-3.2-1B-Instruct
9213176726f574b556790deb65791e0c5aa438b6
, BF16, eager, seed 123, batches 1/4/8; five-token copy continuation. The 52 token sequences match; maximum chosen-token logprob delta is 0.004954 at the unchanged 0.02 tolerance. An earlier staged recall case failed at 0.026329; its cause remains unresolved. This is not a broad model-quality result.
These LMCache measurements were recorded on 15 October 2026 (PDT) using the published candidate. A separate deterministic in-process profile passes 27 cases each for its no-cache oracle, cold restore and warm repeat, along with stop handling, cancellation, receipt and causal timeline checks at the unchanged 0.02 bound. The earlier no-cache repeatability failure without batch invariance remains recorded. CPU guest tests separately cover host exporters on emulated NVMe with ext4, XFS and raw targets; they do not qualify GPU raw-device I/O or SSD performance.
Corrections found during validation
LMCache receiver close · b8845f7c
Repeated backend close submitted cleanup to a stopped receiver event loop, causing a timeout and an unawaited-coroutine warning. Skip that submission after the loop stops; the first close still drains a running loop.
Verification: The public-API regression fails on the base and passes with the fix. All 33 asynchronous backend tests pass. Concurrent close and RDMA hardware behavior are outside this regression's scope.
vLLM / NIXL staging · 2697fd5ead
CUDA copies crossing separately registered host chunks failed with
cudaErrorInvalidValue.
Register the contiguous host arena once with CUDA and release that registration at close. NIXL storage registrations and DMA-BUF boundaries remain unchanged.
Verification: The real CUDA round-trip regression fails on the base and passes for host and udmabuf staging after the fix. Adapter suites pass 52 cases with four explicit hardware gates. The three model modes above pass 57 exact continuations in total.
Both changes passed their configured source checks and review. The LMCache model and 32-profile MP measurements above use the published feature tip
10a941b54;
the close correction is separately regression-tested. The native NIXL model replays use the corrected vLLM tip
2697fd5ead.
Initial failures remain retained, and the original full and cumulative feature refs are unchanged.
Open work before a broader deployment claim
The latest MP profile is one writer, one reader, compatible BF16 full-attention layout and TP=PP=1. Automatic routing, independent multiwriter ownership, writer restart with live old readers, crash-safe leases, cross-host shared NVMe, GPU-direct raw-device qualification and performance are open. The AMD result is staged. Lossy FP8 model quality is not qualified by encoded-buffer ownership tests.
Storage removes a mandatory direct GPU-to-GPU KV transfer; it does not eliminate control messages or make arbitrary local disks a shared namespace. A network storage topology needs its own capability, visibility and durability proof.
Failure cleanup is case-specific. The missing-key rejection after a claim deliberately retains one writer extent rather than risk reusing bytes a consumer may still access. That control passes its fail-closed retention contract; it is not a normal zero-ownership result or automatic crash recovery.
Make targets for storage P/D
The current test profile pins the public LMCache and vLLM candidates. It exposes CPU contracts separately from GPU transport and model-serving evidence. P/D means prefill/decode; MP means multiprocess.
make defconfig-pd-storage
make pd-test-plan
make dmabuf-fetch
# Prepare each pinned application and its test environment first.
make pd-lmcache-test PYTHON=/path/to/lmcache-venv/bin/python
make pd-mp-test PYTHON=/path/to/lmcache-venv/bin/python
make pd-vllm-test PYTHON=/path/to/vllm-venv/bin/python
Publication and restoration
Check generation/manifest identity, publication barriers, acknowledgement (ACK), extent lifetime, restore coverage, launcher admission and causal-trace rules.
Independent storage owners
Run shared-file publication, adoption and exact ACK controls through the real storage adapter and HTTP API. No GPU or experimental kernel is required.
Connector contracts
Check the coordinator, descriptor planning and pack/scatter behavior. Transfer doubles replace NIXL I/O here; hardware cases are explicitly deselected.
pd-cpu-test
runs all three selections in order if one environment can import both pinned projects. Unexpected skips fail the target. Use separate targets and environments otherwise. The older
pd-run
runner remains a basic CPU/file smoke test; it does not implement the full acceptance ladder.
# Check an existing single-host in-process serving receipt:
make pd-timeline-check PD_TIMELINE=/path/to/serving.jsonl
# For a trace that actually used host fixed buffers:
make pd-timeline-check PD_TIMELINE=/path/to/serving.jsonl \
PD_REQUIRED_PATH=host_fixed
The timeline target defaults to requiring
dmabuf_fixed
payload provenance. It checks an existing in-process causal receipt; it does not launch models, check model quality or validate MP HTTP/cross-host traces. Full writer/reader serving, recompute-oracle, failed-load and pressure runs remain separate procedures. See the
kernel and hardware test targets
and
tools/reproduce/dmabuf/README.md
for setup, dependencies and limits. No CPU-only result establishes GPU P/D.
Reviewable source
- LMCache full dated stack: 50 commits · MP configuration and HTTP contract
- NIXL native IO_URING backend: 2 commits · Backend parameters and limits
- vLLM NIXL storage connector: 3 commits
-
Experimental kernel branch
, pin
856b6583ab2f4581e81670845eadb69de7a68b30
Follow-up branches include their full feature stacks: LMCache b8845f7c, NIXL 711dcb4d and vLLM 2697fd5ead. NIXL's follow-up adds a GCC15 test-header fix and documents initialized read extents and locked-memory requirements; its production transfer code is unchanged.
Source branches are public snapshots and retain their pinned bases. These guides describe experimental support; no universal compatibility with current upstream versions is claimed.