mate-runtime-cuda 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mate_runtime_cuda-0.1.0/.gitignore +30 -0
- mate_runtime_cuda-0.1.0/PKG-INFO +15 -0
- mate_runtime_cuda-0.1.0/README.md +19 -0
- mate_runtime_cuda-0.1.0/pyproject.toml +41 -0
- mate_runtime_cuda-0.1.0/src/mate_runtime_cuda/__init__.py +28 -0
- mate_runtime_cuda-0.1.0/src/mate_runtime_cuda/_detect.py +85 -0
- mate_runtime_cuda-0.1.0/src/mate_runtime_cuda/_names.py +95 -0
- mate_runtime_cuda-0.1.0/tests/__init__.py +0 -0
- mate_runtime_cuda-0.1.0/tests/fixtures.py +11 -0
- mate_runtime_cuda-0.1.0/tests/test_detect.py +136 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
.venv/
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
|
|
10
|
+
# uv
|
|
11
|
+
uv.lock
|
|
12
|
+
|
|
13
|
+
# Node / Cloudflare Worker
|
|
14
|
+
worker/node_modules/
|
|
15
|
+
worker/.wrangler/
|
|
16
|
+
worker/dist/
|
|
17
|
+
|
|
18
|
+
# Results (local benchmark output)
|
|
19
|
+
results/
|
|
20
|
+
|
|
21
|
+
# Secrets / local config
|
|
22
|
+
.env
|
|
23
|
+
*.env.local
|
|
24
|
+
|
|
25
|
+
# OS
|
|
26
|
+
.DS_Store
|
|
27
|
+
Thumbs.db
|
|
28
|
+
|
|
29
|
+
# Internal planning notes
|
|
30
|
+
BENCH_NOTES.md
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mate-runtime-cuda
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: NVIDIA CUDA runtime plugin for mate-bench
|
|
5
|
+
Project-URL: Homepage, https://github.com/T0nd3/mate-bench
|
|
6
|
+
Project-URL: Repository, https://github.com/T0nd3/mate-bench
|
|
7
|
+
Author-email: Benjamin Fäuster <benjamin.faeuster@web.de>
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Topic :: System :: Benchmark
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Requires-Dist: mate-bench<0.2,>=0.1
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# mate-runtime-cuda
|
|
2
|
+
|
|
3
|
+
NVIDIA CUDA runtime plugin for [mate-bench](https://github.com/T0nd3/mate-bench).
|
|
4
|
+
|
|
5
|
+
Detects GPU name, chip, VRAM, CUDA version and driver from `nvidia-smi`.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install mate-bench mate-runtime-cuda
|
|
9
|
+
mate list-runtimes
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- NVIDIA GPU with drivers installed (`nvidia-smi` must be in PATH)
|
|
15
|
+
- CUDA 11.x or newer
|
|
16
|
+
|
|
17
|
+
## Supported GPUs
|
|
18
|
+
|
|
19
|
+
Pascal (GTX 10xx) through Blackwell (RTX 50xx), including data centre GPUs (A100, H100, V100).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mate-runtime-cuda"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "NVIDIA CUDA runtime plugin for mate-bench"
|
|
5
|
+
requires-python = ">=3.11"
|
|
6
|
+
license = {text = "MIT"}
|
|
7
|
+
authors = [{name = "Benjamin Fäuster", email = "benjamin.faeuster@web.de"}]
|
|
8
|
+
classifiers = [
|
|
9
|
+
"License :: OSI Approved :: MIT License",
|
|
10
|
+
"Programming Language :: Python :: 3",
|
|
11
|
+
"Programming Language :: Python :: 3.11",
|
|
12
|
+
"Programming Language :: Python :: 3.12",
|
|
13
|
+
"Topic :: System :: Benchmark",
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"mate-bench>=0.1,<0.2",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.urls]
|
|
20
|
+
Homepage = "https://github.com/T0nd3/mate-bench"
|
|
21
|
+
Repository = "https://github.com/T0nd3/mate-bench"
|
|
22
|
+
|
|
23
|
+
[project.entry-points."mate_bench.runtime"]
|
|
24
|
+
cuda = "mate_runtime_cuda:CudaRuntime"
|
|
25
|
+
|
|
26
|
+
[tool.mate-bench]
|
|
27
|
+
requires_mate_bench = ">=0.1,<0.2"
|
|
28
|
+
api_version = 1
|
|
29
|
+
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = ["pytest>=8.0", "ruff>=0.4"]
|
|
32
|
+
|
|
33
|
+
[tool.pytest.ini_options]
|
|
34
|
+
markers = ["integration: requires an NVIDIA GPU with CUDA drivers"]
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["hatchling"]
|
|
38
|
+
build-backend = "hatchling.build"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/mate_runtime_cuda"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from mate_bench.plugin import PluginManifest
|
|
6
|
+
|
|
7
|
+
from ._detect import GpuInfo, is_cuda_available, query_gpu
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CudaRuntime:
|
|
11
|
+
name = "cuda"
|
|
12
|
+
manifest = PluginManifest(requires_mate_bench=">=0.1,<0.2", api_version=1)
|
|
13
|
+
|
|
14
|
+
def is_available(self) -> bool:
|
|
15
|
+
return is_cuda_available()
|
|
16
|
+
|
|
17
|
+
def gpu_info(self, index: int = 0) -> dict[str, Any]:
|
|
18
|
+
info: GpuInfo = query_gpu(index)
|
|
19
|
+
return {
|
|
20
|
+
"gpu_vendor": "nvidia",
|
|
21
|
+
"gpu_name": info.name,
|
|
22
|
+
"gpu_chip": info.chip,
|
|
23
|
+
"vram_gb": info.vram_gb,
|
|
24
|
+
"runtime": info.cuda_version,
|
|
25
|
+
"driver": info.driver_version,
|
|
26
|
+
"_gpu_name_raw": info.name_raw,
|
|
27
|
+
"_gpu_name_known": info.name_known,
|
|
28
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import subprocess
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from ._names import chip_from_name, normalize
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class GpuInfo:
|
|
12
|
+
chip: str # die codename, e.g. "AD102"
|
|
13
|
+
name: str # normalized, e.g. "RTX 4090"
|
|
14
|
+
name_raw: str # as reported by nvidia-smi, e.g. "NVIDIA GeForce RTX 4090"
|
|
15
|
+
name_known: bool # False → unknown model, stored raw + flagged
|
|
16
|
+
vram_gb: float
|
|
17
|
+
cuda_version: str # e.g. "CUDA 12.4"
|
|
18
|
+
driver_version: str # e.g. "550.54.15"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_cuda_available() -> bool:
|
|
22
|
+
"""CUDA is available if nvidia-smi lists at least one GPU."""
|
|
23
|
+
return bool(_run(["nvidia-smi", "-L"]))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def query_gpu(index: int = 0) -> GpuInfo:
|
|
27
|
+
"""Query GPU info for the given device index via nvidia-smi."""
|
|
28
|
+
rows = _query_smi(
|
|
29
|
+
["name", "memory.total", "driver_version", "cuda_version"],
|
|
30
|
+
units=False,
|
|
31
|
+
)
|
|
32
|
+
if not rows:
|
|
33
|
+
raise RuntimeError("No NVIDIA GPU found. Are the drivers installed?")
|
|
34
|
+
if index >= len(rows):
|
|
35
|
+
raise IndexError(f"GPU index {index} out of range ({len(rows)} GPUs found)")
|
|
36
|
+
|
|
37
|
+
row = rows[index]
|
|
38
|
+
raw_name = row[0].strip()
|
|
39
|
+
vram_mib = _parse_float(row[1])
|
|
40
|
+
driver = row[2].strip()
|
|
41
|
+
cuda = row[3].strip()
|
|
42
|
+
|
|
43
|
+
name, name_known = normalize(raw_name)
|
|
44
|
+
chip, chip_known = chip_from_name(name)
|
|
45
|
+
if not chip_known:
|
|
46
|
+
chip = name # fall back to display name as chip key
|
|
47
|
+
|
|
48
|
+
return GpuInfo(
|
|
49
|
+
chip=chip,
|
|
50
|
+
name=name,
|
|
51
|
+
name_raw=raw_name,
|
|
52
|
+
name_known=name_known and chip_known,
|
|
53
|
+
vram_gb=round(vram_mib / 1024, 1),
|
|
54
|
+
cuda_version=f"CUDA {cuda}" if cuda else "CUDA unknown",
|
|
55
|
+
driver_version=driver or "unknown",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# ── internal helpers ──────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _run(cmd: list[str], timeout: int = 10) -> str:
|
|
63
|
+
try:
|
|
64
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
|
|
65
|
+
return result.stdout
|
|
66
|
+
except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
|
|
67
|
+
return ""
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _query_smi(fields: list[str], units: bool = False) -> list[list[str]]:
|
|
71
|
+
"""Run nvidia-smi --query-gpu and return parsed rows."""
|
|
72
|
+
cmd = [
|
|
73
|
+
"nvidia-smi",
|
|
74
|
+
f"--query-gpu={','.join(fields)}",
|
|
75
|
+
"--format=csv,noheader" + ("" if units else ",nounits"),
|
|
76
|
+
]
|
|
77
|
+
out = _run(cmd)
|
|
78
|
+
if not out.strip():
|
|
79
|
+
return []
|
|
80
|
+
return [line.split(",") for line in out.strip().splitlines() if line.strip()]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _parse_float(s: str) -> float:
|
|
84
|
+
m = re.search(r"[\d.]+", s)
|
|
85
|
+
return float(m.group()) if m else 0.0
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
# (substring to match in normalized name, chip codename)
|
|
6
|
+
# Ordered from most specific to least specific.
|
|
7
|
+
_GPU_CHIP_MAP: list[tuple[str, str]] = [
|
|
8
|
+
# Blackwell — RTX 50xx
|
|
9
|
+
("RTX 5090", "GB202"),
|
|
10
|
+
("RTX 5080", "GB203"),
|
|
11
|
+
("RTX 5070 Ti", "GB203"),
|
|
12
|
+
("RTX 5070", "GB205"),
|
|
13
|
+
("RTX 5060 Ti", "GB206"),
|
|
14
|
+
("RTX 5060", "GB206"),
|
|
15
|
+
# Ada Lovelace — RTX 40xx + professional
|
|
16
|
+
("RTX 6000 Ada", "AD102"),
|
|
17
|
+
("RTX 4090", "AD102"),
|
|
18
|
+
("RTX 4080 Super", "AD103"),
|
|
19
|
+
("RTX 4080", "AD103"),
|
|
20
|
+
("RTX 4070 Ti Super", "AD103"),
|
|
21
|
+
("RTX 4070 Ti", "AD104"),
|
|
22
|
+
("RTX 4070 Super", "AD104"),
|
|
23
|
+
("RTX 4070", "AD104"),
|
|
24
|
+
("RTX 4500 Ada", "AD104"),
|
|
25
|
+
("RTX 4000 Ada", "AD104"),
|
|
26
|
+
("RTX 4060 Ti", "AD106"),
|
|
27
|
+
("RTX 4060", "AD107"),
|
|
28
|
+
# Hopper
|
|
29
|
+
("H200", "GH200"),
|
|
30
|
+
("H100", "GH100"),
|
|
31
|
+
# Ampere — data centre
|
|
32
|
+
("A100", "GA100"),
|
|
33
|
+
("A800", "GA100"),
|
|
34
|
+
("RTX A6000", "GA102"),
|
|
35
|
+
("RTX A5000", "GA102"),
|
|
36
|
+
("RTX A4000", "GA104"),
|
|
37
|
+
("RTX A3000", "GA104"),
|
|
38
|
+
("RTX A2000", "GA106"),
|
|
39
|
+
# Ampere — RTX 30xx
|
|
40
|
+
("RTX 3090 Ti", "GA102"),
|
|
41
|
+
("RTX 3090", "GA102"),
|
|
42
|
+
("RTX 3080 Ti", "GA102"),
|
|
43
|
+
("RTX 3080", "GA102"),
|
|
44
|
+
("RTX 3070 Ti", "GA104"),
|
|
45
|
+
("RTX 3070", "GA104"),
|
|
46
|
+
("RTX 3060 Ti", "GA104"),
|
|
47
|
+
("RTX 3060", "GA106"),
|
|
48
|
+
("RTX 3050", "GA107"),
|
|
49
|
+
# Volta
|
|
50
|
+
("Titan V", "GV100"),
|
|
51
|
+
("V100", "GV100"),
|
|
52
|
+
# Turing — RTX 20xx
|
|
53
|
+
("RTX 2080 Ti", "TU102"),
|
|
54
|
+
("RTX 2080 Super", "TU104"),
|
|
55
|
+
("RTX 2080", "TU104"),
|
|
56
|
+
("RTX 2070 Super", "TU104"),
|
|
57
|
+
("RTX 2070", "TU106"),
|
|
58
|
+
("RTX 2060 Super", "TU106"),
|
|
59
|
+
("RTX 2060", "TU106"),
|
|
60
|
+
# Turing — GTX 16xx
|
|
61
|
+
("GTX 1660 Ti", "TU116"),
|
|
62
|
+
("GTX 1660 Super", "TU116"),
|
|
63
|
+
("GTX 1660", "TU116"),
|
|
64
|
+
("GTX 1650 Super", "TU116"),
|
|
65
|
+
("GTX 1650", "TU117"),
|
|
66
|
+
# Pascal — GTX 10xx
|
|
67
|
+
("Titan Xp", "GP102"),
|
|
68
|
+
("GTX 1080 Ti", "GP102"),
|
|
69
|
+
("GTX 1080", "GP104"),
|
|
70
|
+
("GTX 1070 Ti", "GP104"),
|
|
71
|
+
("GTX 1070", "GP104"),
|
|
72
|
+
("GTX 1060", "GP106"),
|
|
73
|
+
("GTX 1050 Ti", "GP107"),
|
|
74
|
+
("GTX 1050", "GP107"),
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
_STRIP_PREFIX = re.compile(r"^(?:NVIDIA\s+)?(?:GeForce\s+|Tesla\s+|Quadro\s+)?", re.IGNORECASE)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def normalize(raw: str) -> tuple[str, bool]:
|
|
81
|
+
"""Return (display_name, is_known_chip).
|
|
82
|
+
|
|
83
|
+
Strips vendor/product-line prefixes and looks up the die codename.
|
|
84
|
+
"""
|
|
85
|
+
display = _STRIP_PREFIX.sub("", raw).strip()
|
|
86
|
+
_, known = chip_from_name(display)
|
|
87
|
+
return display, known
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def chip_from_name(normalized: str) -> tuple[str, bool]:
|
|
91
|
+
"""Return (chip_codename, is_known) for a normalized GPU name."""
|
|
92
|
+
for substring, chip in _GPU_CHIP_MAP:
|
|
93
|
+
if substring.lower() in normalized.lower():
|
|
94
|
+
return chip, True
|
|
95
|
+
return normalized, False
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# nvidia-smi --query-gpu=name,memory.total,driver_version,cuda_version --format=csv,noheader,nounits
|
|
2
|
+
|
|
3
|
+
SMI_RTX4090 = "NVIDIA GeForce RTX 4090, 24564, 550.54.15, 12.4"
|
|
4
|
+
SMI_RTX3080 = "NVIDIA GeForce RTX 3080, 10240, 535.183.01, 12.2"
|
|
5
|
+
SMI_A100 = "NVIDIA A100-SXM4-80GB, 81920, 520.61.05, 11.8"
|
|
6
|
+
SMI_UNKNOWN = "NVIDIA SomeUnknownGPU, 8192, 550.54.15, 12.4"
|
|
7
|
+
SMI_EMPTY = ""
|
|
8
|
+
|
|
9
|
+
# nvidia-smi -L
|
|
10
|
+
SMI_LIST_RTX4090 = "GPU 0: NVIDIA GeForce RTX 4090 (UUID: GPU-abc123)\n"
|
|
11
|
+
SMI_LIST_EMPTY = ""
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from mate_runtime_cuda._detect import _query_smi, is_cuda_available, query_gpu
|
|
8
|
+
from mate_runtime_cuda._names import chip_from_name, normalize
|
|
9
|
+
|
|
10
|
+
from .fixtures import (
|
|
11
|
+
SMI_A100,
|
|
12
|
+
SMI_EMPTY,
|
|
13
|
+
SMI_LIST_EMPTY,
|
|
14
|
+
SMI_LIST_RTX4090,
|
|
15
|
+
SMI_RTX3080,
|
|
16
|
+
SMI_RTX4090,
|
|
17
|
+
SMI_UNKNOWN,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# ── is_cuda_available ─────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TestIsCudaAvailable:
|
|
24
|
+
def test_available_when_smi_returns_output(self):
|
|
25
|
+
with patch("mate_runtime_cuda._detect._run", return_value=SMI_LIST_RTX4090):
|
|
26
|
+
assert is_cuda_available() is True
|
|
27
|
+
|
|
28
|
+
def test_unavailable_when_smi_empty(self):
|
|
29
|
+
with patch("mate_runtime_cuda._detect._run", return_value=SMI_LIST_EMPTY):
|
|
30
|
+
assert is_cuda_available() is False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# ── _query_smi ────────────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class TestQuerySmi:
|
|
37
|
+
def test_parses_rtx4090_row(self):
|
|
38
|
+
with patch("mate_runtime_cuda._detect._run", return_value=SMI_RTX4090):
|
|
39
|
+
rows = _query_smi(["name", "memory.total", "driver_version", "cuda_version"])
|
|
40
|
+
assert len(rows) == 1
|
|
41
|
+
assert "RTX 4090" in rows[0][0]
|
|
42
|
+
|
|
43
|
+
def test_empty_returns_empty_list(self):
|
|
44
|
+
with patch("mate_runtime_cuda._detect._run", return_value=SMI_EMPTY):
|
|
45
|
+
assert _query_smi(["name"]) == []
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ── query_gpu ─────────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TestQueryGpu:
|
|
52
|
+
def test_rtx4090(self):
|
|
53
|
+
with patch("mate_runtime_cuda._detect._run", return_value=SMI_RTX4090):
|
|
54
|
+
info = query_gpu(0)
|
|
55
|
+
assert info.chip == "AD102"
|
|
56
|
+
assert info.name == "RTX 4090"
|
|
57
|
+
assert info.name_raw == "NVIDIA GeForce RTX 4090"
|
|
58
|
+
assert info.name_known is True
|
|
59
|
+
assert info.vram_gb == 24.0
|
|
60
|
+
assert info.cuda_version == "CUDA 12.4"
|
|
61
|
+
assert info.driver_version == "550.54.15"
|
|
62
|
+
|
|
63
|
+
def test_rtx3080(self):
|
|
64
|
+
with patch("mate_runtime_cuda._detect._run", return_value=SMI_RTX3080):
|
|
65
|
+
info = query_gpu(0)
|
|
66
|
+
assert info.chip == "GA102"
|
|
67
|
+
assert info.name == "RTX 3080"
|
|
68
|
+
assert info.vram_gb == 10.0
|
|
69
|
+
|
|
70
|
+
def test_a100(self):
|
|
71
|
+
with patch("mate_runtime_cuda._detect._run", return_value=SMI_A100):
|
|
72
|
+
info = query_gpu(0)
|
|
73
|
+
assert info.chip == "GA100"
|
|
74
|
+
assert info.vram_gb == 80.0
|
|
75
|
+
|
|
76
|
+
def test_unknown_gpu_not_known(self):
|
|
77
|
+
with patch("mate_runtime_cuda._detect._run", return_value=SMI_UNKNOWN):
|
|
78
|
+
info = query_gpu(0)
|
|
79
|
+
assert info.name_known is False
|
|
80
|
+
assert info.name == "SomeUnknownGPU"
|
|
81
|
+
|
|
82
|
+
def test_no_gpu_raises(self):
|
|
83
|
+
with (
|
|
84
|
+
patch("mate_runtime_cuda._detect._run", return_value=SMI_EMPTY),
|
|
85
|
+
pytest.raises(RuntimeError, match="No NVIDIA GPU found"),
|
|
86
|
+
):
|
|
87
|
+
query_gpu(0)
|
|
88
|
+
|
|
89
|
+
def test_index_out_of_range_raises(self):
|
|
90
|
+
with (
|
|
91
|
+
patch("mate_runtime_cuda._detect._run", return_value=SMI_RTX4090),
|
|
92
|
+
pytest.raises(IndexError),
|
|
93
|
+
):
|
|
94
|
+
query_gpu(1)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# ── normalize & chip_from_name ────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class TestNormalize:
|
|
101
|
+
@pytest.mark.parametrize(
|
|
102
|
+
"raw, expected_name",
|
|
103
|
+
[
|
|
104
|
+
("NVIDIA GeForce RTX 4090", "RTX 4090"),
|
|
105
|
+
("NVIDIA GeForce RTX 3080", "RTX 3080"),
|
|
106
|
+
("NVIDIA A100-SXM4-80GB", "A100-SXM4-80GB"),
|
|
107
|
+
("NVIDIA GeForce GTX 1080 Ti", "GTX 1080 Ti"),
|
|
108
|
+
("NVIDIA GeForce RTX 2080 Ti", "RTX 2080 Ti"),
|
|
109
|
+
],
|
|
110
|
+
)
|
|
111
|
+
def test_strips_prefix(self, raw, expected_name):
|
|
112
|
+
name, _ = normalize(raw)
|
|
113
|
+
assert name == expected_name
|
|
114
|
+
|
|
115
|
+
@pytest.mark.parametrize(
|
|
116
|
+
"raw, expected_chip",
|
|
117
|
+
[
|
|
118
|
+
("NVIDIA GeForce RTX 4090", "AD102"),
|
|
119
|
+
("NVIDIA GeForce RTX 3090", "GA102"),
|
|
120
|
+
("NVIDIA GeForce RTX 3080", "GA102"),
|
|
121
|
+
("NVIDIA GeForce RTX 3070", "GA104"),
|
|
122
|
+
("NVIDIA GeForce RTX 2080 Ti", "TU102"),
|
|
123
|
+
("NVIDIA GeForce GTX 1080 Ti", "GP102"),
|
|
124
|
+
("NVIDIA H100", "GH100"),
|
|
125
|
+
("NVIDIA A100-SXM4-80GB", "GA100"),
|
|
126
|
+
],
|
|
127
|
+
)
|
|
128
|
+
def test_known_chips(self, raw, expected_chip):
|
|
129
|
+
name, _ = normalize(raw)
|
|
130
|
+
chip, known = chip_from_name(name)
|
|
131
|
+
assert chip == expected_chip
|
|
132
|
+
assert known is True
|
|
133
|
+
|
|
134
|
+
def test_unknown_chip(self):
|
|
135
|
+
_, known = normalize("NVIDIA Futuristic GPU XYZ")
|
|
136
|
+
assert known is False
|