| |
| |
|
|
| from __future__ import annotations |
|
|
| import ctypes |
| import functools |
| from collections.abc import Callable |
| from dataclasses import dataclass |
|
|
| from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import ( |
| load_nvidia_dynamic_lib as _load_nvidia_dynamic_lib, |
| ) |
| from cuda.pathfinder._utils.platform_aware import IS_WINDOWS |
|
|
|
|
| class QueryDriverCudaVersionError(RuntimeError): |
| """Raised when ``query_driver_cuda_version()`` cannot determine the CUDA driver version.""" |
|
|
|
|
| @dataclass(frozen=True, slots=True) |
| class DriverCudaVersion: |
| """ |
| CUDA-facing driver version reported by ``cuDriverGetVersion()``. |
| |
| The name ``DriverCudaVersion`` is intentionally specific: this dataclass |
| models the version shown as ``CUDA Version`` in ``nvidia-smi``, not the |
| graphics driver release shown as ``Driver Version``. More specifically, |
| it reflects the CUDA user-mode driver (UMD) interface version reported by |
| ``cuDriverGetVersion()``, not the kernel-mode driver (KMD) package |
| version. |
| |
| Example ``nvidia-smi`` output:: |
| |
| +---------------------------------------------------------------------+ |
| | NVIDIA-SMI 595.58.03 Driver Version: 595.58.03 CUDA Version: 13.2 | |
| +---------------------------------------------------------------------+ |
| |
| For the example above, ``DriverCudaVersion(encoded=13020, major=13, |
| minor=2)`` corresponds to ``CUDA Version: 13.2``. It does not correspond |
| to ``Driver Version: 595.58.03``. |
| """ |
|
|
| encoded: int |
| major: int |
| minor: int |
|
|
|
|
| @functools.cache |
| def query_driver_cuda_version() -> DriverCudaVersion: |
| """Return the CUDA driver version parsed into its major/minor components.""" |
| try: |
| encoded = _query_driver_cuda_version_int() |
| return DriverCudaVersion( |
| encoded=encoded, |
| major=encoded // 1000, |
| minor=(encoded % 1000) // 10, |
| ) |
| except Exception as exc: |
| raise QueryDriverCudaVersionError("Failed to query the CUDA driver version.") from exc |
|
|
|
|
| def _query_driver_cuda_version_int() -> int: |
| """Return the encoded CUDA driver version from ``cuDriverGetVersion()``.""" |
| loaded_cuda = _load_nvidia_dynamic_lib("cuda") |
| if IS_WINDOWS: |
| |
| |
| loader_cls: Callable[[str], ctypes.CDLL] = ctypes.WinDLL |
| else: |
| loader_cls = ctypes.CDLL |
| driver_lib = loader_cls(loaded_cuda.abs_path) |
| cu_driver_get_version = driver_lib.cuDriverGetVersion |
| cu_driver_get_version.argtypes = [ctypes.POINTER(ctypes.c_int)] |
| cu_driver_get_version.restype = ctypes.c_int |
| version = ctypes.c_int() |
| status = cu_driver_get_version(ctypes.byref(version)) |
| if status != 0: |
| raise RuntimeError(f"Failed to query CUDA driver version via cuDriverGetVersion() (status={status}).") |
| return version.value |
|
|