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
434 lines
13 KiB
Python
Executable File
434 lines
13 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Test script for validating Mooncake transfer-engine gating and initialization.
|
|
Tests the Mooncake-related branches in the current model-runner flow.
|
|
|
|
This test verifies:
|
|
1. MooncakeTransferEngine initialization conditions
|
|
2. Different server argument combinations that trigger mooncake TE
|
|
3. Mooncake transfer engine initialization with hostname, gpu_id, and ib_device
|
|
|
|
Usage:
|
|
# Run from project root on 2 GPUs
|
|
CUDA_VISIBLE_DEVICES=0,1 python test/manual/kv_transfer/test_mooncake_transfer_engine_init.py
|
|
"""
|
|
|
|
import argparse
|
|
import multiprocessing
|
|
import os
|
|
import sys
|
|
import time
|
|
from dataclasses import dataclass
|
|
from types import SimpleNamespace
|
|
from typing import Optional
|
|
from unittest.mock import patch
|
|
|
|
|
|
@dataclass
|
|
class ServerArgs:
|
|
"""Mock ServerArgs for testing."""
|
|
|
|
disaggregation_mode: str = "null"
|
|
disaggregation_transfer_backend: str = "mooncake"
|
|
enable_hierarchical_cache: bool = False
|
|
hicache_storage_backend: str = "mooncake"
|
|
encoder_only: bool = False
|
|
language_only: bool = False
|
|
encoder_transfer_backend: str = "mooncake"
|
|
enable_elastic_expert_backup: bool = False
|
|
elastic_ep_backend: Optional[str] = None
|
|
disaggregation_ib_device: Optional[str] = None
|
|
mooncake_ib_device: Optional[str] = None
|
|
|
|
|
|
def test_mooncake_te_condition(server_args: ServerArgs) -> bool:
|
|
"""
|
|
Test the condition logic for using MooncakeTransferEngine.
|
|
"""
|
|
from sglang.srt.model_executor.model_runner import ModelRunner
|
|
|
|
dummy_runner = SimpleNamespace(server_args=server_args, gpu_id=0)
|
|
init_called = False
|
|
|
|
def _fake_init_mooncake_transfer_engine(*, hostname, gpu_id, ib_device):
|
|
nonlocal init_called
|
|
init_called = True
|
|
return SimpleNamespace(
|
|
hostname=hostname,
|
|
gpu_id=gpu_id,
|
|
ib_device=ib_device,
|
|
)
|
|
|
|
with (
|
|
patch(
|
|
"sglang.srt.distributed.device_communicators.mooncake_transfer_engine.init_mooncake_transfer_engine",
|
|
side_effect=_fake_init_mooncake_transfer_engine,
|
|
),
|
|
patch(
|
|
"sglang.srt.model_executor.model_runner.get_local_ip_auto",
|
|
return_value="127.0.0.1",
|
|
),
|
|
):
|
|
ModelRunner.init_shared_mooncake_transfer_engine(dummy_runner)
|
|
|
|
return init_called
|
|
|
|
|
|
def run_mooncake_init(
|
|
rank: int,
|
|
world_size: int,
|
|
master_port: int,
|
|
args: argparse.Namespace,
|
|
server_args: ServerArgs,
|
|
):
|
|
"""Worker function for testing mooncake transfer engine initialization."""
|
|
os.environ["CUDA_VISIBLE_DEVICES"] = args.cuda_visible_devices
|
|
os.environ["MASTER_ADDR"] = "127.0.0.1"
|
|
os.environ["MASTER_PORT"] = str(master_port)
|
|
os.environ["RANK"] = str(rank)
|
|
os.environ["WORLD_SIZE"] = str(world_size)
|
|
os.environ["LOCAL_RANK"] = str(rank)
|
|
|
|
# Import before try block to avoid NameError in finally
|
|
import torch
|
|
import torch.distributed as dist
|
|
|
|
dist_initialized = False
|
|
|
|
try:
|
|
# Initialize distributed environment
|
|
print(f"[Rank {rank}] Initializing distributed environment...")
|
|
dist.init_process_group(
|
|
backend="nccl",
|
|
world_size=world_size,
|
|
rank=rank,
|
|
init_method=f"tcp://127.0.0.1:{master_port}",
|
|
device_id=rank,
|
|
)
|
|
dist_initialized = True
|
|
|
|
# Set device
|
|
torch.cuda.set_device(rank)
|
|
|
|
# Sync to ensure all ranks are ready
|
|
dist.barrier()
|
|
print(f"[Rank {rank}] Distributed initialization complete.")
|
|
|
|
# Test the condition logic
|
|
use_mooncake_te = test_mooncake_te_condition(server_args)
|
|
print(f"[Rank {rank}] use_mooncake_te = {use_mooncake_te}")
|
|
|
|
if use_mooncake_te:
|
|
print(f"[Rank {rank}] Attempting to initialize MooncakeTransferEngine...")
|
|
|
|
from sglang.srt.distributed.device_communicators.mooncake_transfer_engine import (
|
|
init_mooncake_transfer_engine,
|
|
)
|
|
from sglang.srt.utils import get_local_ip_auto
|
|
|
|
ib_device = (
|
|
server_args.disaggregation_ib_device or server_args.mooncake_ib_device
|
|
)
|
|
|
|
print(f"[Rank {rank}] IB device: {ib_device}")
|
|
|
|
# Always actually initialize mooncake
|
|
engine = init_mooncake_transfer_engine(
|
|
hostname=get_local_ip_auto(),
|
|
gpu_id=rank,
|
|
ib_device=ib_device,
|
|
)
|
|
print(f"[Rank {rank}] Session ID: {engine.get_session_id()}")
|
|
print(f"[Rank {rank}] MooncakeTransferEngine initialized successfully!")
|
|
|
|
dist.barrier()
|
|
|
|
print(f"[Rank {rank}] Test completed successfully!")
|
|
sys.exit(0)
|
|
|
|
except ImportError as e:
|
|
print(f"[Rank {rank}] Mooncake not available (ImportError): {e}")
|
|
sys.exit(1)
|
|
|
|
except Exception as e:
|
|
print(f"[Rank {rank}] Test failed with error: {e}")
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
finally:
|
|
# Cleanup
|
|
if dist_initialized and dist.is_initialized():
|
|
dist.destroy_process_group()
|
|
print(f"[Rank {rank}] Process group destroyed.")
|
|
|
|
|
|
def run_test(args: argparse.Namespace, server_args: ServerArgs) -> bool:
|
|
"""Run the mooncake transfer engine test."""
|
|
# Set CUDA visible devices
|
|
cuda_devices = args.cuda_visible_devices.split(",")
|
|
world_size = len(cuda_devices)
|
|
|
|
if world_size < 2:
|
|
print("ERROR: This test requires at least 2 GPUs.")
|
|
print(
|
|
"Usage: CUDA_VISIBLE_DEVICES=0,1 python test/manual/kv_transfer/test_mooncake_transfer_engine_init.py"
|
|
)
|
|
sys.exit(1)
|
|
|
|
# Check GPU availability
|
|
import torch
|
|
|
|
if not torch.cuda.is_available():
|
|
print("ERROR: CUDA is not available")
|
|
sys.exit(1)
|
|
|
|
available_gpus = torch.cuda.device_count()
|
|
if world_size > available_gpus:
|
|
print(f"ERROR: Requested {world_size} GPUs but only {available_gpus} available")
|
|
sys.exit(1)
|
|
|
|
print(f"Testing with {world_size} GPUs: {cuda_devices}")
|
|
print()
|
|
|
|
# Print server args configuration
|
|
print("ServerArgs configuration:")
|
|
for key, value in vars(server_args).items():
|
|
print(f" {key}: {value}")
|
|
print()
|
|
|
|
# Check if mooncake should be used
|
|
use_mooncake_te = test_mooncake_te_condition(server_args)
|
|
print(f"use_mooncake_te = {use_mooncake_te}")
|
|
print()
|
|
|
|
# Find a free port
|
|
import socket
|
|
|
|
with socket.socket() as s:
|
|
s.bind(("", 0))
|
|
master_port = s.getsockname()[1]
|
|
|
|
print(f"Using master port: {master_port}")
|
|
|
|
# Spawn worker processes
|
|
ctx = multiprocessing.get_context("spawn")
|
|
processes = []
|
|
|
|
for rank in range(world_size):
|
|
p = ctx.Process(
|
|
target=run_mooncake_init,
|
|
args=(rank, world_size, master_port, args, server_args),
|
|
)
|
|
p.start()
|
|
processes.append(p)
|
|
|
|
# Wait for all processes to complete
|
|
success = True
|
|
for i, p in enumerate(processes):
|
|
p.join(timeout=60)
|
|
if p.exitcode != 0:
|
|
print(f"Process {i} failed with exit code: {p.exitcode}")
|
|
success = False
|
|
|
|
# Cleanup any remaining processes
|
|
for p in processes:
|
|
if p.is_alive():
|
|
print(f"Process {p.pid} is still alive, terminating...")
|
|
p.terminate()
|
|
p.join(timeout=5)
|
|
|
|
return success
|
|
|
|
|
|
def test_condition_logic():
|
|
"""Test the condition logic for different server argument combinations."""
|
|
print("=" * 60)
|
|
print("Testing condition logic for use_mooncake_te")
|
|
print("=" * 60)
|
|
print()
|
|
|
|
original_hicache_reuse = os.environ.get("SGLANG_HICACHE_MOONCAKE_REUSE_TE")
|
|
passed = 0
|
|
failed = 0
|
|
|
|
try:
|
|
test_cases = [
|
|
# (name, env_value, server_args, expected_result)
|
|
(
|
|
"PD disaggregation with mooncake",
|
|
None,
|
|
ServerArgs(
|
|
disaggregation_mode="prefill",
|
|
disaggregation_transfer_backend="mooncake",
|
|
),
|
|
True,
|
|
),
|
|
(
|
|
"PD disaggregation without mooncake",
|
|
None,
|
|
ServerArgs(
|
|
disaggregation_mode="prefill",
|
|
disaggregation_transfer_backend="other",
|
|
),
|
|
False,
|
|
),
|
|
(
|
|
"No disaggregation",
|
|
None,
|
|
ServerArgs(),
|
|
False,
|
|
),
|
|
(
|
|
"HiCache with mooncake (env=False)",
|
|
"0",
|
|
ServerArgs(
|
|
enable_hierarchical_cache=True,
|
|
hicache_storage_backend="mooncake",
|
|
),
|
|
False,
|
|
),
|
|
(
|
|
"HiCache with mooncake (env=True)",
|
|
"1",
|
|
ServerArgs(
|
|
enable_hierarchical_cache=True,
|
|
hicache_storage_backend="mooncake",
|
|
),
|
|
True,
|
|
),
|
|
(
|
|
"Encoder only with mooncake",
|
|
None,
|
|
ServerArgs(encoder_only=True, encoder_transfer_backend="mooncake"),
|
|
True,
|
|
),
|
|
(
|
|
"Language only with mooncake",
|
|
None,
|
|
ServerArgs(language_only=True, encoder_transfer_backend="mooncake"),
|
|
True,
|
|
),
|
|
(
|
|
"Elastic expert backup with backend",
|
|
None,
|
|
ServerArgs(
|
|
enable_elastic_expert_backup=True,
|
|
elastic_ep_backend="mooncake",
|
|
),
|
|
True,
|
|
),
|
|
(
|
|
"Elastic expert backup without backend",
|
|
None,
|
|
ServerArgs(enable_elastic_expert_backup=True, elastic_ep_backend=None),
|
|
False,
|
|
),
|
|
]
|
|
|
|
for name, env_value, server_args, expected in test_cases:
|
|
if env_value is None:
|
|
os.environ.pop("SGLANG_HICACHE_MOONCAKE_REUSE_TE", None)
|
|
else:
|
|
os.environ["SGLANG_HICACHE_MOONCAKE_REUSE_TE"] = env_value
|
|
|
|
result = test_mooncake_te_condition(server_args)
|
|
status = "PASS" if result == expected else "FAIL"
|
|
|
|
if result == expected:
|
|
passed += 1
|
|
else:
|
|
failed += 1
|
|
|
|
print(f"{status}: {name}")
|
|
print(f" Expected: {expected}, Got: {result}")
|
|
print()
|
|
finally:
|
|
if original_hicache_reuse is None:
|
|
os.environ.pop("SGLANG_HICACHE_MOONCAKE_REUSE_TE", None)
|
|
else:
|
|
os.environ["SGLANG_HICACHE_MOONCAKE_REUSE_TE"] = original_hicache_reuse
|
|
|
|
print(f"Condition logic tests: {passed} passed, {failed} failed")
|
|
print()
|
|
|
|
return failed == 0
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Validate Mooncake transfer-engine gating and initialization"
|
|
)
|
|
parser.add_argument(
|
|
"--cuda-visible-devices",
|
|
type=str,
|
|
default="0,1",
|
|
help="CUDA visible devices (default: 0,1)",
|
|
)
|
|
parser.add_argument(
|
|
"--test-case",
|
|
type=str,
|
|
choices=[
|
|
"pd_disaggregation",
|
|
"hicache",
|
|
"encoder_only",
|
|
"language_only",
|
|
"elastic_ep",
|
|
],
|
|
default="pd_disaggregation",
|
|
help="Test case to run",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
print("=" * 60)
|
|
print("Mooncake Transfer Engine Init Test")
|
|
print("=" * 60)
|
|
print()
|
|
|
|
# First run condition logic tests
|
|
condition_passed = test_condition_logic()
|
|
|
|
if not condition_passed:
|
|
print("Condition logic tests failed, skipping distributed test.")
|
|
sys.exit(1)
|
|
|
|
# Configure server args based on test case
|
|
server_args = ServerArgs()
|
|
|
|
if args.test_case == "pd_disaggregation":
|
|
server_args.disaggregation_mode = "prefill"
|
|
server_args.disaggregation_transfer_backend = "mooncake"
|
|
elif args.test_case == "hicache":
|
|
server_args.enable_hierarchical_cache = True
|
|
server_args.hicache_storage_backend = "mooncake"
|
|
os.environ["SGLANG_HICACHE_MOONCAKE_REUSE_TE"] = "1"
|
|
elif args.test_case == "encoder_only":
|
|
server_args.encoder_only = True
|
|
server_args.encoder_transfer_backend = "mooncake"
|
|
elif args.test_case == "language_only":
|
|
server_args.language_only = True
|
|
server_args.encoder_transfer_backend = "mooncake"
|
|
elif args.test_case == "elastic_ep":
|
|
server_args.enable_elastic_expert_backup = True
|
|
server_args.elastic_ep_backend = "mooncake"
|
|
|
|
start_time = time.time()
|
|
success = run_test(args, server_args)
|
|
elapsed_time = time.time() - start_time
|
|
|
|
print()
|
|
print("=" * 60)
|
|
if success:
|
|
print(f"TEST PASSED (elapsed: {elapsed_time:.2f}s)")
|
|
else:
|
|
print(f"TEST FAILED (elapsed: {elapsed_time:.2f}s)")
|
|
print("=" * 60)
|
|
|
|
sys.exit(0 if success else 1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|