From 74c0f11014018a8d5729aa9ee9d0cd5e1fcfd1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E4=BD=B3=E6=B5=A9Alben?= <35291372+XiaoBinGan@users.noreply.github.com> Date: Sat, 31 Oct 2026 18:14:25 +0800 Subject: [PATCH] Fix #4654: close the six handles the sampler and the HIP probe open inside an expression Six open() calls sat inside an expression, so nothing ever called close() on them and the Minimal serving runtime job printed the same ResourceWarning lines on every run: the physical_package_id glob, /proc/cpuinfo, /proc/stat and /proc/meminfo in serve/telemetry.py, and the two properties files the HIP probe reads in serve/server.py. Each now runs under a with statement: telemetry.py reads the cpuinfo, stat and meminfo files through one, and server.py reads the two properties files through a small _read_lines() helper. No value, threshold or return path changes; the figures are the same ones in the same order. --- serve/server.py | 10 ++++++++-- serve/telemetry.py | 16 ++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/serve/server.py b/serve/server.py index 768f6bcc374..72b81495550 100644 --- a/serve/server.py +++ b/serve/server.py @@ -3435,6 +3435,12 @@ def gpu_speed_scores(indices: list[int]) -> dict[int, float] | None: return got if all(i in got and got[i] > 0 for i in indices) else None + +def _read_lines(path: str): + """The lines of `path`, with the file closed when the caller is done (the HIP properties probe reads two).""" + with open(path) as fh: + return fh.readlines() + def hip_speed_scores(indices: list[int], root: str = "/sys/class/kfd/kfd/topology/nodes") -> dict[int, float] | None: """AMD on Linux: SIMDs x max engine clock of each card, from the KFD topology (the order setup and the engine use for "gpu" there: the GPU nodes in node order). None when the files are not there (Windows, no ROCm driver).""" @@ -3445,7 +3451,7 @@ def hip_speed_scores(indices: list[int], root: str = "/sys/class/kfd/kfd/topolog cards = [] for n in nodes: try: - props = dict(line.split() for line in open(os.path.join(root, str(n), "properties")) if len(line.split()) == 2) + props = dict(line.split() for line in _read_lines(os.path.join(root, str(n), "properties")) if len(line.split()) == 2) simd, clk = int(props.get("simd_count", 0)), int(props.get("max_engine_clk_fcompute", 0)) except (OSError, ValueError): continue @@ -3482,7 +3488,7 @@ def hip_gpu_archs(root: str = "/sys/class/kfd/kfd/topology/nodes") -> dict[int, out: dict[int, str] = {} for n in nodes: try: - props = dict(line.split() for line in open(os.path.join(root, str(n), "properties")) if len(line.split()) == 2) + props = dict(line.split() for line in _read_lines(os.path.join(root, str(n), "properties")) if len(line.split()) == 2) ver, simd = int(props.get("gfx_target_version", 0)), int(props.get("simd_count", 0)) except (OSError, ValueError): continue diff --git a/serve/telemetry.py b/serve/telemetry.py index f56da0907f0..8722f62fa5f 100644 --- a/serve/telemetry.py +++ b/serve/telemetry.py @@ -455,7 +455,8 @@ def _cpu_topology(root: str = "/sys/devices/system"): packages = set() for f in glob.glob(os.path.join(root, "cpu", "cpu[0-9]*", "topology", "physical_package_id")): try: - packages.add(open(f, encoding="utf-8").read().strip()) + with open(f, encoding="utf-8") as fh: + packages.add(fh.read().strip()) except OSError: continue nodes = len(glob.glob(os.path.join(root, "node", "node[0-9]*"))) @@ -473,9 +474,10 @@ def _cpu_name(): except OSError: pass elif os.path.exists("/proc/cpuinfo"): - for line in open("/proc/cpuinfo", encoding="utf-8", errors="replace"): - if line.startswith("model name"): - return line.split(":", 1)[1].strip() + with open("/proc/cpuinfo", encoding="utf-8", errors="replace") as fh: + for line in fh: + if line.startswith("model name"): + return line.split(":", 1)[1].strip() return platform.processor() or None @@ -492,7 +494,8 @@ def _times(self): return idle.value, kern.value + user.value # kernel time includes idle return None try: - f = [int(x) for x in open("/proc/stat").readline().split()[1:]] + with open("/proc/stat") as fh: + f = [int(x) for x in fh.readline().split()[1:]] return f[3] + f[4], sum(f) except (OSError, ValueError): return None @@ -519,7 +522,8 @@ class MS(ctypes.Structure): return m.ullTotalPhys - m.ullAvailPhys, m.ullTotalPhys return None, None try: - info = dict(line.split(":", 1) for line in open("/proc/meminfo")) + with open("/proc/meminfo") as fh: + info = dict(line.split(":", 1) for line in fh) total = int(info["MemTotal"].split()[0]) * 1024 avail = int(info["MemAvailable"].split()[0]) * 1024 return total - avail, total