mirror of
https://github.com/logos-blockchain/research.git
synced 2026-08-07 11:43:20 +00:00
82 lines
2.7 KiB
Python
82 lines
2.7 KiB
Python
"""Device (CPU/GPU) identity.
|
|
|
|
Each runner self-reports its hardware in the result `env` (cpu, arch, device).
|
|
The harness derives a device record from that, so identity is correct even for a
|
|
remote runner or a future GPU adapter (which would report device="gpu"). A CLI
|
|
`--device-label` overrides only the human label, e.g. to disambiguate two machines
|
|
that report the same CPU model string.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import platform
|
|
import re
|
|
from typing import Any, Optional
|
|
|
|
|
|
def slug(s: str) -> str:
|
|
out = re.sub(r"[^a-zA-Z0-9]+", "-", s.strip().lower()).strip("-")
|
|
return out or "unknown"
|
|
|
|
|
|
def device_from_env(env: dict[str, Any], override_label: Optional[str] = None) -> dict[str, str]:
|
|
"""Build a device record from a runner's reported env, falling back to the
|
|
host when the runner did not report hardware (older/minimal adapters).
|
|
|
|
The auto label combines the device model with the OS version so runs on the
|
|
same CPU under different OS/kernel versions get distinct labels."""
|
|
name = env.get("cpu") or _host_cpu()
|
|
arch = env.get("arch") or platform.machine() or "unknown"
|
|
dtype = env.get("device") or "cpu"
|
|
os_name = env.get("os") or platform.system().lower() or "unknown"
|
|
os_version = env.get("os_version") or platform.release() or "unknown"
|
|
return {
|
|
"type": dtype,
|
|
"name": name,
|
|
"arch": arch,
|
|
"os": os_name,
|
|
"os_version": os_version,
|
|
"label": override_label or slug(f"{name}-{os_version}"),
|
|
}
|
|
|
|
|
|
# Field priority works across arches: "model name" (x86), "Model" (Raspberry Pi
|
|
# board), "Hardware" (older ARM), "cpu model" (others).
|
|
_CPU_FIELDS = ("model name", "Model", "Hardware", "cpu model")
|
|
|
|
|
|
def parse_cpu_model(cpuinfo_text: str) -> str:
|
|
found: dict[str, str] = {}
|
|
for line in cpuinfo_text.splitlines():
|
|
if ":" not in line:
|
|
continue
|
|
k, _, v = line.partition(":")
|
|
k, v = k.strip(), v.strip()
|
|
if k in _CPU_FIELDS and k not in found and v:
|
|
found[k] = v
|
|
for f in _CPU_FIELDS:
|
|
if f in found:
|
|
return found[f]
|
|
return "unknown"
|
|
|
|
|
|
def _host_cpu() -> str:
|
|
try:
|
|
model = parse_cpu_model(open("/proc/cpuinfo").read())
|
|
if model != "unknown":
|
|
return model
|
|
except OSError:
|
|
pass
|
|
if platform.system() == "Darwin": # macOS has no /proc
|
|
try:
|
|
import subprocess
|
|
|
|
out = subprocess.run(
|
|
["sysctl", "-n", "machdep.cpu.brand_string"],
|
|
capture_output=True, text=True, timeout=2,
|
|
)
|
|
if out.returncode == 0 and out.stdout.strip():
|
|
return out.stdout.strip()
|
|
except Exception: # noqa: BLE001
|
|
pass
|
|
return platform.processor() or "unknown"
|