dashboard/app/collect/cpu.py
2026-08-31 00:47:02 +02:00

81 lines
2.3 KiB
Python

import glob
import psutil
from app.sample import Sample
from app.utils import sysfs
_temp_path: str | None = None
_temp_checked = False
def _find_temp_path() -> str | None:
"""Find the sysfs file reporting CPU temperature, in millidegrees.
Prefers hwmon sensors named k10temp (AMD), coretemp (Intel), or
cpu_thermal (ARM), taking the first temp*_input of the first matching
hwmon; falls back to the acpitz thermal zone. The result is cached by
temp() for the process lifetime.
Returns:
The sysfs file to read, or None if no suitable sensor exists.
"""
for hwmon in sorted(glob.glob("/sys/class/hwmon/hwmon*")):
name = (sysfs.read_str(f"{hwmon}/name") or "").lower()
if name in ("k10temp", "coretemp", "cpu_thermal"):
for t in sorted(glob.glob(f"{hwmon}/temp*_input")):
return t
return None
for zone in sorted(glob.glob("/sys/class/thermal/thermal_zone*")):
if (sysfs.read_str(f"{zone}/type") or "").lower() == "acpitz":
return f"{zone}/temp"
return None
def temp() -> float | None:
"""Read the CPU temperature in degrees Celsius.
The sensor path is resolved once via _find_temp_path. Sysfs reports
millidegrees; the value is converted and rounded to 0.1 °C.
Returns:
Temperature in °C, or None if no sensor or unreadable value.
"""
global _temp_path, _temp_checked
if not _temp_checked:
_temp_checked = True
_temp_path = _find_temp_path()
if _temp_path is None:
return None
v = sysfs.read_float(_temp_path)
if v is None:
return None
return round(v / 1000.0, 1)
def prime() -> None:
"""Prime psutil's CPU percent counter so the next call has a real delta.
psutil.cpu_percent(None) returns 0.0 on its first call; sampler_loop
invokes this before the first sample for that reason.
"""
_ = psutil.cpu_percent(None)
def core_count() -> int:
"""Number of logical CPU cores (at least 1)."""
return psutil.cpu_count(logical=True) or 1
def fill(s: Sample) -> None:
"""Fill the cpu, cpu_temp, and load-average fields of a Sample.
Args:
s: sample to fill.
"""
s.cpu = psutil.cpu_percent(None)
s.cpu_temp = temp()
l1, l5, l15 = psutil.getloadavg()
s.load1 = l1
s.load5 = l5
s.load15 = l15