Add TP server GPU process regression test (#27721)
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
import unittest
|
||||
|
||||
import psutil
|
||||
|
||||
from sglang.srt.utils import kill_process_tree
|
||||
from sglang.test.ci.ci_register import register_cuda_ci
|
||||
from sglang.test.test_utils import (
|
||||
DEFAULT_SMALL_MODEL_NAME_FOR_TEST,
|
||||
DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||
DEFAULT_URL_FOR_TEST,
|
||||
CustomTestCase,
|
||||
popen_launch_server,
|
||||
)
|
||||
|
||||
register_cuda_ci(est_time=120, stage="base-b", runner_config="2-gpu-large")
|
||||
|
||||
|
||||
class TestTPServerGPUProcesses(CustomTestCase):
|
||||
tp_size = 2
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.model = DEFAULT_SMALL_MODEL_NAME_FOR_TEST
|
||||
cls.base_url = DEFAULT_URL_FOR_TEST
|
||||
cls.process = popen_launch_server(
|
||||
cls.model,
|
||||
cls.base_url,
|
||||
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||
other_args=[
|
||||
"--tp-size",
|
||||
str(cls.tp_size),
|
||||
"--mem-fraction-static",
|
||||
"0.70",
|
||||
"--disable-cuda-graph",
|
||||
"--disable-piecewise-cuda-graph",
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
if hasattr(cls, "process") and cls.process:
|
||||
kill_process_tree(cls.process.pid)
|
||||
|
||||
def test_tp_server_has_only_worker_gpu_processes(self):
|
||||
if shutil.which("nvidia-smi") is None:
|
||||
self.skipTest("nvidia-smi is required for GPU process assertions")
|
||||
|
||||
rows = self._wait_for_server_gpu_processes()
|
||||
gpu_pids = {row["pid"] for row in rows}
|
||||
|
||||
self.assertNotIn(
|
||||
self.process.pid,
|
||||
gpu_pids,
|
||||
f"server parent process unexpectedly holds a GPU context: "
|
||||
f"{self._format_rows(rows)}",
|
||||
)
|
||||
self.assertEqual(
|
||||
len(gpu_pids),
|
||||
self.tp_size,
|
||||
f"TP={self.tp_size} server should have exactly {self.tp_size} "
|
||||
f"GPU worker processes, got {len(gpu_pids)}: {self._format_rows(rows)}",
|
||||
)
|
||||
|
||||
def _wait_for_server_gpu_processes(self):
|
||||
deadline = time.monotonic() + 60
|
||||
stable_since = None
|
||||
last_rows = []
|
||||
|
||||
while time.monotonic() < deadline:
|
||||
tree_pids = self._server_process_tree_pids()
|
||||
rows = [
|
||||
row for row in self._query_gpu_processes() if row["pid"] in tree_pids
|
||||
]
|
||||
last_rows = rows
|
||||
|
||||
if len({row["pid"] for row in rows}) >= self.tp_size:
|
||||
if stable_since is None:
|
||||
stable_since = time.monotonic()
|
||||
elif time.monotonic() - stable_since >= 3:
|
||||
return rows
|
||||
else:
|
||||
stable_since = None
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
self.fail(
|
||||
f"Timed out waiting for TP={self.tp_size} GPU worker processes. "
|
||||
f"Last observed rows: {self._format_rows(last_rows)}"
|
||||
)
|
||||
|
||||
def _server_process_tree_pids(self):
|
||||
pids = {self.process.pid}
|
||||
try:
|
||||
parent = psutil.Process(self.process.pid)
|
||||
pids.update(child.pid for child in parent.children(recursive=True))
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
return pids
|
||||
|
||||
def _query_gpu_processes(self):
|
||||
result = subprocess.run(
|
||||
[
|
||||
"nvidia-smi",
|
||||
"--query-compute-apps=gpu_uuid,pid,process_name",
|
||||
"--format=csv,noheader,nounits",
|
||||
],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
rows = []
|
||||
for line in result.stdout.splitlines():
|
||||
fields = [field.strip() for field in line.split(",", maxsplit=2)]
|
||||
if len(fields) != 3:
|
||||
continue
|
||||
gpu_uuid, pid, process_name = fields
|
||||
rows.append(
|
||||
{
|
||||
"gpu_uuid": gpu_uuid,
|
||||
"pid": int(pid),
|
||||
"process_name": process_name,
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
def _format_rows(self, rows):
|
||||
if not rows:
|
||||
return "[]"
|
||||
return "[" + ", ".join(str(row) for row in rows) + "]"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user