Repository navigation
[DCP] [HiCache] Support role-local DCP storage in prefill/decode serving - #41695
Draft
Venkat2811 wants to merge 26 commits into
Draft
Venkat2811 wants to merge 26 commits into
Venkat2811 wants to merge 26 commits into
Conversation
This was referenced Sep 29, 2026
Venkat2811
marked this pull request as ready for review
September 29, 2026 16:59
Venkat2811
requested review from
ByronHsu,
Duyi-Wang,
HaiShaw,
JustinTong0323,
ShangmingCai,
Ying1123,
alphabetc1,
hanming-lu,
hnyls2002,
huangtingwei9988,
hzh0425,
ispobock,
merrymercy,
sogalin,
stmatengss,
wisclmy0611,
xiezhq-hermann,
yizhang2077 and
zijiexia
as code owners
September 29, 2026 16:59
This was referenced Sep 30, 2026
Read shared KV through a registered MLA replica before applying state eviction pressure. The existing survival check fails when touch loses its namespace guard: the replica deletes the shared KV file, causing avoidable cache misses rather than wrong data. Clarify namespace ownership in reserve and document that topology changes can leave old state files outside eviction accounting.
Select complete logical pages when some objects already exist. Preserve upstream worker exception recovery and limit native shard validation to DCP. Share the fresh-process file restore fixture and update host-pool fixtures for current constructors.
…agreement Keep sparse endpoint intersection in the existing prefetch collective and preserve deferred per-pool beliefs. Drop the obsolete chunked write-through implementation and its claim from this stage.
…nt state Reuse upstream Mamba admission with reserved checkpoint slots, decline unregistered prefetch hits before advertising them, and keep incoming recurrent state separate from cache restoration. Require wait-complete prefetch and reject unqualified decode offload for DCP L3.
Use upstream restore locks for pending capacity and GPU assertions. Drop the obsolete pre-gate failure test already covered by upstream gated receiver tests.
Pass the selected policy through both controller layers instead of rechecking the startup default. Exercise real controller validation in the attach regression; timeout-to-wait_complete and retained-policy reattach fail before this change.
Venkat2811
force-pushed
the
venkat/dcp-hicache-l3-3-pd
branch
from
October 16, 2026 00:10
12efa25 to
ed85005
Compare
Venkat2811
added a commit
to datacrunch-research/sglang
that referenced
this pull request
Oct 19, 2026
… headroom // ranks (upstream sgl-project#38157) Squash of the kimi-k3-v0.5.22 integration PR #14 (layer 0). The kimi-k3 v0.5.22 prefill/decode line: v0.5.22 plus this one layer. It is 331f644 (the v0.5.21 kimi-k3 line's layer 5b, fork PR #13) rebased onto v0.5.22, with the two conflicts against v0.5.22's pool_host changes resolved. host_memory_budget_bytes() outside a budget scope returns free // ranks_per_host(), where free is the host headroom left when the rank asks. On an 8-GPU pod the ranks arrive at different times, so a rank that checks after its peers have pinned their pools divides a smaller headroom by 8 again and is refused although every pool fits (seen 2026-10-01 on Kimi-K3: "Requesting 24.77 GB but only have 22.74 GB free"). v0.5.22 still does this with an explicit --hicache-size (hicache_auto_size.py opens no budget scope; pool_host/base.py and pool_host/mamba.py check against free // ranks_per_host()). The guard now checks a pool against the whole remaining headroom; the two callers that size a pool (HiCache auto-sizing, the unified page-envelope pool when --hicache-size and --hicache-ratio are 0) keep this rank's share through host_memory_budget_bytes_per_rank(). The unit tests that pinned the split are updated. Not carried from the v0.5.21 line, for the prefill/decode copy (prefill at DCP 1 with HiCache and Mooncake L3, decode without HiCache): sgl-project#41692 to sgl-project#41695 (file L3 and DCP > 1 L3 only) and sgl-project#42039 (in v0.5.22 as sgl-project#42420 and sgl-project#42788). The aggregated copy (Mooncake L3 at DCP 8) stays on verda/kimi-k3-2026-10-03. Validated on HGX B300 with Kimi-K3 (19 Oct 2026, v0.5.22 image + this layer as a Python overlay): same-time A/B against the v0.5.21 line on a 1 prefill + 2 decode copy (weka median 24 twice, AgentX 48), and a 2 prefill + 2 decode copy (AgentX 56 twice, 64): level or better, no cross-request leaks, no broken answers. Upstream: sgl-project#38157 Issue: sgl-project#38156 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Venkat2811
added a commit
to datacrunch-research/sglang
that referenced
this pull request
Oct 19, 2026
…ing (upstream sgl-project#41695) Squash of the kimi-k3-v0.5.22 integration PR #19 (layer 5), a mirror of the upstream pull request, rebased onto v0.5.22 (baa9bef). Upstream: sgl-project#41695 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Venkat2811
added a commit
to datacrunch-research/sglang
that referenced
this pull request
Oct 27, 2026
…e slots (upstream sgl-project#41695) Layer 12 of the Kimi-K3 nightly line on upstream main 5884e4f. The prefill/decode part of upstream sgl-project#41695 that 5884e4f does not have. A decode server with --disaggregation-decode-enable-radix-cache and HiCache restores the cached prefix locally while prefill sends the rest: - The transfer-side load-back handed the request to init_load_back, so for a hybrid (Mamba/KDA) model it also copied the host checkpoint at the prefix end into the request's own state slot. That slot receives the live state prefill computes for the whole prompt; whichever copy lands last wins. InitLoadBackParams.restore_request_state=False restores the canonical cache slot only. - A hybrid restore needs one canonical state slot besides the request's live slot. Admission keeps a slot free for each queued restore (ensure_mamba_capacity(..., reserved_slots=)) and promises prefill only the device-resident prefix when no slot can be reclaimed; before, the promise went out and the restore failed after prefill had skipped those tokens. - Under DCP, a decode server with an L3 backend requires --hicache-storage-prefetch-policy wait_complete (decode promises the probed L3 span before the read completes) and refuses --disaggregation-decode-enable-offload-kvcache, as sgl-project#41695 did. Checked at startup (resolve_hicache_dcp_compatibility) and on runtime attach, including the same-backend policy update (StorageAttachment.attach; HiCacheController.attach_storage_backend never sees the effective policy). Source: 91ecb13 on the kimi-k3-nightly-3c560089 line, which equals upstream sgl-project#41695's own commits over sgl-project#41694 (head ed85005). Dropped because 5884e4f has it: starting the L3 prefetch before preallocation and promising only the span it took (sgl-project#43548). The sgl-project#41693/sgl-project#41694 ports that 91ecb13 sat on are superseded by sgl-project#41187 (no P/D refusal, no decode-offload case), so the guards are re-expressed on upstream's structure and the tests are rewritten on 5884e4f's fixtures. No change for a decode server without the decode radix cache, which is every K3 recipe today. Tests (CPU), this commit's test files on the parent: test_server_args.py TestHiCacheArgs::test_dcp_decode_storage_requires_wait_complete_without_offload 3 subtests fail (NotImplementedError not raised for timeout, best_effort and decode offload); test_hicache_dcp_host_pool.py TestDcpDecodeStorageAttach 6 subtests fail (attach accepted an early-stopping policy, attached or not); test_mamba_capacity.py test_pd_restore_promise_keeps_a_canonical_state_slot 2 subtests fail (full and pending_restore promised 6 tokens, not 2). With this commit all pass. Tests (GPU, one B300): test_unified_radix_cache_load_back.py Test_FULL_MAMBA_ps1::test_pd_decode_restore_keeps_the_live_request_state fails on the parent (the live slot ends with the checkpoint's marker 11, not the live 37) and passes with this commit. Fork PR (v0.5.22 line): #19 Upstream: sgl-project#41695 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Venkat2811
added a commit
to datacrunch-research/sglang
that referenced
this pull request
Oct 27, 2026
…e slots (upstream sgl-project#41695) Layer 12 of the Kimi-K3 nightly line on upstream main 5884e4f. The prefill/decode part of upstream sgl-project#41695 that 5884e4f does not have. A decode server with --disaggregation-decode-enable-radix-cache and HiCache restores the cached prefix locally while prefill sends the rest: - The transfer-side load-back handed the request to init_load_back, so for a hybrid (Mamba/KDA) model it also copied the host checkpoint at the prefix end into the request's own state slot. That slot receives the live state prefill computes for the whole prompt; whichever copy lands last wins. InitLoadBackParams.restore_request_state=False restores the canonical cache slot only. - A hybrid restore needs one canonical state slot besides the request's live slot. Admission keeps a slot free for each queued restore (ensure_mamba_capacity(..., reserved_slots=)) and promises prefill only the device-resident prefix when no slot can be reclaimed; before, the promise went out and the restore failed after prefill had skipped those tokens. - Under DCP, a decode server with an L3 backend requires --hicache-storage-prefetch-policy wait_complete (decode promises the probed L3 span before the read completes) and refuses --disaggregation-decode-enable-offload-kvcache, as sgl-project#41695 did. Checked at startup (resolve_hicache_dcp_compatibility) and on runtime attach, including the same-backend policy update (StorageAttachment.attach; HiCacheController.attach_storage_backend never sees the effective policy). Source: 91ecb13 on the kimi-k3-nightly-3c560089 line, which equals upstream sgl-project#41695's own commits over sgl-project#41694 (head ed85005). Dropped because 5884e4f has it: starting the L3 prefetch before preallocation and promising only the span it took (sgl-project#43548). The sgl-project#41693/sgl-project#41694 ports that 91ecb13 sat on are superseded by sgl-project#41187 (no P/D refusal, no decode-offload case), so the guards are re-expressed on upstream's structure and the tests are rewritten on 5884e4f's fixtures. No change for a decode server without the decode radix cache, which is every K3 recipe today. Tests (CPU), this commit's test files on the parent: test_server_args.py TestHiCacheArgs::test_dcp_decode_storage_requires_wait_complete_without_offload 3 subtests fail (NotImplementedError not raised for timeout, best_effort and decode offload); test_hicache_dcp_host_pool.py TestDcpDecodeStorageAttach 6 subtests fail (attach accepted an early-stopping policy, attached or not); test_mamba_capacity.py test_pd_restore_promise_keeps_a_canonical_state_slot 2 subtests fail (full and pending_restore promised 6 tokens, not 2). With this commit all pass. Tests (GPU, one B300): test_unified_radix_cache_load_back.py Test_FULL_MAMBA_ps1::test_pd_decode_restore_keeps_the_live_request_state fails on the parent (the live slot ends with the checkpoint's marker 11, not the live 37) and passes with this commit. Fork PR (v0.5.22 line): #19 Upstream: sgl-project#41695 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Venkat2811
added a commit
to datacrunch-research/sglang
that referenced
this pull request
Oct 30, 2026
…attach check sgl-project#42973 made StorageAttachment ask page_interleave_shard_size() about cache.token_to_kv_pool_allocator before attaching a storage backend. The role-local DCP attach tests (ported with sgl-project#41695) build their cache as a SimpleNamespace without that attribute, so 14 of them stopped at an AttributeError. Give the fake a plain namespace there: a stock allocator, shard size 1, which is what those tests mean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Stack 4/4. Depends on #41694. Targets
main, so the full diff is cumulative. Incremental diff. Refreshed onto4cca7fcd3eon 16 October; remains draft. The reviewed recurrent-file dependency was replayed locally; #41692 itself was not changed.Motivation
Decode must honor the prefix it promised to prefill without replacing the live recurrent state received through P-to-D transfer. Enable role-local DCP L3 reuse while preserving that contract.
This work grew out of experiments with Kimi-K3 prefill/decode serving configurations.
Modifications
wait_completeon DCP decode and reject decode KV offload with DCP storage. Runtime attachment forwards the selected policy through both controller layers.Live-state preservation and admission fixes also affect DCP1. Roles can have different layouts, but each reads compatible role-local objects. Persisted cross-layout conversion is unsupported. Losing promised data fails the request safely; it does not turn an incomplete restore into a hit. Broader timeout/liveness redesigns are outside this PR.
Accuracy Tests
Before = hybrid stage
39e4d07b34, which rejects DCP P/D storage. Final stage =ed850058f8. Kimi-Linear uses TP4/DCP1 prefill and TP4/DCP4 decode on one eight-GPU B300 node, with live RDMA transfer and separate role-local namespaces.File P/D ran before the final attach-policy fix; that fix changes runtime attachment, not its startup configuration. Mooncake P/D uses the final runtime code. Compared output IDs match the relevant control. The largest concurrent/retry logprob delta is 0.01291 (threshold 0.2); fresh-reader deltas against the matching warm control are zero. A fresh process can acquire a 64-token shared device prefix during successive requests, so P/D cache counters are not represented as universally zero L1.
25 CPU files plus two scheduler-attach tests pass with CUDA hidden. Four Python/Rust GPU restore tests pass, including preserving live state. Reservation and effective-policy regressions have failing-before/passing-after evidence. Pre-commit and docs checks pass. Hosted CI, B200, Kimi-K3, cross-node P/D, speculative L3 and live P/D SSD pressure were not rerun.
Run the committed regression tests
Use an x86 NVIDIA host. The GPU results below were obtained on B300, with driver 580.178.04. This container pins the tested dependency image. These are portable equivalents of the commands run in a Kubernetes pod, not a claim that this Docker wrapper was itself executed. Model tests download pinned public snapshots; allow approximately 100 GB for Kimi-Linear weights.
CUDA_VISIBLE_DEVICES=999 python test/registered/unit/disaggregation/test_decode_queue_cleanup.py CUDA_VISIBLE_DEVICES=999 python test/registered/unit/mem_cache/test_mamba_capacity.py CUDA_VISIBLE_DEVICES=999 python test/registered/unit/mem_cache/test_hicache_dcp_storage_guards.py CUDA_VISIBLE_DEVICES=999 python test/registered/unit/managers/test_scheduler_hicache_attach.py # Actual H2D state copies, both tree cores, cancellation and live-state checks. CUDA_VISIBLE_DEVICES=0 python test/registered/unit/mem_cache/test_hybrid_l3_restore.pyThe live P/D campaign was a separate local integration harness, not a registered test in this diff. It used page size 64, BF16 weights, FP8 KV, context 4096, chunked prefill 1024,
tokenspeed_mla, Triton linear decode, 10 GB HiCache,page_first,write_through, eager prefill and decode radix caching. The roles use separate file directories or Mooncakeextra_backend_tagvalues. Decode needs--hicache-storage-prefetch-policy wait_complete. A working RDMA setup is required; the local run used DMA-BUF and explicit IB devices. The commands above validate the committed contracts, not that full live deployment or its fault injection.