Files
sglang/test/registered/unit/disaggregation/test_encoder_scheduler.py
T
+26 abddb1c7e9 [Kimi] Support kimi-k3 (#32541)
Co-authored-by: DarkSharpness <76582120+DarkSharpness@users.noreply.github.com>
Co-authored-by: Xiaoyu Zhang <1182563586@qq.com>
Co-authored-by: Mick <mickjagger19@icloud.com>
Co-authored-by: Yuhao Yang <47235274+yhyang201@users.noreply.github.com>
Co-authored-by: Cheng Wan <54331508+ch-wan@users.noreply.github.com>
Co-authored-by: Ke Bao <ispobaoke@gmail.com>
Co-authored-by: Baizhou Zhang <sobereddiezhang@gmail.com>
Co-authored-by: Chunan Zeng <zcnrex@gmail.com>
Co-authored-by: Khoa Pham <khoa.pham@radixark.ai>
Co-authored-by: Ziyi Xu <ziyi.xu@radixark.ai>
Co-authored-by: Zijie Xia <37504505+zijiexia@users.noreply.github.com>
Co-authored-by: Yuwei An <ayw.sirius19@gmail.com>
Co-authored-by: zhangxiaohao <1024393531@qq.com>
Co-authored-by: Yangmin Li <yangminl@nvidia.com>
Co-authored-by: Julien Lin <jullin@nvidia.com>
Co-authored-by: Hao Phan <htphan@nvidia.com>
Co-authored-by: Thomas Wang <1am9trash@gmail.com>
Co-authored-by: RolaoDenthu <xinyisong0111@gmail.com>
Co-authored-by: pigeonsoup <32922982+pigeonsoup@users.noreply.github.com>
Co-authored-by: HaiShaw <hixiao@gmail.com>
Co-authored-by: Xinyuan Tong <115166877+JustinTong0323@users.noreply.github.com>
Co-authored-by: Pranjal Shankhdhar <pranjal.ssh@gmail.com>
Co-authored-by: Lee Nau <lee.nau@gmail.com>
Co-authored-by: HMING <126185151+Hearum@users.noreply.github.com>
Co-authored-by: elvischenv <219235043+elvischenv@users.noreply.github.com>
Co-authored-by: Byron Hsu <byronhsu1230@gmail.com>
Co-authored-by: Byron Hsu <byron+per@periodiclabs.ai>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Thomas Wang <thomawan@amd.com>
Co-authored-by: Xinyi Song <86638975+RolaoDenthu@users.noreply.github.com>
Co-authored-by: Mohammad Miadh Angkad <176301910+mmangkad@users.noreply.github.com>
Co-authored-by: Cheng Wan <cheng.wan@radixark.ai>
Co-authored-by: BBuf <xiaoyu.zhang@radixark.ai>
Co-authored-by: Hanming Lu <hanminglu@meta.com>
Co-authored-by: Xinyi Song <xinyis10@illinois.edu>
2026-08-04 13:22:49 -07:00

126 lines
3.7 KiB
Python

import asyncio
import sys
import pytest
from sglang.srt.disaggregation.encode_server import (
EncoderScheduler,
PendingRequest,
_resolve_encoder_batch_policy,
)
from sglang.test.ci.ci_register import register_cpu_ci
register_cpu_ci(est_time=1, suite="base-a-test-cpu")
def _pending(modality: str = "image") -> PendingRequest:
return PendingRequest(
{"req_id": f"{modality}-request", "modality": modality},
asyncio.get_running_loop(),
)
def test_collect_batch_yields_for_concurrent_image_request_without_fixed_wait():
# The end-to-end coalescing test cannot replace this case: asyncio.gather
# enqueues both requests within one event-loop turn, so it passes even with
# the yield removed. Only a second request enqueued from a separate task
# observes whether _collect_batch yields at all.
async def run_test():
scheduler = EncoderScheduler(
encoder=None,
send_sockets=[],
max_batch_size=8,
coalesce_same_turn=True,
)
first = _pending()
second = _pending()
await scheduler.pending_queue.put(first)
async def enqueue_after_worker_yields():
await scheduler.pending_queue.put(second)
producer = asyncio.create_task(enqueue_after_worker_yields())
batch = await scheduler._collect_batch()
await producer
assert batch == [first, second]
asyncio.run(run_test())
def test_collect_batch_respects_max_batch_size():
async def run_test():
scheduler = EncoderScheduler(
encoder=None,
send_sockets=[],
max_batch_size=2,
coalesce_same_turn=True,
)
requests = [_pending() for _ in range(3)]
for request in requests:
await scheduler.pending_queue.put(request)
assert await scheduler._collect_batch() == requests[:2]
assert scheduler.pending_queue.get_nowait() is requests[2]
asyncio.run(run_test())
def test_scheduler_coalesces_concurrent_submissions():
class FakeEncoder:
def __init__(self):
self.encode_dispatch_lock = asyncio.Lock()
self.batches = []
async def batch_encode(self, requests, _modality):
self.batches.append([request["req_id"] for request in requests])
return [(1, 2, 3, None, None) for _ in requests]
async def run_test():
encoder = FakeEncoder()
scheduler = EncoderScheduler(
encoder=encoder,
send_sockets=[],
max_batch_size=8,
coalesce_same_turn=True,
)
scheduler.start()
try:
requests = [
{
"req_id": f"image-{index}",
"modality": "image",
"mm_items": [object()],
"num_parts": 1,
"part_idx": 0,
}
for index in range(2)
]
results = await asyncio.gather(
*(scheduler.submit(request) for request in requests)
)
finally:
await scheduler.stop()
assert encoder.batches == [["image-0", "image-1"]]
assert results == [(1, 2, 3, None, None)] * 2
asyncio.run(run_test())
@pytest.mark.parametrize(
("model_type", "configured", "explicit", "expected"),
[
("kimi_k3", 8, False, (2, True)),
("kimi_k3", 8, True, (8, True)),
("kimi_k3", 1, False, (1, True)),
("qwen3_vl", 8, False, (8, False)),
],
)
def test_resolve_encoder_batch_policy(model_type, configured, explicit, expected):
assert _resolve_encoder_batch_policy(model_type, configured, explicit) == expected
if __name__ == "__main__":
sys.exit(pytest.main([__file__, "-v"]))