|
1 | 1 | # Copyright (c) Microsoft Corporation. All rights reserved. |
2 | 2 | # Licensed under the Apache 2.0 License. |
3 | 3 | from subprocess import run, Popen, PIPE |
| 4 | +from pathlib import Path |
| 5 | +from typing import Optional, Dict |
4 | 6 |
|
5 | 7 | from loguru import logger as LOG |
6 | 8 |
|
7 | 9 |
|
| 10 | +def get_proc_memory_stats(pid: int) -> Optional[Dict[str, int]]: |
| 11 | + """Read memory statistics for a process from /proc/<pid>/status. |
| 12 | +
|
| 13 | + Returns a dict with keys: |
| 14 | + - current_rss: current resident set size in bytes |
| 15 | + - peak_rss: peak resident set size (VmHWM) in bytes |
| 16 | + - virtual_size: total virtual memory size in bytes |
| 17 | + Returns None if the process info cannot be read. |
| 18 | + """ |
| 19 | + try: |
| 20 | + status_path = Path(f"/proc/{pid}/status") |
| 21 | + text = status_path.read_text() |
| 22 | + except (OSError, PermissionError): |
| 23 | + return None |
| 24 | + |
| 25 | + fields = {"VmRSS": "current_rss", "VmHWM": "peak_rss", "VmSize": "virtual_size"} |
| 26 | + result = {} |
| 27 | + for line in text.splitlines(): |
| 28 | + parts = line.split(":", 1) |
| 29 | + if len(parts) == 2 and parts[0].strip() in fields: |
| 30 | + key = fields[parts[0].strip()] |
| 31 | + # Values in /proc/*/status are in kB |
| 32 | + value_str = parts[1].strip().split()[0] |
| 33 | + result[key] = int(value_str) * 1024 |
| 34 | + return result if len(result) == len(fields) else None |
| 35 | + |
| 36 | + |
8 | 37 | def ccall(*args, path=None, log_output=True, env=None): |
9 | 38 | suffix = f" [cwd: {path}]" if path else "" |
10 | 39 | cmd = " ".join(args) |
|
0 commit comments