Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cuda_core/cuda/core/_device.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
18 changes: 14 additions & 4 deletions cuda_core/cuda/core/_device.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
54 changes: 54 additions & 0 deletions cuda_core/tests/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
# SPDX-License-Identifier: Apache-2.0

import contextlib
import os
import subprocess
import sys
import textwrap
from concurrent.futures import ThreadPoolExecutor

import pytest
Expand Down Expand Up @@ -471,6 +473,58 @@ 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, tmp_path):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor · Functional Correctness · Quick win

important: Establish a CUDA context in the child process.

The subprocess calls CUDA APIs and constructs DeviceProperties, but it never creates, sets, and destroys a CUDA context. Add explicit context setup with cleanup before DeviceProperties._init(device).

As per path instructions: tests that call CUDA APIs must establish their own context.

Source: Path instructions

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
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

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
"""
)
env = {key: value for key, value in os.environ.items() if key != "PYTHONPATH"}
result = subprocess.run( # noqa: S603 - executes a repository-owned test script
[sys.executable, "-c", script, str(driver_version)],
cwd=tmp_path,
env=env,
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
# ============================================================================
Expand Down
Loading