Files
andyyyy64--whichllm/tests/test_nvidia_detection.py
2026-07-13 12:29:01 +08:00

195 lines
6.2 KiB
Python

import builtins
import subprocess
from types import SimpleNamespace
from unittest.mock import Mock
from whichllm.hardware.nvidia import detect_nvidia_gpus
def test_nvidia_smi_fallback_when_pynvml_missing(monkeypatch):
real_import = builtins.__import__
def fake_import(name, *args, **kwargs):
if name == "pynvml":
raise ImportError
return real_import(name, *args, **kwargs)
def fake_run(*args, **kwargs):
return SimpleNamespace(stdout="NVIDIA GeForce RTX 5060 Ti, 16303\n")
monkeypatch.setattr(builtins, "__import__", fake_import)
monkeypatch.setattr(subprocess, "run", fake_run)
gpus = detect_nvidia_gpus()
assert len(gpus) == 1
assert gpus[0].name == "NVIDIA GeForce RTX 5060 Ti"
assert gpus[0].vendor == "nvidia"
assert gpus[0].vram_bytes == 16303 * 1024**2
def test_nvidia_smi_fallback_applies_rtx_a3000_laptop_catalog(monkeypatch):
real_import = builtins.__import__
def fake_import(name, *args, **kwargs):
if name == "pynvml":
raise ImportError
return real_import(name, *args, **kwargs)
def fake_run(*args, **kwargs):
return SimpleNamespace(stdout="NVIDIA RTX A3000 Laptop GPU, 6144 MiB\n")
monkeypatch.setattr(builtins, "__import__", fake_import)
monkeypatch.setattr(subprocess, "run", fake_run)
gpus = detect_nvidia_gpus()
assert len(gpus) == 1
assert gpus[0].name == "NVIDIA RTX A3000 Laptop GPU"
assert gpus[0].compute_capability == (8, 6)
assert gpus[0].memory_bandwidth_gbps == 264.0
def test_nvidia_smi_fallback_resolves_laptop_5090_via_dbgpu(monkeypatch):
# Regression for #74: a laptop RTX 5090 must not inherit the desktop
# 1792 GB/s bandwidth. dbgpu carries "GeForce RTX 5090 Mobile" (~896).
real_import = builtins.__import__
def fake_import(name, *args, **kwargs):
if name == "pynvml":
raise ImportError
return real_import(name, *args, **kwargs)
def fake_run(*args, **kwargs):
return SimpleNamespace(stdout="NVIDIA GeForce RTX 5090 Laptop GPU, 24564 MiB\n")
monkeypatch.setattr(builtins, "__import__", fake_import)
monkeypatch.setattr(subprocess, "run", fake_run)
gpus = detect_nvidia_gpus()
assert len(gpus) == 1
assert gpus[0].name == "NVIDIA GeForce RTX 5090 Laptop GPU"
bw = gpus[0].memory_bandwidth_gbps
assert bw is not None
assert bw < 1500.0 # mobile ~896, not the 1792 desktop value
def test_nvidia_smi_fallback_when_nvml_init_fails(monkeypatch):
class FakeNVMLError(Exception):
pass
fake_pynvml = SimpleNamespace(
NVMLError=FakeNVMLError,
nvmlInit=Mock(side_effect=FakeNVMLError("NVML unavailable")),
)
real_import = builtins.__import__
def fake_import(name, *args, **kwargs):
if name == "pynvml":
return fake_pynvml
return real_import(name, *args, **kwargs)
def fake_run(*args, **kwargs):
return SimpleNamespace(stdout="NVIDIA DGX Spark, 128000 MiB\n")
monkeypatch.setattr(builtins, "__import__", fake_import)
monkeypatch.setattr(subprocess, "run", fake_run)
gpus = detect_nvidia_gpus()
assert len(gpus) == 1
assert gpus[0].name == "NVIDIA DGX Spark"
assert gpus[0].vendor == "nvidia"
assert gpus[0].vram_bytes == 128000 * 1024**2
assert gpus[0].shared_memory is True
def test_nvidia_smi_fallback_detects_gb10_with_na_memory(monkeypatch):
real_import = builtins.__import__
def fake_import(name, *args, **kwargs):
if name == "pynvml":
raise ImportError
return real_import(name, *args, **kwargs)
def fake_run(*args, **kwargs):
return SimpleNamespace(stdout="NVIDIA GB10, [N/A]\n")
monkeypatch.setattr(builtins, "__import__", fake_import)
monkeypatch.setattr(subprocess, "run", fake_run)
monkeypatch.setattr(
"whichllm.hardware.memory.detect_ram_bytes", lambda: 128 * 1024**3
)
gpus = detect_nvidia_gpus()
assert len(gpus) == 1
assert gpus[0].name == "NVIDIA GB10"
assert gpus[0].vendor == "nvidia"
assert gpus[0].vram_bytes == 128 * 1024**3
assert gpus[0].shared_memory is True
assert gpus[0].compute_capability == (12, 1)
assert gpus[0].memory_bandwidth_gbps == 273.0
def test_nvml_detects_gb10_when_memory_info_is_unavailable(monkeypatch):
class FakeNVMLError(Exception):
pass
handle = object()
fake_pynvml = SimpleNamespace(
NVMLError=FakeNVMLError,
nvmlInit=Mock(),
nvmlDeviceGetCount=Mock(return_value=1),
nvmlSystemGetDriverVersion=Mock(return_value=b"580.142"),
nvmlSystemGetCudaDriverVersion_v2=Mock(return_value=12010),
nvmlDeviceGetHandleByIndex=Mock(return_value=handle),
nvmlDeviceGetName=Mock(return_value="NVIDIA GB10"),
nvmlDeviceGetMemoryInfo=Mock(side_effect=FakeNVMLError("not supported")),
nvmlShutdown=Mock(),
)
real_import = builtins.__import__
def fake_import(name, *args, **kwargs):
if name == "pynvml":
return fake_pynvml
return real_import(name, *args, **kwargs)
def fake_run(*args, **kwargs):
raise AssertionError("nvidia-smi fallback should not be used")
monkeypatch.setattr(builtins, "__import__", fake_import)
monkeypatch.setattr(subprocess, "run", fake_run)
monkeypatch.setattr(
"whichllm.hardware.memory.detect_ram_bytes", lambda: 128 * 1024**3
)
gpus = detect_nvidia_gpus()
assert len(gpus) == 1
assert gpus[0].name == "NVIDIA GB10"
assert gpus[0].vendor == "nvidia"
assert gpus[0].vram_bytes == 128 * 1024**3
assert gpus[0].shared_memory is True
assert gpus[0].compute_capability == (12, 1)
assert gpus[0].cuda_version == "12.1"
assert gpus[0].memory_bandwidth_gbps == 273.0
def test_nvidia_smi_fallback_returns_empty_on_command_failure(monkeypatch):
real_import = builtins.__import__
def fake_import(name, *args, **kwargs):
if name == "pynvml":
raise ImportError
return real_import(name, *args, **kwargs)
def fake_run(*args, **kwargs):
raise FileNotFoundError
monkeypatch.setattr(builtins, "__import__", fake_import)
monkeypatch.setattr(subprocess, "run", fake_run)
assert detect_nvidia_gpus() == []