From 8164b1bf12e528b7cbabe210fbadcc7675191113 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 6 May 2026 21:16:49 +0000 Subject: [PATCH 1/3] cuda.core: consolidate get_driver_version and get_driver_version_full MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge the two separate driver version query functions into a single get_driver_version() that returns (umd_version, kmd_version) — a pair of version tuples. UMD is a 2-tuple (major, minor) and KMD is a 3-tuple (major, minor, patch). The function now requires NVML. Co-Authored-By: Claude Opus 4.6 (1M context) --- cuda_core/cuda/core/system/__init__.py | 1 - cuda_core/cuda/core/system/_system.pyx | 59 +++++++------------ cuda_core/docs/source/api.rst | 1 - cuda_core/docs/source/release/1.0.0-notes.rst | 8 +++ cuda_core/tests/system/test_system_system.py | 46 +++++++-------- 5 files changed, 51 insertions(+), 64 deletions(-) diff --git a/cuda_core/cuda/core/system/__init__.py b/cuda_core/cuda/core/system/__init__.py index 436b04577b6..39f6dba27d4 100644 --- a/cuda_core/cuda/core/system/__init__.py +++ b/cuda_core/cuda/core/system/__init__.py @@ -12,7 +12,6 @@ __all__ = [ "CUDA_BINDINGS_NVML_IS_COMPATIBLE", "get_driver_version", - "get_driver_version_full", "get_num_devices", "get_process_name", ] diff --git a/cuda_core/cuda/core/system/_system.pyx b/cuda_core/cuda/core/system/_system.pyx index f3215506902..cff9a0e6ac2 100644 --- a/cuda_core/cuda/core/system/_system.pyx +++ b/cuda_core/cuda/core/system/_system.pyx @@ -29,52 +29,38 @@ else: from cuda.core._utils.cuda_utils import driver, handle_return, runtime -def get_driver_version(kernel_mode: bool = False) -> tuple[int, int]: +def get_driver_version() -> tuple[tuple[int, ...], tuple[int, ...]]: """ Get the driver version. - Parameters - ---------- - kernel_mode: bool - When `True`, return the kernel-mode driver version, e.g. 580.65.06. - Otherwise, return the user-mode driver version, e.g. 13.0.1. + Returns both the user-mode (UMD / CUDA) driver version and the + kernel-mode (KMD / GPU) driver version. Returns ------- - version: tuple[int, int] - Tuple in the format `(MAJOR, MINOR)`. + version : tuple[tuple[int, ...], tuple[int, ...]] + ``(umd_version, kmd_version)`` where ``umd_version`` is typically + a 2-tuple ``(MAJOR, MINOR)`` and ``kmd_version`` is typically + a 3-tuple ``(MAJOR, MINOR, PATCH)``. + + Raises + ------ + RuntimeError + If the NVML library is not available. """ - return get_driver_version_full(kernel_mode)[:2] + if not CUDA_BINDINGS_NVML_IS_COMPATIBLE: + raise RuntimeError("get_driver_version requires NVML support") + initialize() + # UMD (user-mode / CUDA toolkit) version + cdef int v + v = nvml.system_get_cuda_driver_version() + umd = (v // 1000, (v // 10) % 100) -def get_driver_version_full(kernel_mode: bool = False) -> tuple[int, int, int]: - """ - Get the full driver version. + # KMD (kernel-mode / GPU driver) version + kmd = tuple(int(x) for x in nvml.system_get_driver_version().split(".")) - Parameters - ---------- - kernel_mode: bool - When `True`, return the kernel-mode driver version, e.g. 580.65.06. - Otherwise, return the user-mode driver version, e.g. 13.0.1. - - Returns - ------- - version: tuple[int, int, int] - Tuple in the format `(MAJOR, MINOR, PATCH)`. - """ - cdef int v - if kernel_mode: - if not CUDA_BINDINGS_NVML_IS_COMPATIBLE: - raise ValueError("Kernel-mode driver version requires NVML support") - initialize() - return tuple(int(v) for v in nvml.system_get_driver_version().split(".")) - else: - if CUDA_BINDINGS_NVML_IS_COMPATIBLE: - initialize() - v = nvml.system_get_cuda_driver_version() - else: - v = handle_return(driver.cuDriverGetVersion()) - return (v // 1000, (v // 10) % 100, v % 10) + return (umd, kmd) def get_nvml_version() -> tuple[int, ...]: @@ -138,7 +124,6 @@ def get_process_name(pid: int) -> str: __all__ = [ "get_driver_branch", "get_driver_version", - "get_driver_version_full", "get_nvml_version", "get_num_devices", "get_process_name", diff --git a/cuda_core/docs/source/api.rst b/cuda_core/docs/source/api.rst index 41ff5f179ed..dfcc4e08fad 100644 --- a/cuda_core/docs/source/api.rst +++ b/cuda_core/docs/source/api.rst @@ -255,7 +255,6 @@ Basic functions :toctree: generated/ system.get_driver_version - system.get_driver_version_full system.get_driver_branch system.get_num_devices system.get_nvml_version diff --git a/cuda_core/docs/source/release/1.0.0-notes.rst b/cuda_core/docs/source/release/1.0.0-notes.rst index 58553fe59ea..4d57a3c4c45 100644 --- a/cuda_core/docs/source/release/1.0.0-notes.rst +++ b/cuda_core/docs/source/release/1.0.0-notes.rst @@ -152,6 +152,14 @@ Breaking changes :mod:`cuda.core.utils` module. (`#2028 `__) +- Consolidated ``system.get_driver_version()`` and + ``system.get_driver_version_full()`` into a single + :func:`system.get_driver_version` that returns + ``(umd_version, kmd_version)`` — a 2-tuple of version tuples + (UMD is ``(MAJOR, MINOR)``, KMD is ``(MAJOR, MINOR, PATCH)``). + The function now requires NVML support and raises :class:`RuntimeError` + if it is not available. + Fixes and enhancements ----------------------- diff --git a/cuda_core/tests/system/test_system_system.py b/cuda_core/tests/system/test_system_system.py index d21b8d7bf09..fc3bbade372 100644 --- a/cuda_core/tests/system/test_system_system.py +++ b/cuda_core/tests/system/test_system_system.py @@ -19,11 +19,24 @@ from .conftest import skip_if_nvml_unsupported +@skip_if_nvml_unsupported def test_driver_version(): - driver_version = system.get_driver_version() + umd, kmd = system.get_driver_version() + + # UMD: 2-tuple (major, minor), cross-check against cuDriverGetVersion + assert isinstance(umd, tuple) + assert len(umd) == 2 version = handle_return(driver.cuDriverGetVersion()) - expected_driver_version = (version // 1000, (version % 1000) // 10) - assert driver_version == expected_driver_version, "Driver version does not match expected value" + expected_umd = (version // 1000, (version % 1000) // 10) + assert umd == expected_umd, "UMD driver version does not match expected value" + + # KMD: 3-tuple (major, minor, patch) + assert isinstance(kmd, tuple) + assert len(kmd) == 3 + ver_maj, ver_min, ver_patch = kmd + assert 400 <= ver_maj < 1000 + assert ver_min >= 0 + assert 0 <= ver_patch <= 99 def test_num_devices(): @@ -41,28 +54,11 @@ def test_devices(): assert device.device_id == expected_device.device_id, "Device ID does not match expected value" -def test_cuda_driver_version(): - cuda_driver_version = system.get_driver_version_full() - assert isinstance(cuda_driver_version, tuple) - assert len(cuda_driver_version) == 3 - - ver_maj, ver_min, ver_patch = cuda_driver_version - assert ver_maj >= 10 - assert 0 <= ver_min <= 99 - assert 0 <= ver_patch <= 9 - - -@skip_if_nvml_unsupported -def test_gpu_driver_version(): - driver_version = system.get_driver_version(kernel_mode=True) - assert isinstance(driver_version, tuple) - assert len(driver_version) in (2, 3) - - (ver_maj, ver_min, *ver_patch) = driver_version - assert 400 <= ver_maj < 1000 - assert ver_min >= 0 - if ver_patch: - assert 0 <= ver_patch[0] <= 99 +def test_driver_version_requires_nvml(): + if system.CUDA_BINDINGS_NVML_IS_COMPATIBLE: + pytest.skip("NVML is available, cannot test the error path") + with pytest.raises(RuntimeError, match="requires NVML support"): + system.get_driver_version() @skip_if_nvml_unsupported From bfd9ab9fd9fbeb7d7f52ea1cb8a899f266b0b5e7 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 6 May 2026 21:21:48 +0000 Subject: [PATCH 2/3] Remove unused driver import from _system.pyx Co-Authored-By: Claude Opus 4.6 (1M context) --- cuda_core/cuda/core/system/_system.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cuda_core/cuda/core/system/_system.pyx b/cuda_core/cuda/core/system/_system.pyx index cff9a0e6ac2..0f683196f13 100644 --- a/cuda_core/cuda/core/system/_system.pyx +++ b/cuda_core/cuda/core/system/_system.pyx @@ -26,7 +26,7 @@ if CUDA_BINDINGS_NVML_IS_COMPATIBLE: from cuda.core.system._nvml_context import initialize else: - from cuda.core._utils.cuda_utils import driver, handle_return, runtime + from cuda.core._utils.cuda_utils import handle_return, runtime def get_driver_version() -> tuple[tuple[int, ...], tuple[int, ...]]: From d2d387ea1431a06c20d2988e891dbad127d5b521 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 6 May 2026 22:06:06 +0000 Subject: [PATCH 3/3] Fix KMD version test to allow 2-tuple on WSL Windows driver version strings only have two components, so nvmlSystemGetDriverVersion returns X.Y on WSL instead of X.Y.Z. Co-Authored-By: Claude Opus 4.6 (1M context) --- cuda_core/cuda/core/system/_system.pyx | 2 +- cuda_core/tests/system/test_system_system.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cuda_core/cuda/core/system/_system.pyx b/cuda_core/cuda/core/system/_system.pyx index 0f683196f13..5a2d6353989 100644 --- a/cuda_core/cuda/core/system/_system.pyx +++ b/cuda_core/cuda/core/system/_system.pyx @@ -41,7 +41,7 @@ def get_driver_version() -> tuple[tuple[int, ...], tuple[int, ...]]: version : tuple[tuple[int, ...], tuple[int, ...]] ``(umd_version, kmd_version)`` where ``umd_version`` is typically a 2-tuple ``(MAJOR, MINOR)`` and ``kmd_version`` is typically - a 3-tuple ``(MAJOR, MINOR, PATCH)``. + a 3-tuple ``(MAJOR, MINOR, PATCH)`` (2-tuple on WSL). Raises ------ diff --git a/cuda_core/tests/system/test_system_system.py b/cuda_core/tests/system/test_system_system.py index fc3bbade372..eef110090b6 100644 --- a/cuda_core/tests/system/test_system_system.py +++ b/cuda_core/tests/system/test_system_system.py @@ -30,13 +30,14 @@ def test_driver_version(): expected_umd = (version // 1000, (version % 1000) // 10) assert umd == expected_umd, "UMD driver version does not match expected value" - # KMD: 3-tuple (major, minor, patch) + # KMD: 3-tuple (major, minor, patch), or 2-tuple on WSL assert isinstance(kmd, tuple) - assert len(kmd) == 3 - ver_maj, ver_min, ver_patch = kmd + assert len(kmd) in (2, 3) + ver_maj, ver_min, *ver_patch = kmd assert 400 <= ver_maj < 1000 assert ver_min >= 0 - assert 0 <= ver_patch <= 99 + if ver_patch: + assert 0 <= ver_patch[0] <= 99 def test_num_devices():