Keep chunked CP prefills solo during bs>1 admission
Revert the tail-chunk co-batching gate from54c056afbecause allowing a continued chunk to share the next CP bs>1 batch reopens the mixed chunk/page-tail scheduler risks we are currently avoiding. Keep the independent real-prefix budget accounting so chunked requests still contribute their carried prefix to CP cached-token and buffer estimates.\n\nConstraint: Chunked-prefill requests must remain solo until the CP split/page-tail contract is revalidated for mixed batches.\nRejected: Full revert of54c056af| it would also drop true-prefix budget accounting and under-estimate cache/buffer pressure for admitted chunks.\nConfidence: high\nScope-risk: moderate\nDirective: Do not reintroduce tail-chunk co-batching without tests covering page-tail split, CP buffer admission, and ETE chunked+cache-hit replay.\nTested: Local py_compile for environ.py, schedule_policy.py, cp_shared_kv_compose.py, test_prefill_adder.py, test_cp_shared_kv_compose_v2_8rank.py.\nTested: Remote cjy-glm5-new PYTHONPATH=python pytest -q test/registered/unit/managers/test_prefill_adder.py -> 25 passed.\nTested: Remote cjy-glm5-new PYTHONPATH=python pytest -q test/registered/unit/mem_cache/test_cp_shared_kv_runtime.py -> 157 passed, 2 subtests passed.\nNot-tested: Full mixed replay with chunked-prefill traffic after service restart.
This commit is contained in:
@@ -42,17 +42,11 @@ class _CpGroupShim:
|
||||
|
||||
|
||||
def _build_scenario(rank: int, cp_size: int, device: torch.device):
|
||||
"""bs=5 with mixed prefix/extend lengths, extends crossing page bounds.
|
||||
|
||||
The last request is CHUNK-SHAPED (large page-aligned carried prefix +
|
||||
a tail-chunk-sized extend): with mix-chunked co-batching (plan doc S1)
|
||||
a continued chunk is exactly such a (prefix, extend) pair to the CP
|
||||
compose machinery, so this scenario byte-validates the mixed batch.
|
||||
"""
|
||||
"""bs=4 with mixed prefix/extend lengths, extends crossing page bounds."""
|
||||
page_size = 64
|
||||
prefix_lens = [640, 1280, 320, 640, 2048]
|
||||
extend_lens = [95, 130, 64, 200, 512]
|
||||
batch_size = len(prefix_lens)
|
||||
batch_size = 4
|
||||
prefix_lens = [640, 1280, 320, 640]
|
||||
extend_lens = [95, 130, 64, 200]
|
||||
kv_dim = 656 # fp8 layout bytes/token
|
||||
|
||||
from sglang.srt.mem_cache.cp_shared_kv_compute_owner import (
|
||||
|
||||
@@ -6,8 +6,6 @@ from unittest.mock import MagicMock
|
||||
|
||||
import torch
|
||||
|
||||
from sglang.srt.environ import envs
|
||||
|
||||
if "sgl_kernel" not in sys.modules:
|
||||
sys.modules["sgl_kernel"] = types.ModuleType("sgl_kernel")
|
||||
sys.modules["sgl_kernel"].__file__ = "sgl_kernel_stub.py"
|
||||
@@ -987,81 +985,6 @@ class TestPrefillAdder(CustomTestCase):
|
||||
self.assertEqual(adder.cp_shared_kv_prefill_total_cached_tokens, 256)
|
||||
self.assertEqual(adder.cp_shared_kv_prefill_total_extend_tokens, 128)
|
||||
|
||||
def _mix_chunked_adder(self, *, rem_chunk_tokens, extend_cap):
|
||||
set_global_server_args_for_scheduler(
|
||||
ServerArgs(
|
||||
model_path="dummy",
|
||||
enable_nsa_prefill_context_parallel=True,
|
||||
nsa_prefill_cp_mode="in-seq-split",
|
||||
)
|
||||
)
|
||||
self.mock_token_allocator.available_size.return_value = 100000
|
||||
return self.create_adder(
|
||||
self.create_running_batch(),
|
||||
page_size=64,
|
||||
rem_input_tokens=8192,
|
||||
rem_chunk_tokens=rem_chunk_tokens,
|
||||
enable_cp_shared_kv_prefill_bs_gt1=True,
|
||||
cp_shared_kv_prefill_max_batch_requests=8,
|
||||
cp_shared_kv_prefill_max_total_extend_tokens=extend_cap,
|
||||
)
|
||||
|
||||
def test_cp_prefill_mix_chunked_tail_chunk_admits_following_requests(self):
|
||||
# Plan doc S1: with the flag on, a TAIL chunk (extend below the chunk
|
||||
# budget, page-aligned carried prefix) leaves extend-cap headroom and
|
||||
# the following short-extend request co-batches with it.
|
||||
with envs.SGLANG_CP_PREFILL_MIX_CHUNKED.override(True):
|
||||
adder = self._mix_chunked_adder(rem_chunk_tokens=4096, extend_cap=4096)
|
||||
chunked = self.create_prefill_req("chunked", extend_input_len=1280)
|
||||
chunked.prefix_indices = torch.zeros((4096,), dtype=torch.int64)
|
||||
self.assertIsNone(adder.add_chunked_req(chunked)) # tail chunk
|
||||
normal = self.create_prefill_req("normal", extend_input_len=128)
|
||||
self.assertEqual(
|
||||
adder.add_one_req(
|
||||
normal, has_chunked_req=True, truncation_align_size=None
|
||||
),
|
||||
AddReqResult.CONTINUE,
|
||||
)
|
||||
self.assertEqual(
|
||||
[req.rid for req in adder.can_run_list], ["chunked", "normal"]
|
||||
)
|
||||
|
||||
def test_cp_prefill_mix_chunked_full_chunk_stays_solo_by_budget(self):
|
||||
# A FULL chunk consumes the whole (chunk-clamped) extend cap, so the
|
||||
# first following request is rejected by the extend gate — no special
|
||||
# code, the budget arithmetic ends the scan.
|
||||
with envs.SGLANG_CP_PREFILL_MIX_CHUNKED.override(True):
|
||||
adder = self._mix_chunked_adder(rem_chunk_tokens=256, extend_cap=4096)
|
||||
chunked = self.create_prefill_req("chunked", extend_input_len=512)
|
||||
chunked.prefix_indices = torch.zeros((4096,), dtype=torch.int64)
|
||||
self.assertIs(adder.add_chunked_req(chunked), chunked) # truncated
|
||||
self.assertEqual(chunked.extend_input_len, 256)
|
||||
normal = self.create_prefill_req("normal", extend_input_len=128)
|
||||
self.assertEqual(
|
||||
adder.add_one_req(
|
||||
normal, has_chunked_req=True, truncation_align_size=None
|
||||
),
|
||||
AddReqResult.OTHER,
|
||||
)
|
||||
self.assertEqual([req.rid for req in adder.can_run_list], ["chunked"])
|
||||
|
||||
def test_cp_prefill_mix_chunked_non_aligned_prefix_stays_solo(self):
|
||||
# I1 guard: a chunked prefix that is not a page multiple would break
|
||||
# the CP page-aligned split in a multi-request batch — keep it solo.
|
||||
with envs.SGLANG_CP_PREFILL_MIX_CHUNKED.override(True):
|
||||
adder = self._mix_chunked_adder(rem_chunk_tokens=4096, extend_cap=4096)
|
||||
chunked = self.create_prefill_req("chunked", extend_input_len=1280)
|
||||
chunked.prefix_indices = torch.zeros((100,), dtype=torch.int64)
|
||||
self.assertIsNone(adder.add_chunked_req(chunked))
|
||||
normal = self.create_prefill_req("normal", extend_input_len=128)
|
||||
self.assertEqual(
|
||||
adder.add_one_req(
|
||||
normal, has_chunked_req=True, truncation_align_size=None
|
||||
),
|
||||
AddReqResult.OTHER,
|
||||
)
|
||||
self.assertEqual([req.rid for req in adder.can_run_list], ["chunked"])
|
||||
|
||||
def test_cp_prefill_total_cached_limit_stops_second_cached_request(self):
|
||||
set_global_server_args_for_scheduler(
|
||||
ServerArgs(
|
||||
|
||||
Reference in New Issue
Block a user