Files
sgl-project--sglang/test/manual/chunked_prefill/test_scripted_regression.py
T
wehub-resource-sync 94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:16 +08:00

525 lines
20 KiB
Python

import unittest
from sglang.test.scripted_runtime.context import ScriptedContext
from sglang.test.scripted_runtime.test_case import ScriptedTestCase
from sglang.test.scripted_runtime_chunked_helpers import (
DEFAULT_CHUNK_SIZE,
DEFAULT_MAX_STEPS,
VERY_LONG_PROMPT_LEN,
base_engine_kwargs,
run_until,
run_until_all_finished,
run_until_finished,
warmup_radix,
)
def _drain_until_released(t, *handles):
for _ in range(12):
if all(
h.kv_pages == 0
and h.lock_refs == 0
and (h.req is None or h.req.req_pool_idx is None)
for h in handles
):
return
yield
class TestRegressionBasic(ScriptedTestCase):
ENGINE_KWARGS = base_engine_kwargs(chunked_prefill_size=DEFAULT_CHUNK_SIZE)
def test_abort_waiting_releases_all(self):
self.server.execute_script(self._script_abort_waiting_releases_all)
@staticmethod
def _script_abort_waiting_releases_all(t: ScriptedContext):
r = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r, lambda h: h.is_chunking)
t.abort(r)
yield from _drain_until_released(t, r)
assert r.kv_pages == 0
assert r.req.req_pool_idx is None
assert r.lock_refs == 0
assert not r.is_chunking
assert r.req.inflight_middle_chunks == 0
def test_pause_covers_waiting_chunked(self):
self.server.execute_script(self._script_pause_covers_waiting_chunked)
@staticmethod
def _script_pause_covers_waiting_chunked(t: ScriptedContext):
r = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r, lambda h: h.is_chunking)
t.pause_generation(mode="retract")
yield
assert r.kv_pages == 0
assert r.req.req_pool_idx is None
assert r.lock_refs == 0
assert not r.is_chunking
t.continue_generation()
def test_inflight_middle_chunks_invariant(self):
self.server.execute_script(self._script_inflight_middle_chunks_invariant)
@staticmethod
def _script_inflight_middle_chunks_invariant(t: ScriptedContext):
r = t.start_req(
prompt_len=2 * DEFAULT_CHUNK_SIZE, max_new_tokens=4, ignore_eos=True
)
observed_max = 0
saw_chunking_bump = False
cleared_inflight = False
for _ in range(DEFAULT_MAX_STEPS):
req = r.req
if req is not None:
observed_max = max(observed_max, req.inflight_middle_chunks)
if r.chunks_done >= 1 and r.is_chunking:
saw_chunking_bump = saw_chunking_bump or (
req.inflight_middle_chunks > 0
)
if not r.is_chunking and r.chunks_done >= 2:
cleared_inflight = req.inflight_middle_chunks == 0
break
if r.finished:
cleared_inflight = True
break
yield
else:
raise AssertionError("chunk loop did not clear within DEFAULT_MAX_STEPS")
assert saw_chunking_bump, "last-chunk admit must bump inflight_middle_chunks"
assert observed_max == 1, (
f"e875cd36e4: inflight_middle_chunks must be a 0/1 latch; "
f"observed max={observed_max} (pre-fix bug would bump to 2 "
f"at the last-chunk admit boundary)"
)
assert (
cleared_inflight
), "inflight_middle_chunks should be 0 once the chunk loop clears"
yield from run_until_finished(r)
assert r.finished
assert r.chunks_done >= 2
@unittest.skip(
"dbdcdde245 mamba_pool_idx cleanup-skip is mamba-architecture-specific. "
"The shared test fixture does not configure a mamba model; running this "
"regression against the default transformer model would not exercise the "
"mamba NO_TOKEN cleanup path, so the body would be a check "
"with no real protection. Re-enable when a mamba fixture is wired in."
)
def test_mamba_chunked_resume_no_token(self):
self.server.execute_script(self._script_mamba_chunked_resume_no_token)
@staticmethod
def _script_mamba_chunked_resume_no_token(t: ScriptedContext):
r = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until_finished(r)
assert r.finished
def test_merge_batch_assert_widened(self):
self.server.execute_script(self._script_merge_batch_assert_widened)
@staticmethod
def _script_merge_batch_assert_widened(t: ScriptedContext):
r1 = t.start_req(
prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2, ignore_eos=True
)
r2 = t.start_req(prompt_len=16, max_new_tokens=2, ignore_eos=True)
yield from run_until_all_finished([r1, r2])
assert r1.finished and r2.finished
assert r1.chunks_done >= 2 and r2.chunks_done == 0
assert len(r1.req.output_ids) == 2 and len(r2.req.output_ids) == 2
def test_chunked_pending_tokens_subtract_prefix(self):
self.server.execute_script(self._script_chunked_pending_tokens_subtract_prefix)
@staticmethod
def _script_chunked_pending_tokens_subtract_prefix(t: ScriptedContext):
r1 = t.start_req(prompt_len=DEFAULT_CHUNK_SIZE * 4, max_new_tokens=2)
yield from run_until(r1, lambda h: h.is_chunking and h.chunks_done >= 1)
r2 = t.start_req(prompt_len=DEFAULT_CHUNK_SIZE, max_new_tokens=2)
yield from run_until(r2, lambda h: h.status == "waiting")
r1_prefix = len(r1.req.prefix_indices)
assert r1.is_chunking, "r1 must still be the in-flight chunked req"
assert r1_prefix > 0, "r1 must hold a committed prefix as the chunked req"
observed_pending = t.scheduler.load_inquirer._get_num_pending_tokens()
r1_seqlen = r1.req.seqlen
r2_seqlen = r2.req.seqlen
expected_post_fix = (r1_seqlen - r1_prefix) + r2_seqlen
pre_fix_bad = r1_seqlen + r2_seqlen
assert observed_pending == expected_post_fix, (
f"c79a73bec4: load_inquirer must subtract the chunked req's "
f"prefix_indices_len from its pending-token contribution; "
f"observed={observed_pending}, expected_post_fix="
f"{expected_post_fix}, pre_fix_bad={pre_fix_bad}"
)
assert observed_pending < pre_fix_bad, (
f"c79a73bec4: observed pending tokens did not subtract the chunked "
f"prefix (matches the no-subtraction sum {pre_fix_bad}) — fix is regressed"
)
yield from run_until_all_finished([r1, r2])
assert r1.finished and r2.finished
def test_chunked_admission_reuse_branch_balanced(self):
self.server.execute_script(self._script_chunked_admission_reuse_branch_balanced)
@staticmethod
def _script_chunked_admission_reuse_branch_balanced(t: ScriptedContext):
baseline_refs = sum(t.get_all_node_lock_refs().values())
r = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
for target_chunk in (3, 4, 5):
yield from run_until(
r, lambda h: h.chunks_done >= target_chunk and h.is_chunking
)
assert r.lock_refs == 1, (
f"reuse branch re-acquired lock_ref on the chunked req's node at "
f"chunk {target_chunk}: r.lock_refs={r.lock_refs} (expected 1)"
)
per_node = t.get_all_node_lock_refs()
assert max(per_node.values(), default=0) <= 1, (
f"reuse branch double-locked a single node at chunk "
f"{target_chunk}: per-node lock_refs={per_node}"
)
yield from run_until_finished(r)
final_refs = sum(t.get_all_node_lock_refs().values())
assert final_refs == baseline_refs, (
f"chunked lifecycle must net to zero lock_ref delta; "
f"baseline={baseline_refs}, final={final_refs}"
)
assert r.lock_refs == 0
def test_multiturn_full_hit_no_reuse_branch(self):
self.server.execute_script(self._script_multiturn_full_hit_no_reuse_branch)
@staticmethod
def _script_multiturn_full_hit_no_reuse_branch(t: ScriptedContext):
baseline_refs = sum(t.get_all_node_lock_refs().values())
r1 = t.start_req(prompt_len=64, max_new_tokens=2)
yield from run_until_finished(r1)
r2 = t.start_req(prompt_len=64, max_new_tokens=2)
yield from run_until_finished(r2)
assert not r2.is_chunking
assert r2.req.cached_tokens > 0, (
f"follow-up req must fully hit the warm prefix to exercise the "
f"no-reuse path; got cached_tokens={r2.req.cached_tokens}"
)
for _ in range(5):
yield
assert sum(t.get_all_node_lock_refs().values()) == baseline_refs, (
f"full-prefix-hit follow-up must not take the chunked reuse "
f"branch; lock_refs drifted from {baseline_refs} to "
f"{sum(t.get_all_node_lock_refs().values())}"
)
def test_abort_chunked_resume_releases_all_resources(self):
self.server.execute_script(
self._script_abort_chunked_resume_releases_all_resources
)
@staticmethod
def _script_abort_chunked_resume_releases_all_resources(t: ScriptedContext):
baseline_refs = sum(t.get_all_node_lock_refs().values())
r = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r, lambda h: h.is_chunking and h.chunks_done >= 1)
assert r.req.req_pool_idx is not None, "row must be held mid-chunk"
assert r.kv_pages > 0, "committed KV must be held mid-chunk"
assert r.lock_refs >= 1, "radix lock_ref must be held mid-chunk"
t.abort(r)
yield from _drain_until_released(t, r)
assert (
r.req.req_pool_idx is None
), f"96d4749094: abort must release row; got row_idx={r.req.req_pool_idx!r}"
assert (
r.kv_pages == 0
), f"96d4749094: abort must release KV; got kv_pages={r.kv_pages}"
assert (
r.lock_refs == 0
), f"96d4749094: abort must release lock_ref; got lock_refs={r.lock_refs}"
assert not r.is_chunking
assert r.req.inflight_middle_chunks == 0
assert sum(t.get_all_node_lock_refs().values()) == baseline_refs
def test_pause_retract_releases_waiting_chunked_resume(self):
self.server.execute_script(
self._script_pause_retract_releases_waiting_chunked_resume
)
@staticmethod
def _script_pause_retract_releases_waiting_chunked_resume(t: ScriptedContext):
r = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r, lambda h: h.is_chunking and h.chunks_done >= 1)
assert r.req.req_pool_idx is not None and r.kv_pages > 0 and r.lock_refs >= 1
t.pause_generation(mode="retract")
yield
assert r.req.req_pool_idx is None, (
f"f38e69f87d: pause(retract) must release waiting "
f"chunked-resume row; got row_idx={r.req.req_pool_idx!r}"
)
assert r.kv_pages == 0
assert r.lock_refs == 0
assert not r.is_chunking
assert r.status == "waiting", (
f"f38e69f87d: pause(retract) must re-queue the retracted "
f"chunked-resume req; got status={r.status!r}"
)
assert t.scheduler.chunked_req is None
assert t.scheduler.running_batch.is_empty()
t.continue_generation()
yield from run_until_finished(r)
assert r.finished
assert len(r.req.output_ids) == 2
def test_retract_all_clears_batch_with_chunked(self):
self.server.execute_script(self._script_retract_all_clears_batch_with_chunked)
@staticmethod
def _script_retract_all_clears_batch_with_chunked(t: ScriptedContext):
r1 = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
r2 = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r1, lambda h: h.is_chunking and h.chunks_done >= 1)
yield from run_until(r2, lambda h: h.status == "waiting")
t.pause_generation(mode="retract")
yield
assert len(t.scheduler.running_batch.reqs) == 0, (
f"f0388931bf: retract_all must clear batch; got batch_size="
f"{len(t.scheduler.running_batch.reqs)}"
)
assert (
t.scheduler.chunked_req.rid if t.scheduler.chunked_req is not None else None
) is None
for r in (r1, r2):
assert r.status == "waiting"
assert r.kv_pages == 0
assert not r.is_chunking
t.continue_generation()
yield from run_until_all_finished([r1, r2])
class TestRegressionPp(ScriptedTestCase):
ENGINE_KWARGS = base_engine_kwargs(
chunked_prefill_size=DEFAULT_CHUNK_SIZE,
tp_size=2,
pp_size=2,
)
def test_pp_abort_dedup(self):
self.server.execute_script(self._script_pp_abort_dedup)
@staticmethod
def _script_pp_abort_dedup(t: ScriptedContext):
r = t.start_req(prompt_len=2 * DEFAULT_CHUNK_SIZE, max_new_tokens=4)
yield from run_until(r, lambda h: h.chunks_done >= 1 and h.is_chunking)
t.abort(r)
yield
rids_after_abort = [req.rid for req in t.scheduler.running_batch.reqs]
occurrences = sum(1 for rid in rids_after_abort if rid == r.rid)
assert occurrences <= 1, (
f"b823c16e60: batch_rids must dedup across mbs + "
f"waiting_queue; got {occurrences} occurrences of rid="
f"{r.rid} (pre-fix bug would yield 3)"
)
yield from _drain_until_released(t, r)
assert r.finished
class TestRegressionPriority(ScriptedTestCase):
ENGINE_KWARGS = base_engine_kwargs(
chunked_prefill_size=DEFAULT_CHUNK_SIZE,
enable_priority_scheduling=True,
)
def test_priority_skips_chunked_in_prefix_match(self):
self.server.execute_script(self._script_priority_skips_chunked_in_prefix_match)
@staticmethod
def _script_priority_skips_chunked_in_prefix_match(t: ScriptedContext):
r1 = t.start_req(
prompt_len=VERY_LONG_PROMPT_LEN,
max_new_tokens=2,
priority=0,
ignore_eos=True,
)
yield from run_until(r1, lambda h: h.is_chunking and h.chunks_done >= 1)
r1_host_hit_before = r1.req.host_hit_length
r2 = t.start_req(
prompt_len=VERY_LONG_PROMPT_LEN,
max_new_tokens=2,
priority=10,
ignore_eos=True,
)
prev_chunks = r1.chunks_done
while not (r1.finished and r2.finished):
assert r1.req is None or r1.req.host_hit_length == r1_host_hit_before, (
f"aaf3752d2b: priority calc re-matched the chunked-resume req; "
f"host_hit_length changed {r1_host_hit_before} -> "
f"{r1.req.host_hit_length}"
)
assert r1.chunks_done >= prev_chunks, (
f"r1 chunked prefill was preempted by higher-priority r2: "
f"chunks_done regressed {prev_chunks} -> {r1.chunks_done}"
)
prev_chunks = r1.chunks_done
yield
assert r1.finished and r2.finished
assert r1.chunks_done >= 2
assert len(r1.req.output_ids) == 2 and len(r2.req.output_ids) == 2
class TestRegressionLpm(ScriptedTestCase):
ENGINE_KWARGS = base_engine_kwargs(
chunked_prefill_size=DEFAULT_CHUNK_SIZE,
schedule_policy="lpm",
)
def test_chunked_resume_priority_in_sort(self):
self.server.execute_script(self._script_chunked_resume_priority_in_sort)
@staticmethod
def _script_chunked_resume_priority_in_sort(t: ScriptedContext):
r_long = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r_long, lambda h: h.is_chunking)
shorts = [t.start_req(prompt_len=4, max_new_tokens=1) for _ in range(8)]
initial_chunks = r_long.chunks_done
for _ in range(200):
if r_long.chunks_done > initial_chunks:
break
yield
else:
raise AssertionError(
f"chunked req starved by short req flood; "
f"chunks_done stuck at {initial_chunks}"
)
all_reqs = [r_long, *shorts]
done = {r.rid: False for r in all_reqs}
for _ in range(DEFAULT_MAX_STEPS):
for r in all_reqs:
done[r.rid] = done[r.rid] or r.finished
if all(done.values()):
break
yield
else:
raise AssertionError(
f"reqs did not all finish; done={done}, "
f"long_chunks={r_long.chunks_done}"
)
assert r_long.finished
assert r_long.chunks_done >= 2
def test_lpm_skips_chunked_resume_prefix_match(self):
self.server.execute_script(self._script_lpm_skips_chunked_resume_prefix_match)
@staticmethod
def _script_lpm_skips_chunked_resume_prefix_match(t: ScriptedContext):
yield from warmup_radix(t, [1] * (2 * DEFAULT_CHUNK_SIZE))
r1 = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r1, lambda h: h.chunks_done >= 1 and h.is_chunking)
host_hit_before = r1.req.host_hit_length
r2 = t.start_req(prompt_len=2 * DEFAULT_CHUNK_SIZE, max_new_tokens=2)
while not (r1.finished and r2.finished):
assert r1.req is None or r1.req.host_hit_length == host_hit_before, (
f"calc_priority re-matched the chunked-resume req; host_hit_length "
f"changed {host_hit_before} -> {r1.req.host_hit_length}"
)
yield
def test_chunked_resume_priority_under_lpm(self):
self.server.execute_script(self._script_chunked_resume_priority_under_lpm)
@staticmethod
def _script_chunked_resume_priority_under_lpm(t: ScriptedContext):
long_prefix_tokens = [1] * (3 * DEFAULT_CHUNK_SIZE)
yield from warmup_radix(t, long_prefix_tokens)
r1 = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r1, lambda h: h.is_chunking and h.chunks_done >= 1)
competitors = [
t.start_req(prompt_len=3 * DEFAULT_CHUNK_SIZE + 32, max_new_tokens=2)
for _ in range(6)
]
baseline_chunks = r1.chunks_done
for _ in range(50):
if r1.chunks_done > baseline_chunks:
break
yield
else:
raise AssertionError(
f"bf5b4e9a10: chunked-resume starved under LPM by "
f"long-prefix competitors; chunks_done stuck at "
f"{baseline_chunks}"
)
yield from run_until_all_finished([r1, *competitors])
class TestRegressionGptOss(ScriptedTestCase):
ENGINE_KWARGS = base_engine_kwargs(
chunked_prefill_size=DEFAULT_CHUNK_SIZE,
model_path="openai/gpt-oss-20b",
mem_fraction_static=0.70,
disable_piecewise_cuda_graph=True,
)
def test_chunked_stash_bounded_by_kv_committed_len(self):
self.server.execute_script(
self._script_chunked_stash_bounded_by_kv_committed_len
)
@staticmethod
def _script_chunked_stash_bounded_by_kv_committed_len(t: ScriptedContext):
r = t.start_req(prompt_len=VERY_LONG_PROMPT_LEN, max_new_tokens=2)
yield from run_until(r, lambda h: h.is_chunking and h.chunks_done >= 1)
committed = r.req.kv_committed_len
assert committed > 0
assert len(r.req.prefix_indices) <= committed, (
f"cache_unfinished_req over-read past kv_committed_len: "
f"prefix_indices_len={len(r.req.prefix_indices)}, "
f"kv_committed_len={committed}"
)
yield from run_until_finished(r)
if __name__ == "__main__":
unittest.main()