Files
2026-07-13 12:10:44 +08:00

109 lines
3.6 KiB
Python

"""Resolve human-readable names for Intel GPUs via OpenVINO."""
import logging
import re
logger = logging.getLogger(__name__)
class IntelGpuNameResolver:
"""Build a pdev -> normalized device name map by enumerating OpenVINO GPUs.
The lookup is performed once on first access and cached for the process
lifetime. OpenVINO exposes DEVICE_PCI_INFO (domain/bus/device/function) and
FULL_DEVICE_NAME for each GPU it can see, which is enough to associate the
name with the pdev string used by DRM fdinfo.
"""
_names: dict[str, str] | None = None
def get_names(self) -> dict[str, str]:
if self._names is not None:
return self._names
names: dict[str, str] = {}
try:
from openvino import Core
except ImportError:
logger.debug("OpenVINO unavailable; cannot resolve Intel GPU names")
self._names = names
return names
try:
core = Core()
devices = core.available_devices
except Exception as exc:
logger.debug(f"OpenVINO Core initialization failed: {exc}")
self._names = names
return names
cpu_name: str | None = None
if "CPU" in devices:
try:
cpu_name = self._strip_trademarks(
core.get_property("CPU", "FULL_DEVICE_NAME")
)
except Exception as exc:
logger.debug(f"Failed to read CPU FULL_DEVICE_NAME: {exc}")
for device in devices:
if not device.startswith("GPU"):
continue
try:
pci = core.get_property(device, "DEVICE_PCI_INFO")
raw_name = core.get_property(device, "FULL_DEVICE_NAME")
device_type = core.get_property(device, "DEVICE_TYPE")
except Exception as exc:
logger.debug(f"Failed to read properties for {device}: {exc}")
continue
pdev = self._format_pdev(pci)
if not pdev:
continue
names[pdev] = self._resolve_name(raw_name, device_type, cpu_name)
self._names = names
return names
@staticmethod
def _format_pdev(pci) -> str | None:
try:
return f"{pci.domain:04x}:{pci.bus:02x}:{pci.device:02x}.{pci.function:x}"
except AttributeError:
return None
@classmethod
def _resolve_name(cls, raw_name: str, device_type, cpu_name: str | None) -> str:
"""Build a display name for a GPU.
Modern integrated Intel GPUs are reported by OpenVINO with a generic
FULL_DEVICE_NAME like "Intel(R) Graphics (iGPU)" that gives no model
information. Since the iGPU is part of the CPU on these platforms, fall
back to the CPU name (which OpenVINO does report specifically) and
suffix it with "iGPU" so it's clear what the entry is.
"""
is_integrated = "INTEGRATED" in str(device_type).upper()
if is_integrated and cpu_name:
short_cpu = re.sub(r"^Intel\s+", "", cpu_name)
return f"{short_cpu} iGPU"
return cls._normalize_name(raw_name)
@classmethod
def _normalize_name(cls, name: str) -> str:
cleaned = cls._strip_trademarks(name)
cleaned = re.sub(r"\s*\((?:i|d)GPU\)\s*$", "", cleaned, flags=re.IGNORECASE)
return " ".join(cleaned.split())
@staticmethod
def _strip_trademarks(name: str) -> str:
cleaned = re.sub(r"\(R\)|\(TM\)", "", name)
return " ".join(cleaned.split())
intel_gpu_name_resolver = IntelGpuNameResolver()