sgl-project--sglang
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
238 行
7.8 KiB
Python
238 行
7.8 KiB
Python
"""Test tracing in PD disaggregation mode."""
|
|
|
|
import os
|
|
|
|
# Configure OTLP exporter for faster test execution
|
|
# Must be set before importing sglang trace module
|
|
os.environ.setdefault("SGLANG_OTLP_EXPORTER_SCHEDULE_DELAY_MILLIS", "50")
|
|
os.environ.setdefault("SGLANG_OTLP_EXPORTER_MAX_EXPORT_BATCH_SIZE", "4")
|
|
|
|
import logging
|
|
import shlex
|
|
import time
|
|
import unittest
|
|
from urllib.parse import urlparse
|
|
|
|
import requests
|
|
|
|
from sglang.srt.observability.mooncake_trace import MooncakeRequestStage
|
|
from sglang.srt.observability.req_time_stats import RequestStage
|
|
from sglang.srt.utils import kill_process_tree
|
|
from sglang.test.ci.ci_register import register_cuda_ci
|
|
from sglang.test.otel_collector import LightweightOtlpCollector
|
|
from sglang.test.server_fixtures.disaggregation_fixture import get_rdma_devices_args
|
|
from sglang.test.test_utils import (
|
|
DEFAULT_MODEL_NAME_FOR_TEST,
|
|
DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
|
DEFAULT_URL_FOR_TEST,
|
|
CustomTestCase,
|
|
popen_launch_pd_server,
|
|
popen_with_error_check,
|
|
)
|
|
from sglang.utils import wait_for_http_ready
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# CI registration - PD disaggregation requires 2 GPUs
|
|
register_cuda_ci(est_time=65, stage="base-b", runner_config="2-gpu-large")
|
|
|
|
|
|
class TestTraceDisaggregation(CustomTestCase):
|
|
"""Test tracing in PD disaggregation mode."""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
# Initialize collector first
|
|
cls.collector = LightweightOtlpCollector()
|
|
cls.collector.start()
|
|
time.sleep(0.2)
|
|
|
|
# Setup PD disaggregation server addresses
|
|
parsed_url = urlparse(DEFAULT_URL_FOR_TEST)
|
|
cls.base_host = parsed_url.hostname
|
|
base_port = str(parsed_url.port)
|
|
cls.lb_port = base_port
|
|
cls.prefill_port = f"{int(base_port) + 100}"
|
|
cls.decode_port = f"{int(base_port) + 200}"
|
|
cls.bootstrap_port = f"{int(base_port) + 500}"
|
|
cls.prefill_url = f"http://{cls.base_host}:{cls.prefill_port}"
|
|
cls.decode_url = f"http://{cls.base_host}:{cls.decode_port}"
|
|
cls.lb_url = f"http://{cls.base_host}:{cls.lb_port}"
|
|
cls.process_lb = None
|
|
cls.process_decode = None
|
|
cls.process_prefill = None
|
|
cls.model = DEFAULT_MODEL_NAME_FOR_TEST
|
|
|
|
# Config transfer backend
|
|
cls.transfer_backend = ["--disaggregation-transfer-backend", "mooncake"]
|
|
cls.rdma_devices = ["--disaggregation-ib-device", get_rdma_devices_args()]
|
|
|
|
# Start prefill server with trace enabled
|
|
prefill_args = [
|
|
"--trust-remote-code",
|
|
"--disaggregation-mode",
|
|
"prefill",
|
|
"--disaggregation-bootstrap-port",
|
|
cls.bootstrap_port,
|
|
"--tp",
|
|
"1",
|
|
"--enable-trace",
|
|
"--otlp-traces-endpoint",
|
|
"localhost:4317",
|
|
"--trace-modules",
|
|
"request,mooncake",
|
|
]
|
|
prefill_args += cls.transfer_backend + cls.rdma_devices
|
|
cls.process_prefill = popen_launch_pd_server(
|
|
cls.model,
|
|
cls.prefill_url,
|
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
|
other_args=prefill_args,
|
|
)
|
|
|
|
# Start decode server with trace enabled
|
|
decode_args = [
|
|
"--trust-remote-code",
|
|
"--disaggregation-mode",
|
|
"decode",
|
|
"--disaggregation-bootstrap-port",
|
|
cls.bootstrap_port,
|
|
"--tp",
|
|
"1",
|
|
"--base-gpu-id",
|
|
"1",
|
|
"--enable-trace",
|
|
"--otlp-traces-endpoint",
|
|
"localhost:4317",
|
|
]
|
|
decode_args += cls.transfer_backend + cls.rdma_devices
|
|
cls.process_decode = popen_launch_pd_server(
|
|
cls.model,
|
|
cls.decode_url,
|
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
|
other_args=decode_args,
|
|
)
|
|
|
|
# Wait for servers to be ready
|
|
wait_for_http_ready(
|
|
url=cls.prefill_url + "/health",
|
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
|
process=cls.process_prefill,
|
|
)
|
|
wait_for_http_ready(
|
|
url=cls.decode_url + "/health",
|
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
|
process=cls.process_decode,
|
|
)
|
|
|
|
# Start load balancer
|
|
lb_command = [
|
|
"python3",
|
|
"-m",
|
|
"sglang_router.launch_router",
|
|
"--pd-disaggregation",
|
|
"--mini-lb",
|
|
"--prefill",
|
|
cls.prefill_url,
|
|
"--decode",
|
|
cls.decode_url,
|
|
"--host",
|
|
cls.base_host,
|
|
"--port",
|
|
cls.lb_port,
|
|
]
|
|
print("Starting load balancer:", shlex.join(lb_command))
|
|
cls.process_lb = popen_with_error_check(lb_command)
|
|
wait_for_http_ready(url=cls.lb_url + "/health", process=cls.process_lb)
|
|
|
|
# Wait for warmup spans and clear
|
|
time.sleep(1)
|
|
cls.collector.clear()
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
for process in [cls.process_lb, cls.process_decode, cls.process_prefill]:
|
|
if process:
|
|
try:
|
|
kill_process_tree(process.pid)
|
|
except Exception as e:
|
|
print(f"Error killing process {process.pid}: {e}")
|
|
if cls.collector:
|
|
cls.collector.stop()
|
|
time.sleep(5)
|
|
|
|
def setUp(self):
|
|
"""Wait for spans to be drained before each test."""
|
|
max_wait_seconds = 10
|
|
check_interval = 0.2
|
|
elapsed = 0
|
|
consecutive_zero_count = 0
|
|
required_consecutive_zeros = 3
|
|
|
|
while elapsed < max_wait_seconds:
|
|
span_count = self.collector.count_spans()
|
|
if span_count == 0:
|
|
consecutive_zero_count += 1
|
|
if consecutive_zero_count >= required_consecutive_zeros:
|
|
break
|
|
else:
|
|
consecutive_zero_count = 0
|
|
self.collector.clear()
|
|
time.sleep(check_interval)
|
|
elapsed += check_interval
|
|
else:
|
|
raise RuntimeError(
|
|
f"Timeout waiting for spans to drain after {max_wait_seconds}s. "
|
|
f"Remaining spans: {self.collector.count_spans()}"
|
|
)
|
|
|
|
def test_disaggregation_transfer_spans(self):
|
|
"""Test that disaggregation produces PREFILL_TRANSFER_KV_CACHE and DECODE_TRANSFERRED spans."""
|
|
# Set trace level
|
|
response = requests.get(f"{self.prefill_url}/set_trace_level?level=2")
|
|
self.assertEqual(response.status_code, 200)
|
|
self.collector.clear()
|
|
|
|
# Send a request through load balancer
|
|
response = requests.post(
|
|
f"{self.lb_url}/generate",
|
|
json={
|
|
"text": "The capital of France is",
|
|
"sampling_params": {
|
|
"temperature": 0,
|
|
"max_new_tokens": 10,
|
|
},
|
|
"stream": False,
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Wait for async export
|
|
time.sleep(1)
|
|
|
|
# Verify spans were collected
|
|
self.assertGreater(
|
|
self.collector.count_spans(),
|
|
0,
|
|
"No spans collected from disaggregation request",
|
|
)
|
|
|
|
# Verify disaggregation-specific spans exist
|
|
span_names = self.collector.get_span_names()
|
|
|
|
# Check for transfer-related spans
|
|
self.assertTrue(
|
|
self.collector.has_all_spans(
|
|
[
|
|
RequestStage.PREFILL_TRANSFER_KV_CACHE.stage_name,
|
|
RequestStage.DECODE_TRANSFERRED.stage_name,
|
|
MooncakeRequestStage.MOONCAKE_WORKER_SEND.stage_name,
|
|
]
|
|
),
|
|
f"Expected all disaggregation transfer spans, got {sorted(span_names)}",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|