from __future__ import annotations from dataclasses import asdict, dataclass from pathlib import Path import os import platform import shutil @dataclass(slots=True) class HardwareSpecs: hostname: str platform: str cpu_model: str physical_cores: int logical_cores: int memory_total_gb: float memory_available_gb: float disk_total_gb: float disk_free_gb: float python_version: str cuda_available: bool cuda_device: str def to_dict(self) -> dict[str, object]: return asdict(self) def collect_hardware_specs() -> HardwareSpecs: try: import psutil except Exception: # pragma: no cover - psutil is expected to be present in the venv psutil = None hostname = platform.node() or os.environ.get("COMPUTERNAME", "unknown") platform_name = f"{platform.system()} {platform.release()}" cpu_model = platform.processor() or platform.machine() or "unknown" physical_cores = psutil.cpu_count(logical=False) if psutil else 0 logical_cores = psutil.cpu_count(logical=True) if psutil else os.cpu_count() or 0 memory_total_gb = 0.0 memory_available_gb = 0.0 disk_total_gb = 0.0 disk_free_gb = 0.0 if psutil: memory = psutil.virtual_memory() memory_total_gb = memory.total / (1024**3) memory_available_gb = memory.available / (1024**3) disk = psutil.disk_usage(str(Path.home().anchor or Path.cwd().anchor or Path.cwd())) disk_total_gb = disk.total / (1024**3) disk_free_gb = disk.free / (1024**3) cuda_available = False cuda_device = "cpu" try: import torch cuda_available = bool(torch.cuda.is_available()) if cuda_available: cuda_device = torch.cuda.get_device_name(0) except Exception: pass return HardwareSpecs( hostname=hostname, platform=platform_name, cpu_model=cpu_model, physical_cores=int(physical_cores or 0), logical_cores=int(logical_cores or 0), memory_total_gb=memory_total_gb, memory_available_gb=memory_available_gb, disk_total_gb=disk_total_gb, disk_free_gb=disk_free_gb, python_version=platform.python_version(), cuda_available=cuda_available, cuda_device=cuda_device, ) def hardware_table_rows(specs: HardwareSpecs) -> list[dict[str, str]]: return [ {"Metric": "Hostname", "Value": specs.hostname}, {"Metric": "Platform", "Value": specs.platform}, {"Metric": "CPU", "Value": specs.cpu_model}, {"Metric": "Physical Cores", "Value": str(specs.physical_cores)}, {"Metric": "Logical Cores", "Value": str(specs.logical_cores)}, {"Metric": "Memory Total (GB)", "Value": f"{specs.memory_total_gb:.2f}"}, {"Metric": "Memory Available (GB)", "Value": f"{specs.memory_available_gb:.2f}"}, {"Metric": "Disk Total (GB)", "Value": f"{specs.disk_total_gb:.2f}"}, {"Metric": "Disk Free (GB)", "Value": f"{specs.disk_free_gb:.2f}"}, {"Metric": "Python", "Value": specs.python_version}, {"Metric": "CUDA", "Value": "yes" if specs.cuda_available else "no"}, {"Metric": "CUDA Device", "Value": specs.cuda_device}, ]