Remove swa and mamba radix cache (#40313)
This commit is contained in:
@@ -72,12 +72,10 @@ def handle_mamba_backend(server_args: Any):
|
||||
|
||||
|
||||
def handle_int8_mamba_checkpoint(server_args: Any):
|
||||
# The int8 mamba checkpoint pool is only wired into the built-in
|
||||
# MambaRadixCache. The host-offload path (enabled by
|
||||
# --enable-hierarchical-cache) and custom radix-cache backends are NOT
|
||||
# int8-aware: they would read int8 checkpoint slots as bf16 active slots
|
||||
# (wrong pool / out-of-range). Reject the combination up front rather than
|
||||
# silently corrupting state.
|
||||
# The host-offload path (enabled by --enable-hierarchical-cache) and
|
||||
# custom radix-cache backends are NOT int8-aware: they would read int8
|
||||
# checkpoint slots as bf16 active slots (wrong pool / out-of-range).
|
||||
# Reject the combination up front rather than silently corrupting state.
|
||||
cfg = resolving_view(server_args)
|
||||
if not cfg.enable_int8_mamba_checkpoint:
|
||||
return
|
||||
|
||||
@@ -25,7 +25,7 @@ def _qwen4_exp_overrides(server_args: Any, hf_config: Any) -> dict:
|
||||
"""Compressed QSA must own ``page_size`` here,
|
||||
so the qwen3_5 hybrid attention-shape policy is restated rather than shared.
|
||||
page_size=64 needs page-aligned full-KV allocation (slots are full_slot // ratio),
|
||||
which MambaRadixCache allows only with mamba extra-buffer or --disable-radix-cache.
|
||||
which in turn needs the mamba extra-buffer strategy or --disable-radix-cache.
|
||||
"""
|
||||
cfg = resolving_view(server_args)
|
||||
if (
|
||||
|
||||
@@ -678,9 +678,6 @@ class Envs:
|
||||
SGLANG_ENABLE_UNIFIED_RADIX_TREE = EnvBool(False)
|
||||
# Registered TreeCore backend serving the unified radix cache.
|
||||
SGLANG_UNIFIED_RADIX_TREE_CORE_BACKEND = EnvStr("python")
|
||||
# TODO(DSV4): @ispobock this has bug on main branch when retract
|
||||
SGLANG_OPT_SWA_RADIX_CACHE_COMPACT = EnvBool(False)
|
||||
SGLANG_OPT_SWA_SPLIT_LEAF_ON_INSERT = EnvBool(False)
|
||||
SGLANG_OPT_SWA_RELEASE_LEAF_LOCK_AFTER_WINDOW = EnvBool(False)
|
||||
|
||||
# ===================================================================
|
||||
|
||||
@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Any
|
||||
import torch
|
||||
|
||||
from sglang.srt.mem_cache.radix_cache import RadixCache
|
||||
from sglang.srt.mem_cache.swa_radix_cache import SWARadixCache
|
||||
from sglang.srt.mem_cache.unified_cache.unified_tree_core_interface import (
|
||||
RadixCacheWalkResult,
|
||||
)
|
||||
@@ -34,7 +33,7 @@ def walk_radix_cache_for_canary(
|
||||
return radix_cache.tree_core.walk_for_kv_canary(
|
||||
unlocked_only=unlocked_only, swa_resident_only=swa_resident_only
|
||||
)
|
||||
if cache_type is not RadixCache and cache_type is not SWARadixCache:
|
||||
if cache_type is not RadixCache:
|
||||
raise NotImplementedError(
|
||||
f"walk_radix_cache_for_canary does not support {cache_type.__name__}"
|
||||
)
|
||||
@@ -133,9 +132,6 @@ def _node_is_unlocked_for_canary(
|
||||
if type(radix_cache) is RadixCache:
|
||||
return node.lock_ref == 0
|
||||
|
||||
if type(radix_cache) is SWARadixCache:
|
||||
return node.full_lock_ref == 0
|
||||
|
||||
raise NotImplementedError(
|
||||
f"walk_radix_cache_for_canary does not support {type(radix_cache).__name__}"
|
||||
)
|
||||
@@ -146,7 +142,5 @@ def _node_is_swa_resident_for_canary(
|
||||
node: TreeNode,
|
||||
radix_cache: BasePrefixCache,
|
||||
) -> bool:
|
||||
if type(radix_cache) is SWARadixCache:
|
||||
return not node.swa_tombstone
|
||||
|
||||
# RadixCache has no SWA tier, so every node it holds is resident.
|
||||
return True
|
||||
|
||||
@@ -99,8 +99,8 @@ class SchedulerInvariantChecker:
|
||||
session_held = self.pool_stats_observer.session_held_full_tokens()
|
||||
total = ps.full_capacity
|
||||
elif self.is_hybrid_ssm:
|
||||
# Branch on cache type for the protected accessor (MambaRadixCache
|
||||
# splits full/mamba; ChunkCache only has the single protected_size).
|
||||
# Branch on cache type for the protected accessor (a mamba-capable
|
||||
# cache splits full/mamba; ChunkCache only has the single protected_size).
|
||||
# Use the allocator's `.size` for `total`: static max_total_num_tokens for
|
||||
# non-unified pools, the dynamic byte-coordinated cap (matching
|
||||
# `available_size`) for the unified pool.
|
||||
|
||||
@@ -38,7 +38,7 @@ to keep. The layout is specified in
|
||||
Two groups sit outside that stack:
|
||||
|
||||
- **Radix cache** is its own axis. The per-model variants (`radix_cache.py`,
|
||||
`swa_radix_cache.py`, `mamba_radix_cache.py`, `hiradix_cache.py`, `chunk_cache.py`)
|
||||
`hiradix_cache.py`, `chunk_cache.py`)
|
||||
are converging onto the **Unified Radix Cache** (`unified_cache/`,
|
||||
[#20415](https://github.com/sgl-project/sglang/issues/20415)), whose Full/SWA/Mamba
|
||||
component model is documented in
|
||||
|
||||
@@ -271,10 +271,10 @@ def retraction_discard(req: Req, tree_cache: BasePrefixCache, backend: str) -> N
|
||||
|
||||
def release_kv_cache(req: Req, tree_cache: BasePrefixCache, is_insert: bool = True):
|
||||
assert (not req.kv.holds_kv) == req.kv.is_kv_released
|
||||
# MambaRadixCache may alloc mamba state before alloc KV cache
|
||||
# A mamba-capable cache may alloc mamba state before alloc KV cache
|
||||
if not req.kv.holds_kv:
|
||||
assert tree_cache.supports_mamba(), (
|
||||
"Only MambaRadixCache allow freeing before alloc"
|
||||
"Only a mamba-capable tree cache allows freeing before alloc"
|
||||
)
|
||||
# TODO (csy, hanming): clean up this early allocation logic
|
||||
if req.kv.holds_mamba:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,8 +52,8 @@ class PureSWARadixCache(RadixCache):
|
||||
return 0
|
||||
|
||||
def sanity_check(self):
|
||||
"""No-op: PureSWARadixCache uses RadixCache's simple tree structure
|
||||
which doesn't need the dual-LRU sanity checks of SWARadixCache."""
|
||||
"""No-op: an all-SWA model has no full tier, so there is no full/SWA
|
||||
split to cross-check."""
|
||||
pass
|
||||
|
||||
def evict(self, params: EvictParams) -> EvictResult:
|
||||
|
||||
@@ -74,8 +74,8 @@ class QSATokenToKVPool(HybridLinearKVPool):
|
||||
"compressed QSA requires a paged full-KV cache with the page "
|
||||
"a multiple of the compress ratio (compressed slots are "
|
||||
f"full_slot // ratio): page_size={page_size}, "
|
||||
f"ratio={qsa_compress_ratio}. With MambaRadixCache this "
|
||||
"needs the mamba extra-buffer strategy or "
|
||||
f"ratio={qsa_compress_ratio}. This needs the mamba "
|
||||
"extra-buffer strategy or "
|
||||
"--disable-radix-cache (see the Qwen4-Exp arg overrides)."
|
||||
)
|
||||
# super().__init__ computes mem_usage via the overridden get_kv_size_bytes,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ A component-based, pluggable prefix cache framework for SGLang that unifies Full
|
||||
|
||||
## Design Goals
|
||||
|
||||
1. **Unified tree structure** — One radix tree manages all KV cache types instead of separate specialized implementations (`SWARadixCache`, `MambaRadixCache`, etc.).
|
||||
1. **Unified tree structure** — One radix tree manages all KV cache types, replacing the separate specialized implementations that preceded it.
|
||||
2. **Pluggable components** — Each attention/state type (Full, SWA, Mamba) is a `TreeComponent` that implements hook interfaces. Adding a new cache type only requires adding a new component.
|
||||
3. **Per-component resource isolation** — Each component has its own lock reference counting, evictable/protected size tracking, and eviction driver. Auxiliary components use per-component LRUs; Full uses device/host leaf sets.
|
||||
4. **Cascade eviction with priority** — When a component evicts a node, lower-or-equal-priority components on the same node are evicted together, maintaining cross-component consistency.
|
||||
|
||||
@@ -537,8 +537,7 @@ class MambaComponent(TreeComponent):
|
||||
# slot's unflushed ring depth (`write_pos`), so on request finish cap
|
||||
# the donate to the last flush boundary (where temporal is current)
|
||||
# and reset the cursor, keeping the donated checkpoint consistent with
|
||||
# its key length. page_size is asserted == 1, so no realign. Mirrors
|
||||
# MambaRadixCache.cache_finished_req.
|
||||
# its key length. page_size is asserted == 1, so no realign.
|
||||
if is_finished:
|
||||
write_pos_buf = (
|
||||
self.cache.req_to_token_pool.mamba_pool.replayssm_write_pos
|
||||
|
||||
@@ -4611,7 +4611,7 @@ def get_extend_input_len_swa_limit(
|
||||
sliding_window_size: int, chunked_prefill_size: int, page_size: int
|
||||
) -> int:
|
||||
# 1. a factor of 2x is because each prefill contains chunked_prefill_size tokens,
|
||||
# and between prefills, we run swa_radix_cache.cache_unfinished_req(),
|
||||
# and between prefills, we run the tree cache's cache_unfinished_req(),
|
||||
# so we unlock the previously locked nodes.
|
||||
# 2. max is to handle the case that chunked_prefill_size is larger than sliding_window_size.
|
||||
# in that case, each prefill contains chunked_prefill_size tokens,
|
||||
|
||||
@@ -2,7 +2,6 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict
|
||||
|
||||
from sglang.srt.mem_cache.swa_radix_cache import TreeNode as SWATreeNode
|
||||
from sglang.srt.mem_cache.unified_radix_cache import UnifiedTreeNode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -18,8 +17,6 @@ def get_all_node_lock_refs(ctx: ScriptedContext) -> Dict[int, int]:
|
||||
|
||||
|
||||
def _node_lock_ref(node: Any) -> int:
|
||||
if isinstance(node, SWATreeNode):
|
||||
return node.full_lock_ref + node.swa_lock_ref
|
||||
if isinstance(node, UnifiedTreeNode):
|
||||
return sum(cd.lock_ref for cd in node.component_data)
|
||||
return node.lock_ref
|
||||
|
||||
Reference in New Issue
Block a user