guanghulab/zhuyuan-agent/gpu_monitor.py

100 lines
3.4 KiB
Python
Raw Normal View History

# GPU监控模块 · 采集nvidia-smi数据
# HLDP://zhuyuan-agent/gpu-monitor
import subprocess
import json
import re
from typing import List, Dict, Optional
def collect_gpu_metrics() -> Dict:
"""采集所有GPU的实时指标
Returns:
{
"gpus": [
{
"index": 0,
"name": "NVIDIA GeForce RTX 3090",
"uuid": "GPU-xxxx",
"utilization_gpu": 85, # %
"memory_used_mb": 18432, # MB
"memory_total_mb": 24576, # MB
"temperature_gpu": 72, # °C
"power_draw_w": 285.5, # W
"fan_speed": 65 # %
}
],
"error": null
}
"""
try:
# 查询GPU关键指标
result = subprocess.run(
[
"nvidia-smi",
"--query-gpu=index,name,uuid,utilization.gpu,memory.used,memory.total,temperature.gpu,power.draw,fan.speed",
"--format=csv,noheader,nounits"
],
capture_output=True, text=True, timeout=10
)
if result.returncode != 0:
return {"gpus": [], "error": f"nvidia-smi failed: {result.stderr.strip()}"}
gpus = []
for line in result.stdout.strip().split("\n"):
if not line.strip():
continue
parts = [p.strip() for p in line.split(",")]
if len(parts) < 9:
continue
try:
gpu = {
"index": int(parts[0]),
"name": parts[1],
"uuid": parts[2],
"utilization_gpu": int(parts[3]) if parts[3] != "[Not Supported]" else 0,
"memory_used_mb": int(parts[4]) if parts[4] != "[Not Supported]" else 0,
"memory_total_mb": int(parts[5]) if parts[5] != "[Not Supported]" else 0,
"temperature_gpu": int(parts[6]) if parts[6] != "[Not Supported]" else 0,
"power_draw_w": float(parts[7]) if parts[7] not in ("[Not Supported]", "") else 0.0,
"fan_speed": int(parts[8]) if parts[8] not in ("[Not Supported]", "") else 0,
}
gpus.append(gpu)
except (ValueError, IndexError):
continue
return {"gpus": gpus, "error": None}
except FileNotFoundError:
return {"gpus": [], "error": "nvidia-smi not found - not a GPU machine?"}
except subprocess.TimeoutExpired:
return {"gpus": [], "error": "nvidia-smi timed out"}
except Exception as e:
return {"gpus": [], "error": str(e)}
def gpu_summary(gpus: List[Dict]) -> str:
"""生成GPU状态的一行摘要"""
if not gpus:
return "无GPU"
parts = []
for g in gpus:
util = g.get("utilization_gpu", 0)
temp = g.get("temperature_gpu", 0)
mem = g.get("memory_used_mb", 0)
mem_total = g.get("memory_total_mb", 0)
mem_pct = int(mem / mem_total * 100) if mem_total > 0 else 0
parts.append(f"GPU{g['index']}: {util}%/{temp}°C/{mem_pct}%VRAM")
return " | ".join(parts)
# 快速测试
if __name__ == "__main__":
data = collect_gpu_metrics()
print(json.dumps(data, indent=2, ensure_ascii=False))
if data["gpus"]:
print(f"\n摘要: {gpu_summary(data['gpus'])}")