Skip to content

Fix LMCache offload reload handoff#1026

Draft
yhl-amd wants to merge 11 commits into
ROCm:mainfrom
yhl-amd:feature/lmcache-offload-scheme-a
Draft

Fix LMCache offload reload handoff#1026
yhl-amd wants to merge 11 commits into
ROCm:mainfrom
yhl-amd:feature/lmcache-offload-scheme-a

Conversation

@yhl-amd
Copy link
Copy Markdown
Contributor

@yhl-amd yhl-amd commented Jun 2, 2026

Summary

  • apply Scheme A load decisions after block allocation so HBM-satisfied, unaligned, or too-small LMCache hits do not park for unsafe CPU reloads
  • add optional OFFLOAD_UNALIGNED_HANDOFF flow to prefill up to the next LMCache chunk boundary before issuing the CPU load
  • promote completed remote-KV waiters ahead of fresh admissions and drop stale deferred partial-prefill output after handoff
  • add connector and scheduler coverage for min-load skips, aligned loads, unaligned handoff, waiter promotion, and deferred-output cleanup

Validation

  • git diff --check
  • python3 -m pytest tests/test_lmcache_offload_connector.py tests/test_scheduler.py (49 passed, 11 skipped)

Notes

  • Draft PR while benchmark notes and review cleanup are still in progress.

yhl-amd and others added 11 commits May 31, 2026 22:22
…WIP)

New atom/kv_transfer/offload/ package: a standalone (non-vLLM) KV offload
connector that reuses LMCache as a storage tier (CPU LRU + NVMe L3) via
StorageManager + ChunkedTokenDatabase, with an opaque per-block byte codec
(ATOMKVByteCodec) that bypasses engine.store/retrieve to preserve AITER's
swizzled KV layout. Load/save run daemon-after-forward off the RPC thread;
cross-process hit lookup via LMCache's ZMQ LookupClient/LookupServer.

Engine hooks:
- disaggregation/factory.py: register the "lmcache_offload" connector.
- model_engine/scheduler.py: offload-wake branch (a parked
  WAITING_FOR_REMOTE_KVS seq resumes as a suffix prefill, not the P/D
  decode-jump) + offload_resume guard against re-allocate-on-populated-blocks.

TP=2 fixes (offload was non-functional at TP>1):
- config.py: lookup_server_worker_ids=[0]. The cross-rank ZMQ lookup took
  min() across ranks and rank!=0 returned 0 despite having stored the chunk
  (contains()=True) -> min(0,hit)=0 -> the load never fired. Only rank 0
  answers lookup now (both ranks save in lockstep, so rank 0 is authoritative).
- connector.py: split load/save into separate executors so a latency-critical
  reload never queues behind the fire-and-forget save backlog.

Verified end-to-end at TP=2 (MiniMax-M2.5 FP8, 2x MI325X): an evicted 32K
prompt reloads 32000 tokens from CPU and recomputes only the 5-token suffix
(Scheduled prefill cached:[32000], new:[5]); was a full recompute before.

Known issues (WIP):
- Reload latency high (~131s in the micro-bench): the per-block Python copy
  path is slow (~88ms/chunk) and the load waits on the storage_manager lock
  held by a save burst. Needs a bulk/batched copy rewrite of ATOMKVByteCodec.
  See ../OFFLOAD_TP2_FIXES.md and ../PHASE4_RESULTS.md.
- Verbose [OFFLOAD-*] diagnostic logging + an engine.lookup monkeypatch are
  still present and must be removed/demoted before benchmark/production use.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply Scheme A load semantics after allocation: skip small or unsafe CPU reloads, hand off unaligned HBM floors by prefill-to-boundary when enabled, and promote completed remote-KV waiters before fresh admissions.

Add scheduler and connector tests for aligned reloads, unaligned handoff, min-load skips, and deferred-output cleanup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant