#!/usr/bin/env python
# vim: ft=python:ts=4:sw=4:et:ai:cin
# NVML driver for the gpu.nvidia component
import pynvml
from contextlib import contextmanager
import subprocess
import os.path as osp
@contextmanager
def nvml(flags=0):
pynvml.nvmlInitWithFlags(flags)
yield
pynvml.nvmlShutdown()
def process_name(pid, full=False):
try:
proc = subprocess.run(
["ps", "-o", "cmd=", str(pid)],
capture_output=True,
encoding="utf-8",
shell=False,
)
if proc.returncode > 0:
raise SystemError()
cmdline = proc.stdout
return (
cmdline if full else osp.basename(cmdline.split(" ", maxsplit=1)[0])
).strip()
except:
return "[unknown]"
with nvml():
def query(f, *args, default=None, **kw):
try:
f = getattr(pynvml, f)
val = f(*args, **kw)
except:
val = default
if isinstance(val, bytes):
val = val.decode("utf-8")
return val
def query_and_print(name, f, *args, default=None, **kw):
val = query(f, *args, default=default, **kw)
print_entry(name, val)
return val
def print_entry(k, v):
print(f"{v!r}," if k is None else f"{k}={v!r},")
gpu_count = query("nvmlDeviceGetCount")
print("{")
for gi in range(gpu_count):
print("{")
handle = query("nvmlDeviceGetHandleByIndex", gi)
def q(f, *args, **kw):
return query(f, handle, *args, **kw)
def qp(name, f, *args, **kw):
return query_and_print(name, f, handle, *args, **kw)
qp("model_name", "nvmlDeviceGetName")
memory_info = q("nvmlDeviceGetMemoryInfo")
print_entry("mem_used", memory_info.used)
print_entry("mem_total", memory_info.total)
print_entry("mem_free", memory_info.free)
util_rates = q("nvmlDeviceGetUtilizationRates")
print_entry("gpu_util", util_rates.gpu)
print_entry("mem_util", util_rates.memory)
qp("fan_speed", "nvmlDeviceGetFanSpeed")
qp("gpu_temp", "nvmlDeviceGetTemperature", pynvml.NVML_TEMPERATURE_GPU)
qp(
"gpu_temp_thres",
"nvmlDeviceGetTemperatureThreshold",
pynvml.NVML_TEMPERATURE_THRESHOLD_GPU_MAX,
default=100,
)
print_entry("power_usage", q("nvmlDeviceGetPowerUsage") / 1000.0)
print_entry("power_limit", q("nvmlDeviceGetPowerManagementLimit") / 1000.0)
processes = {}
for proc_type, proc_query in (
("c", "nvmlDeviceGetComputeRunningProcesses"),
("g", "nvmlDeviceGetGraphicsRunningProcesses"),
):
for proc in q(proc_query):
pid = proc.pid
processes[pid] = dict(
pid=pid,
name=process_name(pid),
type=proc_type,
gpu_util=0,
mem_util=0,
gpu_mem=proc.usedGpuMemory,
gpu_instance=proc.gpuInstanceId,
)
if len(processes) > 0:
timestamp = 0 # list all processes
samples = q("nvmlDeviceGetProcessUtilization", timestamp)
for s in samples:
if s.pid in processes:
processes[s.pid].update(
dict(
gpu_util=s.smUtil,
mem_util=s.memUtil,
)
)
processes = list(processes.values())
processes.sort(key=lambda x: x["gpu_util"], reverse=True)
print("processes={")
for p in processes:
print("{")
for k in (
"pid",
"name",
"type",
"gpu_util",
"mem_util",
"gpu_mem",
"gpu_instance",
):
print_entry(k, p[k])
print("},")
print("}")
print("},")
print("}")