Files
sglang/test/registered/unit/mem_cache/test_hybrid_pool_assembler.py
T

137 lines
4.9 KiB
Python

"""Unit tests for hybrid HiCache pool assembly."""
import unittest
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
from sglang.srt.mem_cache.base_prefix_cache import EvictParams
from sglang.srt.mem_cache.hybrid_cache.hybrid_pool_assembler import (
_evict_mamba_for_device_alloc,
_evict_swa_for_device_alloc,
_split_hicache_size,
build_full_draft_pools,
)
from sglang.srt.mem_cache.memory_pool import HybridLinearKVPool
from sglang.test.ci.ci_register import register_cpu_ci
from sglang.test.test_utils import CustomTestCase
register_cpu_ci(est_time=1, suite="base-a-test-cpu")
class _Pool:
def __init__(self, kv_bytes):
self._kv_bytes = kv_bytes
def get_kv_size_bytes(self):
return self._kv_bytes
class TestDeviceAllocEviction(CustomTestCase):
def test_swa_evicts_only_allocation_shortfall(self):
cache = MagicMock()
cache.token_to_kv_pool_allocator.swa_available_size.return_value = 8
_evict_swa_for_device_alloc(cache, required_size=10)
cache.evict_for_alloc.assert_called_once_with(EvictParams(swa_num_tokens=2))
cache.evict.assert_not_called()
def test_mamba_evicts_only_allocation_shortfall(self):
cache = MagicMock()
allocator = cache.req_to_token_pool.mamba_allocator
allocator.schedulable_available_size.return_value = 8
_evict_mamba_for_device_alloc(cache, required_size=10)
cache.evict_for_alloc.assert_called_once_with(EvictParams(mamba_num=2))
cache.evict.assert_not_called()
def test_sufficient_capacity_skips_eviction(self):
cache = MagicMock()
cache.token_to_kv_pool_allocator.swa_available_size.return_value = 10
cache.req_to_token_pool.mamba_allocator.schedulable_available_size.return_value = (
10
)
_evict_swa_for_device_alloc(cache, required_size=10)
_evict_mamba_for_device_alloc(cache, required_size=10)
cache.evict_for_alloc.assert_not_called()
cache.evict.assert_not_called()
class TestSplitHicacheSize(CustomTestCase):
def test_splits_total_budget_by_device_bytes(self):
# scalar and (k, v) tuple return shapes both supported
shares = _split_hicache_size(
100, (_Pool(75 * 10**9), _Pool((15 * 10**9, 10 * 10**9)))
)
self.assertEqual(shares, (75.0, 25.0)) # proportional to device KV bytes
self.assertEqual(sum(shares), 100) # total budget preserved, not doubled
def test_splits_total_budget_by_device_bytes_three_pools(self):
# scalar and (k, v) tuple return shapes both supported
shares = _split_hicache_size(
100, (_Pool(55 * 10**9), _Pool((15 * 10**9, 10 * 10**9)), _Pool(20 * 10**9))
)
self.assertEqual(shares, (55.0, 25.0, 20.0)) # proportional to device KV bytes
self.assertEqual(sum(shares), 100) # total budget preserved, not doubled
class TestDraftSidecarPoolDispatch(CustomTestCase):
def test_full_builder_unwraps_empty_hybrid_linear_pool(self):
draft_kv_pool = object.__new__(HybridLinearKVPool)
draft_kv_pool.full_kv_pool = SimpleNamespace(layer_num=0)
specs, entries = build_full_draft_pools(
draft_kv_pool=draft_kv_pool,
tree_cache=None,
server_args=None,
)
self.assertEqual(specs, [])
self.assertEqual(entries, [])
def test_full_builder_sizes_sidecar_for_anchor_logical_space(self):
draft_kv_pool = SimpleNamespace(layer_num=1, size=800)
draft_host_pool = SimpleNamespace(layer_num=1)
tree_cache = SimpleNamespace(
cache_controller=SimpleNamespace(
mem_pool_host=SimpleNamespace(size=100, logical_size=800),
page_size=512,
)
)
# The layout comes from the published configuration.
from sglang.srt.runtime_context import publish, reset_context
from sglang.srt.server_args import ServerArgs
server_args = ServerArgs(model_path="dummy", hicache_mem_layout="page_first")
publish(server_args, role="scheduler")
self.addCleanup(reset_context)
with (
patch(
"sglang.srt.mem_cache.hybrid_cache.hybrid_pool_assembler."
"_build_mha_mla_host_pool",
return_value=draft_host_pool,
) as build_host_pool,
patch(
"sglang.srt.mem_cache.hybrid_cache.hybrid_pool_assembler."
"_get_allocator_type",
return_value="default",
),
):
specs, entries = build_full_draft_pools(
draft_kv_pool=draft_kv_pool,
tree_cache=tree_cache,
server_args=server_args,
)
self.assertEqual(build_host_pool.call_args.kwargs["host_to_device_ratio"], 1.0)
self.assertEqual(len(specs), 1)
self.assertIs(entries[0].host_pool, draft_host_pool)
if __name__ == "__main__":
unittest.main()