211 lines
6.2 KiB
Python
211 lines
6.2 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
from modelforge_api.domain.enums import Availability
|
|
from modelforge_api.domain.hardware import (
|
|
AcceleratorInventory,
|
|
AcceleratorTelemetry,
|
|
HostInventory,
|
|
NvidiaCollection,
|
|
ObservedValue,
|
|
StorageObservation,
|
|
)
|
|
|
|
|
|
class FakeHostCollector:
|
|
def __init__(self, identity: str = "node-identity") -> None:
|
|
self.identity = identity
|
|
|
|
def collect(self) -> HostInventory:
|
|
return HostInventory(
|
|
identity_key=self.identity,
|
|
identity_source="test",
|
|
hostname="forge-host",
|
|
display_name="Forge Host",
|
|
os_name="TestOS",
|
|
os_version=ObservedValue.known("1"),
|
|
architecture="x86_64",
|
|
kernel_version=ObservedValue.known("1.0"),
|
|
cpu_model=ObservedValue.known("Test CPU"),
|
|
logical_cpu_count=ObservedValue.known(16),
|
|
physical_core_count=ObservedValue.known(8),
|
|
total_ram_bytes=ObservedValue.known(64 * 1024**3),
|
|
available_ram_bytes=ObservedValue.known(32 * 1024**3),
|
|
agent_version="0.1.0",
|
|
storage=[
|
|
StorageObservation(
|
|
purpose="artifacts",
|
|
path=str(Path("/artifacts")),
|
|
total_bytes=ObservedValue.known(1000),
|
|
used_bytes=ObservedValue.known(400),
|
|
free_bytes=ObservedValue.known(600),
|
|
)
|
|
],
|
|
)
|
|
|
|
|
|
def accelerator(device_uuid: str = "GPU-A", name: str = "Fake GPU") -> AcceleratorInventory:
|
|
return AcceleratorInventory(
|
|
device_index=0,
|
|
device_uuid=device_uuid,
|
|
pci_bus_id=ObservedValue.known("0000:01:00.0"),
|
|
name=name,
|
|
architecture=ObservedValue.known("ada"),
|
|
compute_capability_major=ObservedValue.known(8),
|
|
compute_capability_minor=ObservedValue.known(9),
|
|
total_vram_bytes=ObservedValue.known(16 * 1024**3),
|
|
driver_version=ObservedValue.known("600.1"),
|
|
cuda_driver_version=ObservedValue.known("13.0"),
|
|
mig_mode_current=ObservedValue.absent(Availability.UNSUPPORTED),
|
|
)
|
|
|
|
|
|
def telemetry(device_uuid: str = "GPU-A", utilization: int = 25) -> AcceleratorTelemetry:
|
|
return AcceleratorTelemetry(
|
|
device_uuid=device_uuid,
|
|
used_vram_bytes=ObservedValue.known(2 * 1024**3),
|
|
free_vram_bytes=ObservedValue.known(14 * 1024**3),
|
|
gpu_utilization_percent=ObservedValue.known(utilization),
|
|
memory_utilization_percent=ObservedValue.known(10),
|
|
temperature_c=ObservedValue.known(45),
|
|
power_draw_w=ObservedValue.known(80.0),
|
|
power_limit_w=ObservedValue.known(320.0),
|
|
graphics_clock_mhz=ObservedValue.known(2000),
|
|
memory_clock_mhz=ObservedValue.known(10000),
|
|
fan_speed_percent=ObservedValue.absent(Availability.UNSUPPORTED),
|
|
performance_state=ObservedValue.known("P2"),
|
|
)
|
|
|
|
|
|
class FakeAcceleratorCollector:
|
|
def __init__(
|
|
self,
|
|
devices: list[AcceleratorInventory] | None = None,
|
|
availability: Availability = Availability.KNOWN,
|
|
utilization: int = 25,
|
|
) -> None:
|
|
self.devices = devices or []
|
|
self.availability = availability
|
|
self.utilization = utilization
|
|
|
|
def collect(self) -> NvidiaCollection:
|
|
return NvidiaCollection(
|
|
availability=self.availability,
|
|
reason="NVML unavailable"
|
|
if self.availability is not Availability.KNOWN
|
|
else ("no NVIDIA devices detected" if not self.devices else None),
|
|
inventory=self.devices,
|
|
telemetry=[telemetry(item.device_uuid, self.utilization) for item in self.devices],
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class Memory:
|
|
total: int = 16 * 1024**3
|
|
used: int = 2 * 1024**3
|
|
free: int = 14 * 1024**3
|
|
|
|
|
|
@dataclass
|
|
class Utilization:
|
|
gpu: int = 25
|
|
memory: int = 10
|
|
|
|
|
|
@dataclass
|
|
class Pci:
|
|
busId: bytes = b"0000:01:00.0"
|
|
|
|
|
|
class FakeNvml:
|
|
class NVMLError(Exception):
|
|
pass
|
|
|
|
class NVMLError_NotSupported(NVMLError):
|
|
pass
|
|
|
|
NVML_TEMPERATURE_GPU = 0
|
|
NVML_CLOCK_GRAPHICS = 0
|
|
NVML_CLOCK_MEM = 1
|
|
NVML_DEVICE_ARCH_ADA = 7
|
|
|
|
def __init__(
|
|
self,
|
|
count: int = 1,
|
|
init_error: bool = False,
|
|
unsupported_power: bool = False,
|
|
device_error: int | None = None,
|
|
) -> None:
|
|
self.count = count
|
|
self.init_error = init_error
|
|
self.unsupported_power = unsupported_power
|
|
self.device_error = device_error
|
|
self.shutdown_calls = 0
|
|
|
|
def nvmlInit(self):
|
|
if self.init_error:
|
|
raise self.NVMLError("driver")
|
|
|
|
def nvmlShutdown(self):
|
|
self.shutdown_calls += 1
|
|
|
|
def nvmlDeviceGetCount(self):
|
|
return self.count
|
|
|
|
def nvmlSystemGetDriverVersion(self):
|
|
return b"600.1"
|
|
|
|
def nvmlSystemGetCudaDriverVersion_v2(self):
|
|
return 13000
|
|
|
|
def nvmlDeviceGetHandleByIndex(self, index):
|
|
if self.device_error == index:
|
|
raise self.NVMLError("device")
|
|
return index
|
|
|
|
def nvmlDeviceGetUUID(self, handle):
|
|
return f"GPU-{handle}".encode()
|
|
|
|
def nvmlDeviceGetName(self, handle):
|
|
return f"Fake GPU {handle}".encode()
|
|
|
|
def nvmlDeviceGetMemoryInfo(self, handle):
|
|
return Memory()
|
|
|
|
def nvmlDeviceGetPciInfo(self, handle):
|
|
return Pci(busId=f"0000:0{handle + 1}:00.0".encode())
|
|
|
|
def nvmlDeviceGetCudaComputeCapability(self, handle):
|
|
return (8, 9)
|
|
|
|
def nvmlDeviceGetMigMode(self, handle):
|
|
raise self.NVMLError_NotSupported()
|
|
|
|
def nvmlDeviceGetArchitecture(self, handle):
|
|
return self.NVML_DEVICE_ARCH_ADA
|
|
|
|
def nvmlDeviceGetUtilizationRates(self, handle):
|
|
return Utilization()
|
|
|
|
def nvmlDeviceGetTemperature(self, handle, sensor):
|
|
return 45
|
|
|
|
def nvmlDeviceGetPowerUsage(self, handle):
|
|
if self.unsupported_power:
|
|
raise self.NVMLError_NotSupported()
|
|
return 80000
|
|
|
|
def nvmlDeviceGetEnforcedPowerLimit(self, handle):
|
|
return 320000
|
|
|
|
def nvmlDeviceGetClockInfo(self, handle, clock):
|
|
return 2000
|
|
|
|
def nvmlDeviceGetFanSpeed(self, handle):
|
|
raise self.NVMLError_NotSupported()
|
|
|
|
def nvmlDeviceGetPerformanceState(self, handle):
|
|
return 2
|