Skip to content

Commit c20c03a

Browse files
committed
refactor(utils): extract system utilities to dedicated module
Move environment, file path, and process management functions to vllm/utils/system_utils.py: - update_environment_variables: Update multiple environment variables - set_env_var: Temporarily set environment variable (context manager) - unique_filepath: Generate unique file paths - set_process_title: Set process title with optional suffix - decorate_logs: Add process name/PID prefix to stdout/stderr - _add_prefix: Internal helper for log decoration This reduces vllm/utils/__init__.py from 1310 to 1220 lines and groups related system-level utilities in a single, cohesive module. Contributes to #26900 Signed-off-by: dongbo910220 <1275604947@qq.com>
1 parent 1c691f4 commit c20c03a

File tree

2 files changed

+134
-114
lines changed

2 files changed

+134
-114
lines changed

vllm/utils/__init__.py

Lines changed: 16 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,32 @@
3535
)
3636
from concurrent.futures.process import ProcessPoolExecutor
3737
from functools import cache, partial, wraps
38-
from pathlib import Path
39-
from typing import TYPE_CHECKING, Any, TextIO, TypeVar
38+
from typing import TYPE_CHECKING, Any, TypeVar
4039

4140
import cloudpickle
4241
import psutil
4342
import regex as re
44-
import setproctitle
4543
import torch
4644
import yaml
4745

4846
import vllm.envs as envs
4947
from vllm.logger import enable_trace_function_call, init_logger
5048
from vllm.ray.lazy_utils import is_in_ray_actor
49+
from vllm.utils.system_utils import (
50+
decorate_logs,
51+
set_env_var,
52+
set_process_title,
53+
unique_filepath,
54+
update_environment_variables,
55+
)
56+
57+
_ = (
58+
decorate_logs,
59+
set_env_var,
60+
set_process_title,
61+
unique_filepath,
62+
update_environment_variables,
63+
)
5164

5265
_DEPRECATED_MAPPINGS = {
5366
"cprofile": "profiling",
@@ -146,18 +159,6 @@ def random_uuid() -> str:
146159
return str(uuid.uuid4().hex)
147160

148161

149-
def update_environment_variables(envs: dict[str, str]):
150-
for k, v in envs.items():
151-
if k in os.environ and os.environ[k] != v:
152-
logger.warning(
153-
"Overwriting environment variable %s from '%s' to '%s'",
154-
k,
155-
os.environ[k],
156-
v,
157-
)
158-
os.environ[k] = v
159-
160-
161162
def cdiv(a: int, b: int) -> int:
162163
"""Ceiling division."""
163164
return -(a // -b)
@@ -1187,72 +1188,6 @@ def has_tilelang() -> bool:
11871188
return _has_module("tilelang")
11881189

11891190

1190-
def set_process_title(
1191-
name: str, suffix: str = "", prefix: str = envs.VLLM_PROCESS_NAME_PREFIX
1192-
) -> None:
1193-
"""
1194-
Set the current process title to a specific name with an
1195-
optional suffix.
1196-
1197-
Args:
1198-
name: The title to assign to the current process.
1199-
suffix: An optional suffix to append to the base name.
1200-
prefix: A prefix to prepend to the front separated by `::`.
1201-
"""
1202-
if suffix:
1203-
name = f"{name}_{suffix}"
1204-
setproctitle.setproctitle(f"{prefix}::{name}")
1205-
1206-
1207-
def _add_prefix(file: TextIO, worker_name: str, pid: int) -> None:
1208-
"""Prepend each output line with process-specific prefix"""
1209-
1210-
prefix = f"{CYAN}({worker_name} pid={pid}){RESET} "
1211-
file_write = file.write
1212-
1213-
def write_with_prefix(s: str):
1214-
if not s:
1215-
return
1216-
if file.start_new_line: # type: ignore[attr-defined]
1217-
file_write(prefix)
1218-
idx = 0
1219-
while (next_idx := s.find("\n", idx)) != -1:
1220-
next_idx += 1
1221-
file_write(s[idx:next_idx])
1222-
if next_idx == len(s):
1223-
file.start_new_line = True # type: ignore[attr-defined]
1224-
return
1225-
file_write(prefix)
1226-
idx = next_idx
1227-
file_write(s[idx:])
1228-
file.start_new_line = False # type: ignore[attr-defined]
1229-
1230-
file.start_new_line = True # type: ignore[attr-defined]
1231-
file.write = write_with_prefix # type: ignore[method-assign]
1232-
1233-
1234-
def decorate_logs(process_name: str | None = None) -> None:
1235-
"""
1236-
Adds a process-specific prefix to each line of output written to stdout and
1237-
stderr.
1238-
1239-
This function is intended to be called before initializing the api_server,
1240-
engine_core, or worker classes, so that all subsequent output from the
1241-
process is prefixed with the process name and PID. This helps distinguish
1242-
log output from different processes in multi-process environments.
1243-
1244-
Args:
1245-
process_name: Optional; the name of the process to use in the prefix.
1246-
If not provided, the current process name from the multiprocessing
1247-
context is used.
1248-
"""
1249-
if process_name is None:
1250-
process_name = get_mp_context().current_process().name
1251-
pid = os.getpid()
1252-
_add_prefix(sys.stdout, process_name, pid)
1253-
_add_prefix(sys.stderr, process_name, pid)
1254-
1255-
12561191
def length_from_prompt_token_ids_or_embeds(
12571192
prompt_token_ids: list[int] | None,
12581193
prompt_embeds: torch.Tensor | None,
@@ -1275,36 +1210,3 @@ def length_from_prompt_token_ids_or_embeds(
12751210
f" prompt_embeds={prompt_embeds_len}"
12761211
)
12771212
return prompt_token_len
1278-
1279-
1280-
@contextlib.contextmanager
1281-
def set_env_var(key, value):
1282-
old = os.environ.get(key)
1283-
os.environ[key] = value
1284-
try:
1285-
yield
1286-
finally:
1287-
if old is None:
1288-
del os.environ[key]
1289-
else:
1290-
os.environ[key] = old
1291-
1292-
1293-
def unique_filepath(fn: Callable[[int], Path]) -> Path:
1294-
"""
1295-
unique_filepath returns a unique path by trying
1296-
to include an integer in increasing order.
1297-
1298-
fn should be a callable that returns a path that
1299-
includes the passed int at a fixed location.
1300-
1301-
Note: This function has a TOCTOU race condition.
1302-
Caller should use atomic operations (e.g., open with 'x' mode)
1303-
when creating the file to ensure thread safety.
1304-
"""
1305-
i = 0
1306-
while True:
1307-
p = fn(i)
1308-
if not p.exists():
1309-
return p
1310-
i += 1

vllm/utils/system_utils.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3+
4+
from __future__ import annotations
5+
6+
import contextlib
7+
import os
8+
import sys
9+
from collections.abc import Callable, Iterator
10+
from pathlib import Path
11+
from typing import TextIO
12+
13+
import setproctitle
14+
15+
import vllm.envs as envs
16+
from vllm.logger import init_logger
17+
18+
logger = init_logger(__name__)
19+
20+
CYAN = "\033[1;36m"
21+
RESET = "\033[0;0m"
22+
23+
24+
# Environment variable utilities
25+
26+
27+
def update_environment_variables(envs_dict: dict[str, str]):
28+
"""Update multiple environment variables with logging."""
29+
for k, v in envs_dict.items():
30+
if k in os.environ and os.environ[k] != v:
31+
logger.warning(
32+
"Overwriting environment variable %s from '%s' to '%s'",
33+
k,
34+
os.environ[k],
35+
v,
36+
)
37+
os.environ[k] = v
38+
39+
40+
@contextlib.contextmanager
41+
def set_env_var(key: str, value: str) -> Iterator[None]:
42+
"""Temporarily set an environment variable."""
43+
old = os.environ.get(key)
44+
os.environ[key] = value
45+
try:
46+
yield
47+
finally:
48+
if old is None:
49+
os.environ.pop(key, None)
50+
else:
51+
os.environ[key] = old
52+
53+
54+
# File path utilities
55+
56+
57+
def unique_filepath(fn: Callable[[int], Path]) -> Path:
58+
"""Generate a unique file path by trying incrementing integers.
59+
60+
Note: This function has a TOCTOU race condition.
61+
Caller should use atomic operations (e.g., open with 'x' mode)
62+
when creating the file to ensure thread safety.
63+
"""
64+
i = 0
65+
while True:
66+
p = fn(i)
67+
if not p.exists():
68+
return p
69+
i += 1
70+
71+
72+
# Process management utilities
73+
74+
75+
def set_process_title(
76+
name: str, suffix: str = "", prefix: str = envs.VLLM_PROCESS_NAME_PREFIX
77+
) -> None:
78+
"""Set the current process title with optional suffix."""
79+
if suffix:
80+
name = f"{name}_{suffix}"
81+
setproctitle.setproctitle(f"{prefix}::{name}")
82+
83+
84+
def _add_prefix(file: TextIO, worker_name: str, pid: int) -> None:
85+
"""Add colored prefix to file output for log decoration."""
86+
prefix = f"{CYAN}({worker_name} pid={pid}){RESET} "
87+
file_write = file.write
88+
89+
def write_with_prefix(s: str):
90+
if not s:
91+
return
92+
if file.start_new_line: # type: ignore[attr-defined]
93+
file_write(prefix)
94+
idx = 0
95+
while (next_idx := s.find("\n", idx)) != -1:
96+
next_idx += 1
97+
file_write(s[idx:next_idx])
98+
if next_idx == len(s):
99+
file.start_new_line = True # type: ignore[attr-defined]
100+
return
101+
file_write(prefix)
102+
idx = next_idx
103+
file_write(s[idx:])
104+
file.start_new_line = False # type: ignore[attr-defined]
105+
106+
file.start_new_line = True # type: ignore[attr-defined]
107+
file.write = write_with_prefix # type: ignore[method-assign]
108+
109+
110+
def decorate_logs(process_name: str | None = None) -> None:
111+
"""Decorate stdout/stderr with process name and PID prefix."""
112+
from vllm.utils import get_mp_context
113+
114+
if process_name is None:
115+
process_name = get_mp_context().current_process().name
116+
pid = os.getpid()
117+
_add_prefix(sys.stdout, process_name, pid)
118+
_add_prefix(sys.stderr, process_name, pid)

0 commit comments

Comments
 (0)