feat: prefix KV reuse - #181
Conversation
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
|
Momus plan review: [OKAY] on the first review round. |
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Migrate BatchMetadata and runtime AttentionMetadata to the canonical PagedBatchLengths (query/query_offsets/context/kv) contract; qo_indptr uses query lengths while KV pages use total; record last_flashinfer_plan; update all consumers. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add block refcounts (retain/release/ref_count), validated layered store binding, layer-complete copy-on-write for shared partial tails, and checkpoint/restore-based swap. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add SequenceAllocationPlan/GroupAllocationReceipt with prepare/commit/abort group protocol, pin-before-evict scheduler admission, lease-aware prefix eviction, and committed-KV/has_prefix_lease sequence state. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Advance committed_kv_tokens only after successful forward, publish newly complete prompt blocks by committed range, and exclude reused-prefix/non-cold requests from DFlash delegation. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Gate prefix reuse behind capability + enable flag; bind validated layered store before scheduler construction; expose prefix_cache lifecycle stats; add --prefix-cache-max-entries and reload invalidation. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add opt-in MOE_PREFIX_CACHE_CUDA parity + active-reference eviction tests that verify real cold/warm FlashInfer geometry and exact refcount transitions on a supported Qwen3 runner. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add disabled/cold/warm prefix-cache benchmark with digest-mismatch abort and dry-run schema test; re-export FlashInferPlanMetadata; document scope, invariants, metrics, and rollback across serving/benchmarking/README/ARCHITECTURE/CHANGELOG. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
|
Independent implementation verification:
PR remains draft for real Qwen3/FlashInfer qualification. |
|
Productization findings (full report: The reported native segfault was the multi-model
Remaining correctness concern: with reuse active ( |
…ging Other tests purge moe_infinity.runtime from sys.modules at import time, which re-registers a duplicate flashinfer_utils. importlib.reload on the module-level binding then failed with 'module ... not in sys.modules'. Re-fetch the current module via importlib.import_module before reloading.
* fix(serving): prefix-cache binding, hit stats, FlashInfer dtype, sm120 eager - kv_cache.set_block_store: normalize cuda device index so 'cuda' vs 'cuda:0' geometry no longer rejects the store (prefix cache now binds/activates) - prefix_cache/engine: surface prefix_cache_hits_total + matched_tokens_total - attention_backend: pass q_data_type/kv_data_type to FlashInfer plans - big_modeling: use eager attention for qwen3 when flash-attn unusable (sm120) - prefix_cache_benchmark: one model per subprocess (avoids multi-model crash) - engine: include bind exception detail in disabled reason * test(prefix): kernel-parity evidence + runnable subprocess parity harness - benchmarks/prefix_cache_benchmark: add --parity-report (per-mode tensor dumps + numerical analysis instead of digest-only failure), and --device-memory-ratio/--kv-cache-ratio so the suite fits shared GPUs. - tests/integration/test_flashinfer_kernel_parity: prove full-prefill and append kernel schedules are each deterministic, within ULP-scale error of an fp32 reference, and mask partial-page tails (3/3 pass on sm120). Cross-kernel bitwise equality is not an invariant. - tests/serving/test_prefix_cache_cuda: run warm-vs-cold parity through one-engine-per-subprocess (kTopologyHandle-safe) with correct invariants: disabled==cold bitwise control, geometry-proven reuse, tolerance + near-tie-aware token comparison. * test(prefix): tolerate near-tie swaps, require shared top-2 at any flip Warm-vs-cold token equality is unattainable: the paths use different FlashInfer kernel schedules (ULP-level per-op deltas) and expert-output accumulation order is nondeterministic, so near-tie argmax swaps occur even between same-mode reruns. Keep disabled==cold bitwise as the strict store-path regression check; at a flip require the two runs to share the same top-2 candidate pair, which still catches real corruption. --------- Co-authored-by: drunkcoding <leyang.xue@ed.ac.uk>
Description
Opt-in, correctness-preserving longest-prefix KV reuse wired into the active OpenAI continuous-batching path, with exact cold/warm equivalence and unchanged disabled or unsupported-runtime behavior.
Motivation
A
PrefixCachescaffold existed, but the active request path performed no KV lookup, attachment, publication, or reuse. This PR implements the full path per the Momus-approved plan (docs/superpowers/plans/2026-08-21-prefix-kv-reuse.md).What changed
serving/prefix_contract.py,serving/prefix_cache.py): single definition site forPrefixLease/PrefixMatch/PrefixLeaseProvider; namespace-scoped exact parent-path prefix tree with SHA-256 only as a bucket accelerator, pinned leases with retain/release, lease-aware subtree LRU eviction.runtime/attention_backend.py,models/qwen3_paged_attention.py,serving/model_runner.py): one validatedLayeredPagedKVStoreacross all layers with export/import/checkpoint/restore; per-modulelayer_idxplumbing;ModelRunner.get_prefix_reuse_capabilitywith complete-registry validation.runtime/attention_types.py,serving/batch.py,serving/model_runner.py,runtime/attention_backend.py): canonicalPagedBatchLengths(query_lengths, query_offsets, context_lengths, kv_seq_lengths); FlashInferqo_indptruses query lengths while KV pages use total;last_flashinfer_plansnapshot.serving/kv_cache.py): block refcounts, validated store binding that disables independent tensors, layer-complete copy-on-write for shared partial tails, checkpoint/restore-based swap.serving/scheduler.py,serving/sequence.py,serving/kv_cache.py): pin-before-evict, all-or-nothingSequenceGroupadmission viaprepare_group/commit_group/abort_group.serving/engine.py): advancecommitted_kv_tokensonly after a successful forward, publish only block-complete committed prompt ranges, exclude reused-prefix and non-cold requests from DFlash delegation.serving/engine.py,entrypoints/openai/api_server_v2.py): capability + flag gate, validated store bound before scheduler construction,--prefix-cache-max-entries,/v1/reloadinvalidation,prefix_cache_*stats.test_prefix_cache_cuda.py), disabled/cold/warm benchmark with digest-mismatch abort (benchmarks/serving/prefix_cache_benchmark.py), and serving/benchmarking/README/ARCHITECTURE/CHANGELOG updates.Scope / limitations
PrefixLeaseProvidercontracts with chunked prefill; co-enablement requires future reconciliation tests.MOE_PREFIX_CACHE_CUDA=1, and the benchmark dry-run schema check passes.Type of Change
Verification
tests/python/serving(174 passed, 3 CUDA/FlashInfer skips),tests/python/contextpilot(76 passed), touchedtests/python/unit,tests/python/dflash,tests/python/integration.ruff checkclean on all touched files; LSP reports no errors inserving/orattention_backend.py.Checklist