Files
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

221 lines
9.0 KiB
Python

"""
Mixin class providing multiplexing scheduling logic
"""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Optional
import torch
import torch.distributed as dist
from torch.cuda.streams import ExternalStream
from sglang.srt.distributed.parallel_state import set_pdmux_status
from sglang.srt.model_executor.forward_batch_info import ForwardMode
from sglang.srt.multiplex.pdmux_context import (
get_current_stream_idx,
get_sm_counts,
get_stream_groups,
initialize_stream_groups,
load_pdmux_config,
set_current_stream_idx,
)
if TYPE_CHECKING:
from sglang.srt.managers.schedule_batch import ScheduleBatch
from sglang.srt.managers.scheduler import Scheduler
logger = logging.getLogger(__name__)
class SchedulerMultiplexMixin:
def init_pdmux(self: Scheduler):
# The current split prefill batch
self.split_prefill_batch: Optional[ScheduleBatch] = None
# for pd_multiplexing, Init stream_groups, exclude normal stream for prefill only and decode only
self.pdmux_config = load_pdmux_config(self.server_args.pdmux_config_path)
initialize_stream_groups(self.gpu_id, self.pdmux_config)
self.stream_groups = get_stream_groups()
self.sm_counts = get_sm_counts()
self.real_sm_group_num = len(self.stream_groups)
logger.info(
f"PD-Multiplexing enabled with {self.real_sm_group_num} stream groups, sm_counts (prefill_sm, decode_sm): {self.sm_counts}"
)
# TODO(jason-fxz): This is a temporary demo
def adjust_stream_groups(
self: Scheduler,
) -> tuple[int, tuple[ExternalStream, ExternalStream]]:
if not self.running_batch.is_empty() and self.split_prefill_batch:
decode_bs = self.running_batch.batch_size()
manual_divisions = self.pdmux_config.manual_divisions
if manual_divisions:
for i in range(len(manual_divisions)):
_, _, threshold = manual_divisions[i]
if decode_bs >= threshold:
stream_idx = i + 1
else:
stream_idx = max(
1,
min(
self.real_sm_group_num - 2,
decode_bs
* (self.real_sm_group_num - 2)
// self.pdmux_config.decode_bs_divisor,
),
)
set_current_stream_idx(stream_idx)
elif not self.running_batch.is_empty():
set_current_stream_idx(self.real_sm_group_num - 1)
else:
set_current_stream_idx(0)
stream_idx = get_current_stream_idx()
self.tp_worker.model_runner.update_decode_attn_backend(stream_idx)
return stream_idx, self.stream_groups[stream_idx]
def update_split_prefill_batch(self: Scheduler, sm_count: int) -> bool:
if self.split_prefill_batch:
return False
# add new request
prefill_plan = self.get_new_batch_prefill(self.running_batch)
batch = prefill_plan.batch_to_run
self.running_batch = prefill_plan.running_batch
if batch and not batch.is_empty():
batch.forward_mode = (
ForwardMode.SPLIT_PREFILL
) # Set forward mode for split prefill
self.split_prefill_batch = batch
return True
return False
@torch.inference_mode()
def event_loop_pdmux(self: Scheduler):
"""A scheduler loop for pd multiplexing."""
decode_done = False
prefill_done = False
wait_prefill_kernel_done = False
adjust_stream_group = False
stream_idx = get_current_stream_idx()
stream_group = self.stream_groups[stream_idx]
prefill_stream = stream_group[0]
decode_stream = stream_group[1]
torch.cuda.empty_cache()
logger.debug("Starting event loop for pd multiplexing...")
while True:
with torch.cuda.stream(decode_stream):
set_pdmux_status(False)
recv_reqs = self.request_receiver.recv_requests()
self.process_input_requests(recv_reqs)
with torch.cuda.stream(prefill_stream):
set_pdmux_status(True)
sm_count = self.sm_counts[stream_idx][0]
if not wait_prefill_kernel_done:
adjust_stream_group = (
self.update_split_prefill_batch(sm_count) or adjust_stream_group
)
with torch.cuda.stream(decode_stream):
set_pdmux_status(False)
self.running_batch = self.update_running_batch(self.running_batch)
adjust_stream_group = adjust_stream_group or (
stream_idx > 0 and self.running_batch.is_empty()
)
if self.running_batch.is_empty() and self.split_prefill_batch is None:
self.on_idle()
if adjust_stream_group:
prefill_stream.synchronize()
decode_stream.synchronize()
stream_idx, stream_group = self.adjust_stream_groups()
prefill_stream = stream_group[0]
decode_stream = stream_group[1]
adjust_stream_group = False
logger.debug(
f"Adjusting stream groups: {stream_idx}, prefill sm: {self.sm_counts[stream_idx][0]}, decode sm: {self.sm_counts[stream_idx][1]}"
)
with torch.cuda.stream(decode_stream):
set_pdmux_status(False)
# process decode batch
if self.running_batch and not self.running_batch.is_empty():
decode_result = self.run_batch(self.running_batch)
decode_done = True
else:
decode_done = False
with torch.cuda.stream(prefill_stream):
set_pdmux_status(True)
if (
self.split_prefill_batch
and not self.split_prefill_batch.is_empty()
and not wait_prefill_kernel_done
):
prefill_done = True
forward_count = (
max(
1,
self.pdmux_config.split_forward_token_budget
// self.split_prefill_batch.extend_num_tokens,
)
if self.split_prefill_batch.extend_num_tokens > 0
else self.model_config.num_hidden_layers
)
next_split_index = min(
self.split_prefill_batch.split_index + forward_count,
self.model_config.num_hidden_layers,
)
forward_count = (
next_split_index - self.split_prefill_batch.split_index
)
self.split_prefill_batch.split_forward_count = forward_count
prefill_result = self.run_batch(self.split_prefill_batch)
if next_split_index == self.model_config.num_hidden_layers:
self.split_prefill_batch.split_prefill_finished = True
prefill_exe_done = prefill_stream.record_event()
self.split_prefill_batch.split_index = next_split_index
elif wait_prefill_kernel_done:
prefill_done = True
else:
prefill_done = False
with torch.cuda.stream(decode_stream):
set_pdmux_status(False)
decode_stream.synchronize()
if decode_done:
self.process_batch_result(self.running_batch, decode_result)
with torch.cuda.stream(prefill_stream):
set_pdmux_status(True)
if prefill_done and self.split_prefill_batch.split_prefill_finished:
wait_prefill_kernel_done = True
prefill_exe_done_flag = prefill_exe_done.query()
flags = (
torch.ones(1, device="cpu", dtype=torch.int32)
if prefill_exe_done_flag
else torch.zeros(1, device="cpu", dtype=torch.int32)
)
self.tp_cpu_group.allreduce(flags, dist.ReduceOp.SUM).wait()
if flags.item() == self.tp_size:
self.process_batch_result(
self.split_prefill_batch, prefill_result
)
if self.running_batch and not self.running_batch.is_empty():
self.running_batch.merge_batch(self.split_prefill_batch)
else:
self.running_batch = self.split_prefill_batch
self.split_prefill_batch = None
wait_prefill_kernel_done = False
adjust_stream_group = True