Repository navigation
Expand file tree
/
Copy pathsmi.py
More file actions
127 lines (104 loc) · 3.22 KB
/
Copy pathsmi.py
File metadata and controls
127 lines (104 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""nvidia-smi helpers. GPU index follows ``CUDA_VISIBLE_DEVICES``.
``nvidia-smi --id=0`` is the first *physical* card. Torch ``cuda:0`` is the
first *visible* card. Multi-GPU boxes must use the same id or ``--codec auto``
plans VRAM for the wrong device.
"""
from __future__ import annotations
import os
import shutil
import subprocess
from pathlib import Path
__all__ = [
"compute_cap",
"device_id",
"executable",
"gpu_name",
"query_field",
"query_mib",
"total_mib",
"used_mib",
"visible_gpu_looks_sm120",
]
def device_id() -> str:
"""Selector for ``nvidia-smi --id=``: index, UUID, or PCI bus id."""
vis = os.environ.get("CUDA_VISIBLE_DEVICES", "").strip()
if not vis:
return "0"
first = vis.split(",")[0].strip()
if first in ("", "-1"):
return "0"
return first
def executable() -> str | None:
hit = shutil.which("nvidia-smi")
if hit:
return hit
if os.name != "nt":
return None
system = Path(os.environ.get("SystemRoot", r"C:\Windows"))
program = Path(os.environ.get("ProgramFiles", r"C:\Program Files"))
for candidate in (
system / "System32" / "nvidia-smi.exe",
program / "NVIDIA Corporation" / "NVSMI" / "nvidia-smi.exe",
):
if candidate.is_file():
return str(candidate)
return None
def query_field(field: str) -> str | None:
"""One nvidia-smi CSV cell for the visible GPU, or None."""
exe = executable()
if exe is None:
return None
try:
out = subprocess.run(
[
exe,
f"--id={device_id()}",
f"--query-gpu={field}",
"--format=csv,nounits,noheader",
],
capture_output=True,
text=True,
timeout=10,
)
except (OSError, subprocess.SubprocessError):
return None
if out.returncode != 0:
return None
try:
line = out.stdout.strip().splitlines()[0].strip()
except IndexError:
return None
if not line or line.lower() in {"[n/a]", "n/a"}:
return None
return line
def query_mib(field: str) -> int | None:
raw = query_field(field)
if raw is None:
return None
try:
return int(raw)
except ValueError:
return None
def gpu_name() -> str | None:
return query_field("name")
def compute_cap() -> tuple[int, int] | None:
"""Driver-reported compute capability, e.g. ``(12, 0)`` on a 5070 Ti."""
raw = query_field("compute_cap")
if raw is None:
return None
parts = raw.replace(",", ".").split(".")
if len(parts) < 2 or not parts[0].isdigit() or not parts[1].isdigit():
return None
return int(parts[0]), int(parts[1])
def visible_gpu_looks_sm120() -> bool:
"""nvidia-smi only. Used by setup before torch is installed."""
from gpu.arch_family import looks_sm120
return looks_sm120(capability=compute_cap(), device_name=gpu_name())
def total_mib() -> int | None:
value = query_mib("memory.total")
if value is None or value <= 0:
return None
return value
def used_mib() -> int | None:
"""Occupied MiB. ``0`` is a real empty-card reading, not a miss."""
return query_mib("memory.used")