refactor: add type hints to scheduler mixins (#15913)

This commit is contained in:
Cheng Wan
2025-12-26 16:50:07 -08:00
committed by GitHub
parent 93495dcac9
commit 988b14ca0e
5 changed files with 42 additions and 22 deletions
@@ -111,7 +111,7 @@ class SchedulerMetricsMixin:
self.spec_num_forward_ct += bs self.spec_num_forward_ct += bs
self.num_generated_tokens += num_accepted_tokens self.num_generated_tokens += num_accepted_tokens
def reset_metrics(self): def reset_metrics(self: Scheduler):
self.forward_ct_decode = 0 self.forward_ct_decode = 0
self.num_generated_tokens = 0 self.num_generated_tokens = 0
self.spec_num_accepted_tokens = 0 self.spec_num_accepted_tokens = 0
@@ -512,7 +512,7 @@ class SchedulerMetricsMixin:
except Exception as e: except Exception as e:
logger.warning(f"Failed to update LoRA metrics: {e}") logger.warning(f"Failed to update LoRA metrics: {e}")
def calculate_utilization(self): def calculate_utilization(self: Scheduler):
if self.disaggregation_mode == DisaggregationMode.PREFILL: if self.disaggregation_mode == DisaggregationMode.PREFILL:
self.stats.utilization = -1 self.stats.utilization = -1
else: else:
@@ -556,7 +556,7 @@ class SchedulerMetricsMixin:
) )
@contextmanager @contextmanager
def record_forward_metrics(self: Scheduler, batch): def record_forward_metrics(self: Scheduler, batch: ScheduleBatch):
if not (self.enable_metrics and ENABLE_METRICS_DEVICE_TIMER): if not (self.enable_metrics and ENABLE_METRICS_DEVICE_TIMER):
yield yield
return return
@@ -666,7 +666,7 @@ class SchedulerPPMixin:
f"Target latency: {self.length_predictor.target_latency:.2f}ms" f"Target latency: {self.length_predictor.target_latency:.2f}ms"
) )
def predict_next_chunk_size(self: "Scheduler", history_len: int) -> Optional[int]: def predict_next_chunk_size(self: Scheduler, history_len: int) -> Optional[int]:
""" """
Predict next chunk size dynamically based on current history length. Predict next chunk size dynamically based on current history length.
@@ -2,7 +2,7 @@ import logging
import os import os
import time import time
from pathlib import Path from pathlib import Path
from typing import List, Optional from typing import TYPE_CHECKING, List, Optional
import torch import torch
@@ -14,6 +14,10 @@ from sglang.srt.utils import is_npu
from sglang.srt.utils.profile_merger import ProfileMerger from sglang.srt.utils.profile_merger import ProfileMerger
from sglang.srt.utils.profile_utils import ProfileManager from sglang.srt.utils.profile_utils import ProfileManager
if TYPE_CHECKING:
from sglang.srt.managers.schedule_batch import ScheduleBatch
from sglang.srt.managers.scheduler import Scheduler
_is_npu = is_npu() _is_npu = is_npu()
if _is_npu: if _is_npu:
import torch_npu import torch_npu
@@ -29,7 +33,7 @@ logger = logging.getLogger(__name__)
class SchedulerProfilerMixin: class SchedulerProfilerMixin:
def init_profiler(self): def init_profiler(self: Scheduler):
if envs.SGLANG_PROFILE_V2.get(): if envs.SGLANG_PROFILE_V2.get():
self._profile_manager = ProfileManager( self._profile_manager = ProfileManager(
tp_rank=self.tp_rank, tp_rank=self.tp_rank,
@@ -59,7 +63,7 @@ class SchedulerProfilerMixin:
self.rpd_profiler = None self.rpd_profiler = None
def init_profile( def init_profile(
self, self: Scheduler,
output_dir: Optional[str], output_dir: Optional[str],
start_step: Optional[int], start_step: Optional[int],
num_steps: Optional[int], num_steps: Optional[int],
@@ -130,7 +134,7 @@ class SchedulerProfilerMixin:
return ProfileReqOutput(success=True, message="Succeeded") return ProfileReqOutput(success=True, message="Succeeded")
def start_profile( def start_profile(
self, stage: Optional[ForwardMode] = None self: Scheduler, stage: Optional[ForwardMode] = None
) -> ProfileReqOutput | None: ) -> ProfileReqOutput | None:
if envs.SGLANG_PROFILE_V2.get(): if envs.SGLANG_PROFILE_V2.get():
return self._profile_manager.manual_start() return self._profile_manager.manual_start()
@@ -208,7 +212,7 @@ class SchedulerProfilerMixin:
return ProfileReqOutput(success=True, message="Succeeded") return ProfileReqOutput(success=True, message="Succeeded")
def _merge_profile_traces(self) -> str: def _merge_profile_traces(self: Scheduler) -> str:
if not self.merge_profiles: if not self.merge_profiles:
return "" return ""
@@ -241,7 +245,7 @@ class SchedulerProfilerMixin:
return merge_message return merge_message
def stop_profile( def stop_profile(
self, stage: Optional[ForwardMode] = None self: Scheduler, stage: Optional[ForwardMode] = None
) -> ProfileReqOutput | None: ) -> ProfileReqOutput | None:
if envs.SGLANG_PROFILE_V2.get(): if envs.SGLANG_PROFILE_V2.get():
return self._profile_manager.manual_stop() return self._profile_manager.manual_stop()
@@ -328,7 +332,7 @@ class SchedulerProfilerMixin:
return ProfileReqOutput(success=True, message=f"Succeeded.{merge_message}") return ProfileReqOutput(success=True, message=f"Succeeded.{merge_message}")
def _profile_batch_predicate(self, batch): def _profile_batch_predicate(self: Scheduler, batch: ScheduleBatch):
if envs.SGLANG_PROFILE_V2.get(): if envs.SGLANG_PROFILE_V2.get():
self._profile_manager.step(forward_mode=batch.forward_mode) self._profile_manager.step(forward_mode=batch.forward_mode)
return return
@@ -368,7 +372,7 @@ class SchedulerProfilerMixin:
): ):
self.start_profile() self.start_profile()
def profile(self, recv_req: ProfileReq): def profile(self: Scheduler, recv_req: ProfileReq):
if recv_req.type == ProfileReqType.START_PROFILE: if recv_req.type == ProfileReqType.START_PROFILE:
if recv_req.profile_by_stage or recv_req.start_step: if recv_req.profile_by_stage or recv_req.start_step:
return self.init_profile( return self.init_profile(
@@ -43,7 +43,9 @@ logger = logging.getLogger(__name__)
class SchedulerUpdateWeightsMixin: class SchedulerUpdateWeightsMixin:
def update_weights_from_disk(self, recv_req: UpdateWeightFromDiskReqInput): def update_weights_from_disk(
self: Scheduler, recv_req: UpdateWeightFromDiskReqInput
):
"""In-place update of the weights from disk.""" """In-place update of the weights from disk."""
success, message = self.tp_worker.update_weights_from_disk(recv_req) success, message = self.tp_worker.update_weights_from_disk(recv_req)
if success: if success:
@@ -54,12 +56,16 @@ class SchedulerUpdateWeightsMixin:
logger.error(message) logger.error(message)
return UpdateWeightFromDiskReqOutput(success, message, 0) return UpdateWeightFromDiskReqOutput(success, message, 0)
def init_weights_update_group(self, recv_req: InitWeightsUpdateGroupReqInput): def init_weights_update_group(
self: Scheduler, recv_req: InitWeightsUpdateGroupReqInput
):
"""Initialize the online model parameter update group.""" """Initialize the online model parameter update group."""
success, message = self.tp_worker.init_weights_update_group(recv_req) success, message = self.tp_worker.init_weights_update_group(recv_req)
return InitWeightsUpdateGroupReqOutput(success, message) return InitWeightsUpdateGroupReqOutput(success, message)
def destroy_weights_update_group(self, recv_req: DestroyWeightsUpdateGroupReqInput): def destroy_weights_update_group(
self: Scheduler, recv_req: DestroyWeightsUpdateGroupReqInput
):
"""Destroy the online model parameter update group.""" """Destroy the online model parameter update group."""
success, message = self.tp_worker.destroy_weights_update_group(recv_req) success, message = self.tp_worker.destroy_weights_update_group(recv_req)
return DestroyWeightsUpdateGroupReqOutput(success, message) return DestroyWeightsUpdateGroupReqOutput(success, message)
@@ -78,7 +84,9 @@ class SchedulerUpdateWeightsMixin:
logger.error(message) logger.error(message)
return UpdateWeightsFromDistributedReqOutput(success, message) return UpdateWeightsFromDistributedReqOutput(success, message)
def update_weights_from_tensor(self, recv_req: UpdateWeightsFromTensorReqInput): def update_weights_from_tensor(
self: Scheduler, recv_req: UpdateWeightsFromTensorReqInput
):
"""Update the online model parameter from tensors.""" """Update the online model parameter from tensors."""
worker = self.draft_worker or self.tp_worker worker = self.draft_worker or self.tp_worker
success, message = worker.update_weights_from_tensor(recv_req) success, message = worker.update_weights_from_tensor(recv_req)
@@ -92,7 +100,9 @@ class SchedulerUpdateWeightsMixin:
torch.distributed.barrier(group=self.tp_cpu_group) torch.distributed.barrier(group=self.tp_cpu_group)
return UpdateWeightsFromTensorReqOutput(success, message) return UpdateWeightsFromTensorReqOutput(success, message)
def update_weights_from_ipc(self, recv_req: UpdateWeightsFromIPCReqInput): def update_weights_from_ipc(
self: Scheduler, recv_req: UpdateWeightsFromIPCReqInput
):
"""Update the online model parameter from IPC for checkpoint-engine integration.""" """Update the online model parameter from IPC for checkpoint-engine integration."""
success, message = self.tp_worker.update_weights_from_ipc(recv_req) success, message = self.tp_worker.update_weights_from_ipc(recv_req)
if success: if success:
@@ -104,7 +114,7 @@ class SchedulerUpdateWeightsMixin:
torch.distributed.barrier(group=self.tp_cpu_group) torch.distributed.barrier(group=self.tp_cpu_group)
return UpdateWeightsFromIPCReqOutput(success, message) return UpdateWeightsFromIPCReqOutput(success, message)
def get_weights_by_name(self, recv_req: GetWeightsByNameReqInput): def get_weights_by_name(self: Scheduler, recv_req: GetWeightsByNameReqInput):
parameter = self.tp_worker.get_weights_by_name(recv_req) parameter = self.tp_worker.get_weights_by_name(recv_req)
return GetWeightsByNameReqOutput(parameter) return GetWeightsByNameReqOutput(parameter)
@@ -3,6 +3,7 @@ Mixin class providing multiplexing scheduling logic
""" """
import logging import logging
from typing import TYPE_CHECKING
import torch import torch
import torch.distributed as dist import torch.distributed as dist
@@ -19,12 +20,15 @@ from sglang.srt.multiplex.pdmux_context import (
set_current_stream_idx, set_current_stream_idx,
) )
if TYPE_CHECKING:
from sglang.srt.managers.scheduler import Scheduler
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class SchedulerMultiplexMixin: class SchedulerMultiplexMixin:
def init_pdmux(self): def init_pdmux(self: Scheduler):
# for pd_multiplexing, Init stream_groups, exclude normal stream for prefill only and decode only # 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) self.pdmux_config = load_pdmux_config(self.server_args.pdmux_config_path)
initialize_stream_groups(self.gpu_id, self.pdmux_config) initialize_stream_groups(self.gpu_id, self.pdmux_config)
@@ -36,7 +40,9 @@ class SchedulerMultiplexMixin:
) )
# TODO(jason-fxz): This is a temporary demo # TODO(jason-fxz): This is a temporary demo
def adjust_stream_groups(self) -> tuple[int, tuple[ExternalStream, ExternalStream]]: def adjust_stream_groups(
self: Scheduler,
) -> tuple[int, tuple[ExternalStream, ExternalStream]]:
if not self.running_batch.is_empty() and self.split_prefill_batch: if not self.running_batch.is_empty() and self.split_prefill_batch:
decode_bs = self.running_batch.batch_size() decode_bs = self.running_batch.batch_size()
manual_divisions = self.pdmux_config.manual_divisions manual_divisions = self.pdmux_config.manual_divisions
@@ -66,7 +72,7 @@ class SchedulerMultiplexMixin:
self.tp_worker.model_runner.update_decode_attn_backend(stream_idx) self.tp_worker.model_runner.update_decode_attn_backend(stream_idx)
return stream_idx, self.stream_groups[stream_idx] return stream_idx, self.stream_groups[stream_idx]
def update_split_prefill_batch(self, sm_count: int) -> bool: def update_split_prefill_batch(self: Scheduler, sm_count: int) -> bool:
if self.split_prefill_batch: if self.split_prefill_batch:
return False return False
@@ -81,7 +87,7 @@ class SchedulerMultiplexMixin:
return False return False
@torch.inference_mode() @torch.inference_mode()
def event_loop_pdmux(self): def event_loop_pdmux(self: Scheduler):
"""A scheduler loop for pd multiplexing.""" """A scheduler loop for pd multiplexing."""
decode_done = False decode_done = False
prefill_done = False prefill_done = False