项目文件夹

文件
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

345 行
12 KiB
Python

"""
Unit tests for the ProfileMerger implementation.
Usage:
python test_profile_merger.py
python -m unittest test_profile_merger.py -v
"""
import gzip
import json
import os
import shutil
import tempfile
import unittest
from sglang.srt.managers.io_struct import ProfileReq, ProfileReqType
from sglang.srt.utils.profile_merger import ProfileMerger
from sglang.test.ci.ci_register import (
register_amd_ci,
register_cpu_ci,
register_cuda_ci,
)
from sglang.test.test_utils import CustomTestCase
register_cuda_ci(est_time=9, stage="base-b", runner_config="1-gpu-small")
register_amd_ci(est_time=8, suite="stage-b-test-1-gpu-small-amd")
register_cpu_ci(est_time=8, suite="base-c-test-cpu")
class TestProfileMerger(CustomTestCase):
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
self.profile_id = "test_profile_123"
self.merger = ProfileMerger(self.temp_dir, self.profile_id)
def tearDown(self):
shutil.rmtree(self.temp_dir, ignore_errors=True)
def test_rank_extraction_and_labeling(self):
# Test TP-only
filename = f"{self.profile_id}-TP-0.trace.json.gz"
rank_info = self.merger._extract_rank_info(filename)
self.assertEqual(rank_info, {"tp_rank": 0})
label = self.merger._create_rank_label(rank_info)
self.assertEqual(label, "[TP00]")
# Test all parallelism types
filename = f"{self.profile_id}-TP-1-DP-2-PP-3-EP-4.trace.json.gz"
rank_info = self.merger._extract_rank_info(filename)
self.assertEqual(
rank_info, {"tp_rank": 1, "dp_rank": 2, "pp_rank": 3, "ep_rank": 4}
)
label = self.merger._create_rank_label(rank_info)
self.assertEqual(label, "[TP01-DP02-PP03-EP04]")
# Test partial ranks
filename = f"{self.profile_id}-TP-0-DP-1.trace.json.gz"
rank_info = self.merger._extract_rank_info(filename)
self.assertEqual(rank_info, {"tp_rank": 0, "dp_rank": 1})
label = self.merger._create_rank_label(rank_info)
self.assertEqual(label, "[TP00-DP01]")
# Test no ranks
filename = f"{self.profile_id}.trace.json.gz"
rank_info = self.merger._extract_rank_info(filename)
self.assertEqual(rank_info, {})
label = self.merger._create_rank_label(rank_info)
self.assertEqual(label, "[Unknown]")
def test_sort_index_calculation(self):
# Single rank
rank_info = {"tp_rank": 0}
sort_idx = self.merger._calculate_sort_index(rank_info, 83)
self.assertEqual(sort_idx, 83)
# Multiple ranks
rank_info = {"tp_rank": 1, "dp_rank": 2, "pp_rank": 3, "ep_rank": 4}
sort_idx = self.merger._calculate_sort_index(rank_info, 83)
self.assertNotEqual(sort_idx, 83)
self.assertGreater(sort_idx, 1000000)
# Empty ranks
rank_info = {}
sort_idx = self.merger._calculate_sort_index(rank_info, 83)
self.assertEqual(sort_idx, 83)
def test_rank_sort_key(self):
# Full ranks: TP-1, DP-2, PP-3, EP-4 → sorted as (DP, EP, PP, TP)
filename = f"{self.profile_id}-TP-1-DP-2-PP-3-EP-4.trace.json.gz"
sort_key = self.merger._get_rank_sort_key(filename)
self.assertEqual(sort_key, (2, 4, 3, 1))
# Missing ranks: only TP-1 → sorted as (DP=0, EP=0, PP=0, TP=1)
filename = f"{self.profile_id}-TP-1.trace.json.gz"
sort_key = self.merger._get_rank_sort_key(filename)
self.assertEqual(sort_key, (0, 0, 0, 1))
def test_discover_trace_files(self):
# Create mock trace files
trace_files = [
f"{self.profile_id}-TP-0.trace.json.gz", # Old format
f"{self.profile_id}-TP-1.trace.json.gz", # Old format
f"{self.profile_id}-TP-0-DP-1.trace.json.gz", # New format
]
for filename in trace_files:
filepath = os.path.join(self.temp_dir, filename)
with gzip.open(filepath, "wt") as f:
json.dump({"traceEvents": []}, f)
discovered = self.merger._discover_trace_files()
self.assertEqual(len(discovered), 3)
# Check that all expected files are discovered
discovered_basenames = {os.path.basename(f) for f in discovered}
expected_basenames = {
f"{self.profile_id}-TP-0.trace.json.gz",
f"{self.profile_id}-TP-1.trace.json.gz",
f"{self.profile_id}-TP-0-DP-1.trace.json.gz",
}
self.assertEqual(discovered_basenames, expected_basenames)
# Test no matches
empty_merger = ProfileMerger(self.temp_dir, "nonexistent")
discovered = empty_merger._discover_trace_files()
self.assertEqual(len(discovered), 0)
def test_merge_chrome_traces(self):
# Create multiple trace files in random order
trace_files = [
{
"filename": f"{self.profile_id}-TP-1-DP-1.trace.json.gz",
"events": [
{"ph": "X", "name": "op1", "pid": 83, "ts": 1000.0, "dur": 10.0}
],
},
{
"filename": f"{self.profile_id}-TP-0.trace.json.gz",
"events": [
{"ph": "X", "name": "op2", "pid": 84, "ts": 2000.0, "dur": 15.0}
],
},
{
"filename": f"{self.profile_id}-TP-0-DP-1.trace.json.gz",
"events": [
{"ph": "X", "name": "op3", "pid": 85, "ts": 3000.0, "dur": 20.0}
],
},
]
for trace_data in trace_files:
filepath = os.path.join(self.temp_dir, trace_data["filename"])
trace_content = {
"schemaVersion": 1,
"deviceProperties": [{"device_id": 0, "name": "GPU-0"}],
"traceEvents": trace_data["events"],
}
with gzip.open(filepath, "wt") as f:
json.dump(trace_content, f)
# Test file ordering by capturing log messages
import logging
logger = logging.getLogger("sglang.srt.utils.profile_merger")
with self.assertLogs(logger, level="INFO") as log_capture:
merged_path = self.merger.merge_chrome_traces()
# Verify files were processed in rank order
log_messages = [
record.getMessage()
for record in log_capture.records
if "Processing file:" in record.getMessage()
]
self.assertIn("TP-0.trace.json.gz", log_messages[0]) # (0,0,0,0) comes first
self.assertIn(
"TP-0-DP-1.trace.json.gz", log_messages[1]
) # (0,1,0,0) comes second
self.assertIn(
"TP-1-DP-1.trace.json.gz", log_messages[2]
) # (1,1,0,0) comes last
# Verify merged content
self.assertTrue(os.path.exists(merged_path))
with gzip.open(merged_path, "rt") as f:
merged_data = json.load(f)
self.assertEqual(len(merged_data["traceEvents"]), 3)
self.assertEqual(len(merged_data["deviceProperties"]), 3)
# Check rank labels in events
events = merged_data["traceEvents"]
pids = [event["pid"] for event in events]
self.assertIn("[TP00] 84", pids)
self.assertIn("[TP00-DP01] 85", pids)
self.assertIn("[TP01-DP01] 83", pids)
# Test merge summary
summary = self.merger.get_merge_summary()
self.assertEqual(summary["total_files"], 3)
self.assertEqual(summary["total_events"], 3)
self.assertEqual(summary["profile_id"], self.profile_id)
# Test no files error
empty_merger = ProfileMerger(self.temp_dir, "nonexistent")
with self.assertRaises(ValueError):
empty_merger.merge_chrome_traces()
class TestProfileMergerIntegration(CustomTestCase):
def test_data_structures_merge_profiles(self):
# Test ProfileReq
req = ProfileReq()
self.assertFalse(req.merge_profiles)
self.assertEqual(req.req_type, ProfileReqType.START_PROFILE)
req = ProfileReq(merge_profiles=True)
self.assertTrue(req.merge_profiles)
class TestProfileMergerEdgeCases(CustomTestCase):
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
self.profile_id = "test_edge_cases"
self.merger = ProfileMerger(self.temp_dir, self.profile_id)
def tearDown(self):
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
def test_error_handling_and_edge_cases(self):
# Test malformed trace file
filename = f"{self.profile_id}-TP-0.trace.json.gz"
filepath = os.path.join(self.temp_dir, filename)
with gzip.open(filepath, "wt") as f:
f.write("invalid json content")
merged_path = self.merger.merge_chrome_traces()
self.assertTrue(os.path.exists(merged_path))
with gzip.open(merged_path, "rt") as f:
merged_data = json.load(f)
self.assertEqual(len(merged_data["traceEvents"]), 0)
# Test empty trace file
with gzip.open(filepath, "wt") as f:
json.dump({}, f)
merged_path = self.merger.merge_chrome_traces()
self.assertTrue(os.path.exists(merged_path))
# Test missing device properties
trace_data = {
"schemaVersion": 1,
"traceEvents": [
{"ph": "X", "name": "test", "pid": 83, "ts": 1000.0, "dur": 10.0}
],
}
with gzip.open(filepath, "wt") as f:
json.dump(trace_data, f)
merged_path = self.merger.merge_chrome_traces()
with gzip.open(merged_path, "rt") as f:
merged_data = json.load(f)
self.assertNotIn("deviceProperties", merged_data)
def test_missing_ranks_and_none_handling(self):
# Test rank extraction with missing ranks
filename = f"{self.profile_id}-TP-0.trace.json.gz"
rank_info = self.merger._extract_rank_info(filename)
self.assertEqual(rank_info, {"tp_rank": 0})
# Test rank label creation with missing ranks
label = self.merger._create_rank_label({"tp_rank": 0})
self.assertEqual(label, "[TP00]")
label = self.merger._create_rank_label({})
self.assertEqual(label, "[Unknown]")
# Test sort index calculation
sort_idx = self.merger._calculate_sort_index({"tp_rank": 0}, 83)
self.assertGreater(sort_idx, 0)
sort_idx = self.merger._calculate_sort_index({}, 83)
self.assertEqual(sort_idx, 83)
# Test sort key generation
sort_key = self.merger._get_rank_sort_key(filename)
self.assertEqual(sort_key, (0, 0, 0, 0))
# Test _maybe_cast_int with various inputs
self.assertIsNone(self.merger._maybe_cast_int(None))
self.assertIsNone(self.merger._maybe_cast_int("invalid"))
self.assertEqual(self.merger._maybe_cast_int("123"), 123)
self.assertEqual(self.merger._maybe_cast_int(456), 456)
def test_mixed_rank_scenarios(self):
trace_scenarios = [
{
"filename": f"{self.profile_id}-TP-0.trace.json.gz",
"events": [
{"ph": "X", "name": "op1", "pid": 83, "ts": 1000.0, "dur": 10.0}
],
},
{
"filename": f"{self.profile_id}-TP-1-DP-0.trace.json.gz",
"events": [
{"ph": "X", "name": "op2", "pid": 84, "ts": 2000.0, "dur": 15.0}
],
},
{
"filename": f"{self.profile_id}-TP-0-DP-1-PP-0.trace.json.gz",
"events": [
{"ph": "X", "name": "op3", "pid": 85, "ts": 3000.0, "dur": 20.0}
],
},
]
for scenario in trace_scenarios:
filepath = os.path.join(self.temp_dir, scenario["filename"])
trace_data = {
"schemaVersion": 1,
"deviceProperties": [{"device_id": 0, "name": "GPU-0"}],
"traceEvents": scenario["events"],
}
with gzip.open(filepath, "wt") as f:
json.dump(trace_data, f)
merged_path = self.merger.merge_chrome_traces()
self.assertTrue(os.path.exists(merged_path))
with gzip.open(merged_path, "rt") as f:
merged_data = json.load(f)
self.assertEqual(len(merged_data["traceEvents"]), 3)
events = merged_data["traceEvents"]
pids = [event["pid"] for event in events]
self.assertIn("[TP00] 83", pids)
self.assertIn("[TP01-DP00] 84", pids)
self.assertIn("[TP00-DP01-PP00] 85", pids)
if __name__ == "__main__":
unittest.main()