mirror of
https://github.com/Heretek-AI/Strata.git
synced 2026-11-07 10:05:58 -10:00
Hardware list: AMD cards are counted from the kernel's KFD files when there is no setup module and no rocm-smi (ROCm from a Python venv), instead of not at all
This commit is contained in:
1 parent
ab083a693f
commit
bc694233bf
2 files changed
+91
No files matched your search
@@ -976,6 +976,8 @@ class Strata:
|
||||
amd = []
|
||||
if not WIN and not amd and shutil.which("rocm-smi"):
|
||||
amd = rocm_smi_gpus()
|
||||
if not WIN and not amd: # no setup module, no rocm-smi (ROCm from a Python venv): the kernel's own list
|
||||
amd = kfd_gpus()
|
||||
# A PC whose only NVIDIA cards are Pascal / Volta (two GTX 1080s) and that has no AMD card Strata can use: setup runs them with the
|
||||
# CUDA 12 engine (old_gpus_opt_in), so the app must not call it "no supported graphics card" and start both cards Off (#3655).
|
||||
# A PC with a newer card keeps recommending that one; naming an old card is still the opt-in.
|
||||
@@ -1879,6 +1881,43 @@ def windows_video_controllers() -> list:
|
||||
return [{"name": x.get("Name"), "driver": x.get("DriverVersion")} for x in d if isinstance(x, dict)]
|
||||
|
||||
|
||||
KFD_SUPPORTED = ("gfx1100", "gfx1101", "gfx1102", "gfx1200", "gfx1201", "gfx1030", "gfx1031", "gfx1151")
|
||||
|
||||
|
||||
def kfd_gpus(sysfs: str = "/sys") -> list:
|
||||
"""AMD cards from the kernel's KFD topology and the amdgpu driver's files, with no ROCm tool and no setup module: a PC that has only the
|
||||
driver plus the engine's own runtime has no rocm-smi, amd-smi or rocminfo, and the cards were then not counted at all (a 4-card PC ran on one).
|
||||
Numbered as HIP numbers them (the GPU nodes in order, CPU nodes skipped)."""
|
||||
base = Path(sysfs) / "class/kfd/kfd/topology/nodes"
|
||||
out = []
|
||||
try:
|
||||
nodes = sorted((p for p in base.iterdir() if p.name.isdigit()), key=lambda p: int(p.name))
|
||||
except OSError:
|
||||
return out
|
||||
for node in nodes:
|
||||
try:
|
||||
props = dict(line.partition(" ")[::2] for line in (node / "properties").read_text().splitlines())
|
||||
ver, simd = int(props.get("gfx_target_version") or 0), int(props.get("simd_count") or 0)
|
||||
except (OSError, ValueError):
|
||||
continue
|
||||
if ver == 0 or simd == 0:
|
||||
continue
|
||||
arch = f"gfx{ver // 10000}{(ver // 100) % 100:x}{ver % 100:x}"
|
||||
dev = Path(sysfs) / f"class/drm/renderD{props.get('drm_render_minor', '').strip()}/device"
|
||||
try:
|
||||
vram = int((dev / "mem_info_vram_total").read_text()) / 2 ** 30
|
||||
except (OSError, ValueError):
|
||||
vram = 0.0
|
||||
try:
|
||||
name = (dev / "product_name").read_text().strip() or f"AMD Radeon ({arch})"
|
||||
except OSError:
|
||||
name = f"AMD Radeon ({arch})"
|
||||
ok = arch in KFD_SUPPORTED
|
||||
out.append({"index": len(out), "name": name, "vram_gb": round(vram, 1), "arch": arch, "driver": "amdgpu", "vendor": "amd",
|
||||
"usable": ok, "problem": None if ok else f"not supported - Strata's AMD backend does not list {arch}"})
|
||||
return out
|
||||
|
||||
|
||||
def rocm_smi_gpus() -> list:
|
||||
s = run_quiet(["rocm-smi", "--showproductname", "--showmeminfo", "vram", "--json"])
|
||||
try:
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
"""A PC with only the amdgpu driver (no rocm-smi, no setup module) still counts every AMD card, from a fake sysfs.
|
||||
|
||||
python -m unittest tools.test_kfd_gpus
|
||||
"""
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
sys.path.insert(0, str(ROOT / "tools"))
|
||||
import strata_mcp as M # noqa: E402
|
||||
|
||||
|
||||
def node(root: Path, i: int, ver: int, simd: int, minor: int, vram: int = 0, name: str | None = None):
|
||||
n = root / "class/kfd/kfd/topology/nodes" / str(i)
|
||||
n.mkdir(parents=True)
|
||||
(n / "properties").write_text(f"cpu_cores_count {0 if simd else 12}\nsimd_count {simd}\ngfx_target_version {ver}\ndrm_render_minor {minor}\n")
|
||||
if simd:
|
||||
d = root / f"class/drm/renderD{minor}/device"
|
||||
d.mkdir(parents=True)
|
||||
(d / "mem_info_vram_total").write_text(str(vram))
|
||||
if name:
|
||||
(d / "product_name").write_text(name + "\n")
|
||||
|
||||
|
||||
class KfdGpus(unittest.TestCase):
|
||||
def test_four_cards_and_the_cpu_node(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
node(root, 0, 0, 0, 0)
|
||||
for k in range(4):
|
||||
node(root, k + 1, 120001, 128, 128 + k, 32 << 30, "AMD Radeon AI PRO R9700")
|
||||
gpus = M.kfd_gpus(tmp)
|
||||
self.assertEqual([g["index"] for g in gpus], [0, 1, 2, 3])
|
||||
self.assertTrue(all(g["usable"] and g["arch"] == "gfx1201" and g["vram_gb"] == 32.0 for g in gpus))
|
||||
|
||||
def test_an_unlisted_architecture_is_named_not_hidden(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
node(Path(tmp), 0, 90010, 60, 128, 8 << 30)
|
||||
(g,) = M.kfd_gpus(tmp)
|
||||
self.assertFalse(g["usable"])
|
||||
self.assertIn("gfx90a", g["problem"])
|
||||
|
||||
def test_no_amd_driver_is_an_empty_list(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
self.assertEqual(M.kfd_gpus(tmp), [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user