diff --git a/cuda_core/cuda/core/_device.pyi b/cuda_core/cuda/core/_device.pyi index 8c2b273a6cd..da5e2b692ab 100644 --- a/cuda_core/cuda/core/_device.pyi +++ b/cuda_core/cuda/core/_device.pyi @@ -447,7 +447,10 @@ class DeviceProperties: """bool: Device supports HOST_NUMA location with the virtual memory management APIs like cuMemCreate, cuMemMap and related APIs.""" @property def host_numa_memory_pools_supported(self) -> bool: - """bool: Device supports HOST_NUMA location with the cuMemAllocAsync and cuMemPool family of APIs.""" + """bool: Device supports HOST_NUMA location with the cuMemAllocAsync and cuMemPool family of APIs. + + The value is inferred for drivers before CUDA 12.9. + """ @property def host_numa_multinode_ipc_supported(self) -> bool: """bool: Device supports HOST_NUMA location IPC between nodes in a multi-node system.""" diff --git a/cuda_core/cuda/core/_device.pyx b/cuda_core/cuda/core/_device.pyx index 8611cd3d819..2fe8ca78388 100644 --- a/cuda_core/cuda/core/_device.pyx +++ b/cuda_core/cuda/core/_device.pyx @@ -28,6 +28,7 @@ from cuda.core._rt cimport ( get_last_error, as_cu, ) +from cuda.core._utils.version cimport cy_driver_version from cuda.core._stream import IsStreamType, Stream, StreamOptions from cuda.core._utils.clear_error_support import assert_type @@ -910,10 +911,19 @@ cdef class DeviceProperties: @property def host_numa_memory_pools_supported(self) -> bool: - """bool: Device supports HOST_NUMA location with the cuMemAllocAsync and cuMemPool family of APIs.""" - return bool( - self._get_cached_attribute(driver.CUdevice_attribute.CU_DEVICE_ATTRIBUTE_HOST_NUMA_MEMORY_POOLS_SUPPORTED) - ) + """bool: Device supports HOST_NUMA location with the cuMemAllocAsync and cuMemPool family of APIs. + + The value is inferred for drivers before CUDA 12.9. + """ + cdef tuple drv_ver = cy_driver_version() + if drv_ver >= (12, 9, 0): + return bool( + self._get_cached_attribute( + driver.CUdevice_attribute.CU_DEVICE_ATTRIBUTE_HOST_NUMA_MEMORY_POOLS_SUPPORTED + ) + ) + # The attribute arrived in CUDA 12.9, HOST_NUMA pools in CUDA 12.6 (#2795). + return drv_ver >= (12, 6, 0) and self.memory_pools_supported and not self.integrated # Start of CUDA 13 device attributes diff --git a/cuda_core/tests/test_device.py b/cuda_core/tests/test_device.py index d12b86e0190..bf956a5baca 100644 --- a/cuda_core/tests/test_device.py +++ b/cuda_core/tests/test_device.py @@ -4,6 +4,7 @@ import contextlib import subprocess import sys +import textwrap from concurrent.futures import ThreadPoolExecutor import pytest @@ -471,6 +472,55 @@ def test_device_properties_complete(): assert tab_props == live_props # Ensure exact match. +@pytest.mark.agent_authored(model="gpt-6") +@pytest.mark.parametrize("driver_version", [12050, 12060, 12080]) +def test_host_numa_memory_pools_supported_on_pre_12_9_driver(driver_version): + script = textwrap.dedent( + """ + import sys + + from cuda.bindings import driver + + simulated_driver_version = int(sys.argv[1]) + driver.cuDriverGetVersion = lambda: (driver.CUresult.CUDA_SUCCESS, simulated_driver_version) + (status,) = driver.cuInit(0) + if int(status) == int(driver.CUresult.CUDA_ERROR_NO_DEVICE): + print("No CUDA device is available") + raise SystemExit(77) + assert int(status) == int(driver.CUresult.CUDA_SUCCESS), status + status, device_count = driver.cuDeviceGetCount() + if int(status) == int(driver.CUresult.CUDA_ERROR_NO_DEVICE) or ( + int(status) == int(driver.CUresult.CUDA_SUCCESS) and device_count == 0 + ): + print("No CUDA device is available") + raise SystemExit(77) + assert int(status) == int(driver.CUresult.CUDA_SUCCESS), status + status, device = driver.cuDeviceGet(0) + assert int(status) == int(driver.CUresult.CUDA_SUCCESS), status + + from cuda.core._device import DeviceProperties + + properties = DeviceProperties._init(device) + expected = ( + False + if simulated_driver_version < 12060 + else properties.memory_pools_supported and not properties.integrated + ) + assert properties.host_numa_memory_pools_supported is expected + """ + ) + result = subprocess.run( # noqa: S603 - executes a repository-owned test script + [sys.executable, "-c", script, str(driver_version)], + capture_output=True, + check=False, + text=True, + timeout=60, + ) + if result.returncode == 77: + pytest.skip(result.stdout + result.stderr) + assert result.returncode == 0, result.stdout + result.stderr + + # ============================================================================ # Device Equality Tests # ============================================================================