"""资源探针:本地引擎推理时采样峰值内存/CPU;模型大小读磁盘。 注意:psutil 测的是整个 Python 进程 RSS(含解释器与已加载库),用于本地模型横向对比是 合理代理量;报告会标注硬件环境,且只在本地引擎启用,云端 gummy 不测(填 N/A)。 """ from __future__ import annotations import os import threading import time import psutil class ResourceProbe: """上下文管理器:with 块内后台采样进程 RSS / CPU%。""" def __init__(self, interval: float = 0.05): self.interval = interval self._stop = threading.Event() self._thread: threading.Thread | None = None self._proc = psutil.Process(os.getpid()) self.peak_rss = 0 self._cpu: list[float] = [] def __enter__(self) -> "ResourceProbe": self._proc.cpu_percent(None) # 预热:首次调用返回 0,丢弃 self._thread = threading.Thread(target=self._run, daemon=True) self._thread.start() return self def _run(self) -> None: while not self._stop.is_set(): try: self.peak_rss = max(self.peak_rss, self._proc.memory_info().rss) c = self._proc.cpu_percent(None) if c > 0: self._cpu.append(c) except Exception: pass time.sleep(self.interval) def __exit__(self, *_exc) -> None: self._stop.set() if self._thread: self._thread.join(timeout=1.0) @property def peak_rss_mb(self) -> float: return self.peak_rss / 1024 / 1024 @property def avg_cpu(self) -> float: return sum(self._cpu) / len(self._cpu) if self._cpu else 0.0 def dir_size_mb(path: str) -> float: """目录下所有文件体积之和(MB);路径不存在返回 0。""" total = 0 if not path or not os.path.exists(path): return 0.0 if os.path.isfile(path): return os.path.getsize(path) / 1024 / 1024 for root, _dirs, files in os.walk(path): for f in files: try: total += os.path.getsize(os.path.join(root, f)) except OSError: pass return total / 1024 / 1024 def hardware_info() -> dict: """报告里标注的硬件环境。""" import platform vm = psutil.virtual_memory() return { "platform": platform.platform(), "machine": platform.machine(), "cpu_count": psutil.cpu_count(logical=True), "cpu_count_physical": psutil.cpu_count(logical=False), "total_mem_gb": round(vm.total / 1024**3, 1), }