From 8164b1bf12e528b7cbabe210fbadcc7675191113 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 6 May 2026 21:16:49 +0000 Subject: [PATCH 1/7] 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/7] 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/7] 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(): From ebd2229e5574253620ce070de44112441a194431 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 7 May 2026 13:45:49 +0000 Subject: [PATCH 4/7] Split into get_user_mode_driver_version and get_kernel_mode_driver_version Per review feedback, split the consolidated get_driver_version() into two separate functions so each returns a simple tuple[int, ...]: - get_user_mode_driver_version(): works with or without NVML (falls back to cuDriverGetVersion), returns (major, minor) - get_kernel_mode_driver_version(): requires NVML, returns (major, minor, patch) or (major, minor) on WSL Co-Authored-By: Claude Opus 4.6 (1M context) --- cuda_core/cuda/core/system/__init__.py | 3 +- cuda_core/cuda/core/system/_system.pyx | 54 +++++++++++-------- cuda_core/docs/source/api.rst | 3 +- cuda_core/docs/source/release/1.0.0-notes.rst | 12 ++--- cuda_core/tests/system/test_system_system.py | 20 +++---- 5 files changed, 52 insertions(+), 40 deletions(-) diff --git a/cuda_core/cuda/core/system/__init__.py b/cuda_core/cuda/core/system/__init__.py index 39f6dba27d4..d90242d9d50 100644 --- a/cuda_core/cuda/core/system/__init__.py +++ b/cuda_core/cuda/core/system/__init__.py @@ -11,7 +11,8 @@ __all__ = [ "CUDA_BINDINGS_NVML_IS_COMPATIBLE", - "get_driver_version", + "get_kernel_mode_driver_version", + "get_user_mode_driver_version", "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 5a2d6353989..1cefeb38267 100644 --- a/cuda_core/cuda/core/system/_system.pyx +++ b/cuda_core/cuda/core/system/_system.pyx @@ -26,22 +26,40 @@ if CUDA_BINDINGS_NVML_IS_COMPATIBLE: from cuda.core.system._nvml_context import initialize else: - from cuda.core._utils.cuda_utils import handle_return, runtime + from cuda.core._utils.cuda_utils import driver, handle_return, runtime -def get_driver_version() -> tuple[tuple[int, ...], tuple[int, ...]]: +def get_user_mode_driver_version() -> tuple[int, ...]: """ - Get the driver version. + Get the user-mode (UMD / CUDA) driver version. - Returns both the user-mode (UMD / CUDA) driver version and the - kernel-mode (KMD / GPU) driver version. + This is the most commonly needed version when checking CUDA driver + compatibility. It works with all ``cuda-bindings`` versions: when + NVML is available it uses NVML, otherwise it falls back to the + CUDA driver API. Returns ------- - 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)`` (2-tuple on WSL). + version : tuple[int, ...] + A 2-tuple ``(MAJOR, MINOR)``. + """ + cdef int v + 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) + + +def get_kernel_mode_driver_version() -> tuple[int, ...]: + """ + Get the kernel-mode (KMD / GPU) driver version. + + Returns + ------- + version : tuple[int, ...] + Typically a 3-tuple ``(MAJOR, MINOR, PATCH)`` (2-tuple on WSL). Raises ------ @@ -49,18 +67,11 @@ def get_driver_version() -> tuple[tuple[int, ...], tuple[int, ...]]: If the NVML library is not available. """ if not CUDA_BINDINGS_NVML_IS_COMPATIBLE: - raise RuntimeError("get_driver_version requires NVML support") + raise RuntimeError( + "get_kernel_mode_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) - - # KMD (kernel-mode / GPU driver) version - kmd = tuple(int(x) for x in nvml.system_get_driver_version().split(".")) - - return (umd, kmd) + return tuple(int(x) for x in nvml.system_get_driver_version().split(".")) def get_nvml_version() -> tuple[int, ...]: @@ -123,7 +134,8 @@ def get_process_name(pid: int) -> str: __all__ = [ "get_driver_branch", - "get_driver_version", + "get_kernel_mode_driver_version", + "get_user_mode_driver_version", "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 dfcc4e08fad..ffb000b3847 100644 --- a/cuda_core/docs/source/api.rst +++ b/cuda_core/docs/source/api.rst @@ -254,7 +254,8 @@ Basic functions .. autosummary:: :toctree: generated/ - system.get_driver_version + system.get_user_mode_driver_version + system.get_kernel_mode_driver_version 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 4d57a3c4c45..73caea151ef 100644 --- a/cuda_core/docs/source/release/1.0.0-notes.rst +++ b/cuda_core/docs/source/release/1.0.0-notes.rst @@ -152,13 +152,11 @@ 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. +- Replaced ``system.get_driver_version()`` and + ``system.get_driver_version_full()`` with + :func:`system.get_user_mode_driver_version` (works with or without + NVML) and :func:`system.get_kernel_mode_driver_version` (requires + NVML). Each returns a ``tuple[int, ...]``. Fixes and enhancements ----------------------- diff --git a/cuda_core/tests/system/test_system_system.py b/cuda_core/tests/system/test_system_system.py index eef110090b6..7480a0fd85e 100644 --- a/cuda_core/tests/system/test_system_system.py +++ b/cuda_core/tests/system/test_system_system.py @@ -19,18 +19,18 @@ from .conftest import skip_if_nvml_unsupported -@skip_if_nvml_unsupported -def test_driver_version(): - umd, kmd = system.get_driver_version() - - # UMD: 2-tuple (major, minor), cross-check against cuDriverGetVersion +def test_user_mode_driver_version(): + umd = system.get_user_mode_driver_version() assert isinstance(umd, tuple) assert len(umd) == 2 version = handle_return(driver.cuDriverGetVersion()) - expected_umd = (version // 1000, (version % 1000) // 10) - assert umd == expected_umd, "UMD driver version does not match expected value" + expected = (version // 1000, (version % 1000) // 10) + assert umd == expected, "UMD driver version does not match expected value" - # KMD: 3-tuple (major, minor, patch), or 2-tuple on WSL + +@skip_if_nvml_unsupported +def test_kernel_mode_driver_version(): + kmd = system.get_kernel_mode_driver_version() assert isinstance(kmd, tuple) assert len(kmd) in (2, 3) ver_maj, ver_min, *ver_patch = kmd @@ -55,11 +55,11 @@ def test_devices(): assert device.device_id == expected_device.device_id, "Device ID does not match expected value" -def test_driver_version_requires_nvml(): +def test_kernel_mode_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() + system.get_kernel_mode_driver_version() @skip_if_nvml_unsupported From 4c7cd2c5b0ae4cb6b001b8913fb5de02e3e3db05 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 7 May 2026 13:51:27 +0000 Subject: [PATCH 5/7] Add example version strings to driver version docstrings Co-Authored-By: Claude Opus 4.6 (1M context) --- cuda_core/cuda/core/system/_system.pyx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cuda_core/cuda/core/system/_system.pyx b/cuda_core/cuda/core/system/_system.pyx index 1cefeb38267..5079542b914 100644 --- a/cuda_core/cuda/core/system/_system.pyx +++ b/cuda_core/cuda/core/system/_system.pyx @@ -41,7 +41,7 @@ def get_user_mode_driver_version() -> tuple[int, ...]: Returns ------- version : tuple[int, ...] - A 2-tuple ``(MAJOR, MINOR)``. + A 2-tuple ``(MAJOR, MINOR)``, e.g. ``(13, 0)`` for CUDA 13.0. """ cdef int v if CUDA_BINDINGS_NVML_IS_COMPATIBLE: @@ -54,12 +54,13 @@ def get_user_mode_driver_version() -> tuple[int, ...]: def get_kernel_mode_driver_version() -> tuple[int, ...]: """ - Get the kernel-mode (KMD / GPU) driver version. + Get the kernel-mode (KMD / GPU) driver version, e.g. 580.65.06. Returns ------- version : tuple[int, ...] - Typically a 3-tuple ``(MAJOR, MINOR, PATCH)`` (2-tuple on WSL). + Typically a 3-tuple ``(MAJOR, MINOR, PATCH)`` + (2-tuple on WSL), e.g. ``(580, 65, 6)``. Raises ------ From 27ad775c0a3756a283a391f1611b06b042ebb0c6 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 7 May 2026 13:55:37 +0000 Subject: [PATCH 6/7] Remove NVML implementation detail from UMD docstring Co-Authored-By: Claude Opus 4.6 (1M context) --- cuda_core/cuda/core/system/_system.pyx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cuda_core/cuda/core/system/_system.pyx b/cuda_core/cuda/core/system/_system.pyx index 5079542b914..b3c85f8af18 100644 --- a/cuda_core/cuda/core/system/_system.pyx +++ b/cuda_core/cuda/core/system/_system.pyx @@ -34,9 +34,7 @@ def get_user_mode_driver_version() -> tuple[int, ...]: Get the user-mode (UMD / CUDA) driver version. This is the most commonly needed version when checking CUDA driver - compatibility. It works with all ``cuda-bindings`` versions: when - NVML is available it uses NVML, otherwise it falls back to the - CUDA driver API. + compatibility. It works with all ``cuda-bindings`` versions. Returns ------- From 2fe17c8b9e84821a7a7da1649772cd4b52c36c2c Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 7 May 2026 13:58:34 +0000 Subject: [PATCH 7/7] Sort __all__ alphabetically in system/__init__.py Co-Authored-By: Claude Opus 4.6 (1M context) --- cuda_core/cuda/core/system/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cuda_core/cuda/core/system/__init__.py b/cuda_core/cuda/core/system/__init__.py index d90242d9d50..c662ee97754 100644 --- a/cuda_core/cuda/core/system/__init__.py +++ b/cuda_core/cuda/core/system/__init__.py @@ -12,9 +12,9 @@ __all__ = [ "CUDA_BINDINGS_NVML_IS_COMPATIBLE", "get_kernel_mode_driver_version", - "get_user_mode_driver_version", "get_num_devices", "get_process_name", + "get_user_mode_driver_version", ]