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
187 lines
6.5 KiB
Python
187 lines
6.5 KiB
Python
import logging
|
|
import time
|
|
from typing import TYPE_CHECKING, List
|
|
|
|
import torch.cuda
|
|
|
|
from sglang.srt.environ import envs
|
|
from sglang.srt.eplb.expert_distribution import get_global_expert_distribution_recorder
|
|
from sglang.srt.eplb.expert_location import (
|
|
ExpertLocationMetadata,
|
|
format_expert_location_layout,
|
|
format_expert_location_layout_diff,
|
|
get_global_expert_location_metadata,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from sglang.srt.model_executor.model_runner import ModelRunner
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class EPLBManager:
|
|
def __init__(self, model_runner: "ModelRunner"):
|
|
super().__init__()
|
|
self._model_runner = model_runner
|
|
self._server_args = model_runner.server_args
|
|
self._rebalance_layers_per_chunk = (
|
|
self._server_args.eplb_rebalance_layers_per_chunk
|
|
)
|
|
self._rebalance_num_iterations = self._server_args.eplb_rebalance_num_iterations
|
|
|
|
# Otherwise, the circular buffer will contain stale data. If the case is needed, it can be implemented.
|
|
assert (
|
|
self._server_args.eplb_rebalance_num_iterations
|
|
>= self._server_args.expert_distribution_recorder_buffer_size
|
|
), "eplb_rebalance_num_iterations must be greater than expert_distribution_recorder_buffer_size"
|
|
|
|
if not get_global_expert_distribution_recorder().recording:
|
|
get_global_expert_distribution_recorder().start_record()
|
|
|
|
logger.info(
|
|
f"[EPLBManager] system started, will rebalance per {self._rebalance_num_iterations} iterations."
|
|
)
|
|
|
|
self._main_generator = self._entrypoint()
|
|
|
|
def on_forward_pass_end(self):
|
|
next(self._main_generator)
|
|
|
|
def reset_generator(self):
|
|
self._main_generator = self._entrypoint()
|
|
|
|
# can be more complex if needed
|
|
def _entrypoint(self):
|
|
while True:
|
|
for _ in range(self._rebalance_num_iterations):
|
|
yield
|
|
|
|
yield from self.rebalance()
|
|
|
|
def rebalance(self):
|
|
logger.info("[EPLBManager] rebalance start")
|
|
|
|
enable_timing = self._rebalance_layers_per_chunk is None
|
|
|
|
if enable_timing:
|
|
torch.get_device_module().synchronize()
|
|
time_start = time.time()
|
|
|
|
dump_record_output = get_global_expert_distribution_recorder().dump_record(
|
|
output_mode="object"
|
|
)
|
|
logical_count = dump_record_output["logical_count"]
|
|
average_utilization_rate_over_window = dump_record_output[
|
|
"average_utilization_rate_over_window"
|
|
]
|
|
|
|
# Check whether rebalancing is needed
|
|
if not self._check_rebalance_needed(average_utilization_rate_over_window):
|
|
return
|
|
|
|
expert_location_metadata = ExpertLocationMetadata.init_by_eplb(
|
|
self._server_args, self._model_runner.model_config, logical_count
|
|
)
|
|
|
|
update_layer_ids_chunks = self._compute_update_layer_ids_chunks()
|
|
all_update_layer_ids = [
|
|
layer_id for chunk in update_layer_ids_chunks for layer_id in chunk
|
|
]
|
|
self._log_rebalance_layout_before_update(
|
|
expert_location_metadata,
|
|
update_layer_ids=all_update_layer_ids,
|
|
)
|
|
for chunk_layer_ids in update_layer_ids_chunks:
|
|
if len(update_layer_ids_chunks) > 1:
|
|
yield
|
|
self._model_runner.update_expert_location(
|
|
expert_location_metadata,
|
|
update_layer_ids=chunk_layer_ids,
|
|
)
|
|
|
|
self._log_rebalance_layout_after_update(update_layer_ids=all_update_layer_ids)
|
|
|
|
msg = f"[EPLBManager] rebalance end"
|
|
if enable_timing:
|
|
torch.get_device_module().synchronize()
|
|
time_end = time.time()
|
|
msg += f" time={time_end - time_start:.3f}s"
|
|
logger.info(msg)
|
|
|
|
def _check_rebalance_needed(self, average_utilization_rate_over_window):
|
|
if average_utilization_rate_over_window is None:
|
|
return True
|
|
|
|
if (
|
|
average_utilization_rate_over_window
|
|
> self._server_args.eplb_min_rebalancing_utilization_threshold
|
|
):
|
|
logger.info(
|
|
f"[EPLBManager] Skipped ep rebalancing: current GPU utilization {average_utilization_rate_over_window:.2f} > minimum rebalance threshold {self._server_args.eplb_min_rebalancing_utilization_threshold:.2f}"
|
|
)
|
|
return False
|
|
|
|
return True
|
|
|
|
def _compute_update_layer_ids_chunks(self) -> List[List[int]]:
|
|
all_layer_ids = sorted(
|
|
list(self._model_runner.model.routed_experts_weights_of_layer.keys())
|
|
)
|
|
chunk_size = self._rebalance_layers_per_chunk or 1000000
|
|
return list(_chunk_list(all_layer_ids, chunk_size=chunk_size))
|
|
|
|
def _should_log_expert_location_metadata(self) -> bool:
|
|
return (
|
|
self._model_runner.tp_rank == 0
|
|
and envs.SGLANG_LOG_EXPERT_LOCATION_METADATA.get()
|
|
)
|
|
|
|
def _log_rebalance_layout_before_update(
|
|
self,
|
|
new_expert_location_metadata: ExpertLocationMetadata,
|
|
update_layer_ids: List[int],
|
|
):
|
|
if not self._should_log_expert_location_metadata():
|
|
return
|
|
|
|
old_expert_location_metadata = get_global_expert_location_metadata()
|
|
logger.info(
|
|
"[EPLBManager] rebalance layout before:\n%s",
|
|
format_expert_location_layout(
|
|
old_expert_location_metadata,
|
|
layer_ids=update_layer_ids,
|
|
),
|
|
)
|
|
logger.info(
|
|
"[EPLBManager] rebalance layout target:\n%s",
|
|
format_expert_location_layout(
|
|
new_expert_location_metadata,
|
|
layer_ids=update_layer_ids,
|
|
),
|
|
)
|
|
logger.info(
|
|
"[EPLBManager] rebalance layout diff:\n%s",
|
|
format_expert_location_layout_diff(
|
|
old_expert_location_metadata,
|
|
new_expert_location_metadata,
|
|
layer_ids=update_layer_ids,
|
|
),
|
|
)
|
|
|
|
def _log_rebalance_layout_after_update(self, update_layer_ids: List[int]):
|
|
if not self._should_log_expert_location_metadata():
|
|
return
|
|
|
|
logger.info(
|
|
"[EPLBManager] rebalance layout after:\n%s",
|
|
format_expert_location_layout(
|
|
get_global_expert_location_metadata(),
|
|
layer_ids=update_layer_ids,
|
|
),
|
|
)
|
|
|
|
|
|
def _chunk_list(items: List, chunk_size):
|
|
for start_index in range(0, len(items), chunk_size):
|
|
yield items[start_index : start_index + chunk_size]
|