From e52d93279a1e16ade5c4a4ea4451bd954a5f71ad Mon Sep 17 00:00:00 2001 From: Aryan Date: Mon, 14 Sep 2026 18:27:56 -0400 Subject: [PATCH 1/3] fix(cuda.core): allow NUMA pools on older drivers Signed-off-by: Aryan --- cuda_core/cuda/core/_memory/_pinned_memory_resource.pyx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/cuda_core/cuda/core/_memory/_pinned_memory_resource.pyx b/cuda_core/cuda/core/_memory/_pinned_memory_resource.pyx index 18621fb08bc..d38768cb9b1 100644 --- a/cuda_core/cuda/core/_memory/_pinned_memory_resource.pyx +++ b/cuda_core/cuda/core/_memory/_pinned_memory_resource.pyx @@ -121,13 +121,7 @@ cdef class PinnedMemoryResource(_MemPool): raise TypeError("Cannot allocate from a mapped IPC-enabled memory resource") cdef Stream s = Stream_accept(stream) device = s.device - cdef bint supported = ( - device.properties.host_numa_memory_pools_supported - if self._numa_id >= 0 - else device.properties.host_memory_pools_supported - ) - - if not supported: + if self._numa_id < 0 and not device.properties.host_memory_pools_supported: raise RuntimeError( f"CUDA device {device.device_id} does not support the requested " "host memory pool for PinnedMemoryResource. Use " From 5b7cd966c3b371bfec0dbf0aff7dda3719eb3d94 Mon Sep 17 00:00:00 2001 From: Aryan Date: Mon, 12 Oct 2026 19:00:23 -0400 Subject: [PATCH 2/3] fix(cuda.core): infer NUMA pool support before CUDA 12.9 Signed-off-by: Aryan --- cuda_core/cuda/core/_device.pyi | 5 ++- cuda_core/cuda/core/_device.pyx | 18 ++++++-- .../core/_memory/_pinned_memory_resource.pyx | 8 +++- cuda_core/tests/test_device.py | 43 +++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-) 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/cuda/core/_memory/_pinned_memory_resource.pyx b/cuda_core/cuda/core/_memory/_pinned_memory_resource.pyx index d38768cb9b1..18621fb08bc 100644 --- a/cuda_core/cuda/core/_memory/_pinned_memory_resource.pyx +++ b/cuda_core/cuda/core/_memory/_pinned_memory_resource.pyx @@ -121,7 +121,13 @@ cdef class PinnedMemoryResource(_MemPool): raise TypeError("Cannot allocate from a mapped IPC-enabled memory resource") cdef Stream s = Stream_accept(stream) device = s.device - if self._numa_id < 0 and not device.properties.host_memory_pools_supported: + cdef bint supported = ( + device.properties.host_numa_memory_pools_supported + if self._numa_id >= 0 + else device.properties.host_memory_pools_supported + ) + + if not supported: raise RuntimeError( f"CUDA device {device.device_id} does not support the requested " "host memory pool for PinnedMemoryResource. Use " diff --git a/cuda_core/tests/test_device.py b/cuda_core/tests/test_device.py index d12b86e0190..d99ffa20796 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,48 @@ 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 = 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 # ============================================================================ From 6efba0745100d660d80bb5c7423c0aa374a92797 Mon Sep 17 00:00:00 2001 From: Aryan Date: Mon, 12 Oct 2026 19:36:36 -0400 Subject: [PATCH 3/3] test(cuda.core): skip NUMA regression without devices Signed-off-by: Aryan --- cuda_core/tests/test_device.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cuda_core/tests/test_device.py b/cuda_core/tests/test_device.py index d99ffa20796..bf956a5baca 100644 --- a/cuda_core/tests/test_device.py +++ b/cuda_core/tests/test_device.py @@ -488,6 +488,13 @@ def test_host_numa_memory_pools_supported_on_pre_12_9_driver(driver_version): 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