[Kimi] Support DCP + DSpark (ported from kimi-k3 branch) (#32828)

This commit is contained in:
Khoa Pham
2026-07-31 17:39:00 -07:00
committed by GitHub
parent e4c4faf8a2
commit 1496bfee93
8 changed files with 445 additions and 17 deletions
@@ -6,11 +6,14 @@ deferral. See PagedTokenToKVPoolAllocator.free_segment for why unique is avoided
"""
import unittest
from types import SimpleNamespace
from unittest.mock import patch
import torch
from sglang.srt.mem_cache.allocator.base import BaseTokenToKVPoolAllocator
from sglang.srt.mem_cache.allocator.paged import PagedTokenToKVPoolAllocator
from sglang.srt.mem_cache.common import _release_overallocated_kv_indices
from sglang.test.ci.ci_register import register_cpu_ci
register_cpu_ci(est_time=15, suite="base-a-test-cpu")
@@ -103,6 +106,43 @@ class TestFreeSegment(unittest.TestCase):
with self.assertRaises(AssertionError):
alloc.free_group_end()
def test_overallocated_tail_uses_allocator_page_size_under_dcp(self):
# Scaled-down DCP example: the configured logical page is 1 while the
# allocator page is widened to 4. cache_finished_req has already freed
# the committed tail [4, 5), so over-allocation cleanup for [5, 7)
# must not release the same physical page again.
alloc = _make_allocator()
alloc.debug_mode = True
row = _make_kv_row(alloc, 2 * PAGE_SIZE)
tree_cache = SimpleNamespace(
token_to_kv_pool_allocator=alloc,
req_to_token_pool=SimpleNamespace(req_to_token=row.unsqueeze(0)),
)
req = SimpleNamespace(req_pool_idx=0)
before = len(alloc.free_pages)
alloc.free_group_begin()
alloc.free_segment(row[PAGE_SIZE : PAGE_SIZE + 1], start_pos=PAGE_SIZE)
with (
patch(
"sglang.srt.mem_cache.common.get_spec",
return_value=SimpleNamespace(speculative_algorithm="DSPARK"),
),
patch(
"sglang.srt.mem_cache.common.get_serving",
return_value=SimpleNamespace(strip_thinking_cache=False),
),
):
_release_overallocated_kv_indices(
req,
start_p=PAGE_SIZE + 1,
end_p=2 * PAGE_SIZE - 1,
tree_cache=tree_cache,
)
alloc.free_group_end()
self.assertEqual(len(alloc.free_pages), before + 1)
class TestFreeSegments(unittest.TestCase):
def _freed_by_segments(self, num_tokens, spans):