Skip to content
Merged
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
1 change: 1 addition & 0 deletions cuda_core/pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

[pytest]
addopts = --showlocals --durations=20
pythonpath = tests
norecursedirs = cython
markers =
# Keep this authorship marker registry in sync across all pytest config roots.
Expand Down
25 changes: 25 additions & 0 deletions cuda_core/tests/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,28 @@ by `cuCtxSynchronize()` before popping the context. Tests should not rely on
that as a substitute for cleaning up explicitly: prefer context managers for
resources whose lifetime fits a single scope, and keep pool lifetimes inside
the test that creates them.

## Shared test support

See also: https://docs.pytest.org/en/stable/reference/fixtures.html#conftest-py-sharing-fixtures-across-multiple-files

Follow these rules when adding or moving shared test code:

- Never import from a `conftest.py`.
- Put suite-wide fixtures and pytest hooks in `tests/conftest.py`. Put fixtures
needed only by one test subtree in that subtree's nearest `conftest.py`.
- Put a pytest hook in a nested `conftest.py` only if pytest supports that hook
there. If the hook receives suite-wide data, explicitly limit its effects to
the intended subtree.
- Code used only to implement fixtures or hooks may remain in the same
`conftest.py`. Put functions and constants imported by test modules in
`tests/helpers/` instead.
- Import helpers explicitly from the test root, for example:
`from helpers.memory import create_managed_memory_resource_or_skip`.
- Fixtures in a nested `conftest.py` are available to tests in its directory
and descendants; fixtures from applicable parent `conftest.py` files remain
available.
- Do not add `__init__.py` solely because a test directory contains a
`conftest.py`.
- In directories without `__init__.py`, keep test-module basenames unique
within this test suite.
84 changes: 2 additions & 82 deletions cuda_core/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@

pytest_plugins = ["cuda_python_test_helpers._pytest_plugin"]

from cuda_python_test_helpers.marks import skipif_need_cuda_headers # noqa: F401 (re-exported for tests)
from cuda_python_test_helpers.mempool import xfail_if_mempool_oom
from helpers.constants import POOL_SIZE
from helpers.memory import skip_if_pinned_memory_unsupported

import cuda.core
from cuda.bindings import driver
Expand All @@ -45,7 +44,7 @@
PinnedMemoryResourceOptions,
_device,
)
from cuda.core._utils.cuda_utils import CUDAError, handle_return
from cuda.core._utils.cuda_utils import handle_return


def pytest_configure(config):
Expand Down Expand Up @@ -141,85 +140,6 @@ def pytest_collection_modifyitems(self, config, items):
item.obj = _wrap_worker_cuda_test(item.obj)


def skip_if_pinned_memory_unsupported(device):
try:
if not device.properties.host_memory_pools_supported:
pytest.skip("Device does not support host mempool operations")
except AttributeError:
pytest.skip("PinnedMemoryResource requires CUDA 13.0 or later")


def skip_if_managed_memory_unsupported(device):
try:
if not device.properties.memory_pools_supported or not device.properties.concurrent_managed_access:
pytest.skip("Device does not support managed memory pool operations")
except AttributeError:
pytest.skip("ManagedMemoryResource requires CUDA 13.0 or later")
try:
ManagedMemoryResource()
except CUDAError as e:
xfail_if_mempool_oom(e, device)
raise
except RuntimeError as e:
if "requires CUDA 13.0" in str(e):
pytest.skip("ManagedMemoryResource requires CUDA 13.0 or later")
raise


def create_managed_memory_resource_or_skip(*args, xfail_device=None, **kwargs):
# Keep the established "skip" helper name for call-site readability, even though
# Windows MCDM mempool OOM setup failures are xfailed instead of skipped.
try:
return ManagedMemoryResource(*args, **kwargs)
except CUDAError as e:
xfail_if_mempool_oom(e, _device_id_from_resource_options(xfail_device, args, kwargs))
if "CUDA_ERROR_NOT_SUPPORTED" in str(e):
pytest.skip("ManagedMemoryResource is not supported on this platform/device")
raise
except RuntimeError as e:
if "requires CUDA 13.0" in str(e):
pytest.skip("ManagedMemoryResource requires CUDA 13.0 or later")
if "concurrent managed access is not available" in str(e).lower():
pytest.skip("Device does not support concurrent managed memory access")
raise


def create_pinned_memory_resource_or_xfail(*args, xfail_device=None, **kwargs):
try:
return PinnedMemoryResource(*args, **kwargs)
except CUDAError as e:
xfail_if_mempool_oom(e, xfail_device)
raise


@contextmanager
def xfail_on_graph_mempool_oom(device=0):
try:
yield
except CUDAError as e:
xfail_if_mempool_oom(e, "cuGraphAddMemAllocNode", device)
raise


def _device_id_from_resource_options(device, args, kwargs):
if device is not None:
return device
options = kwargs.get("options")
if options is None and args:
options = args[0]
if options is None:
return 0
if isinstance(options, dict):
preferred_location = options.get("preferred_location")
preferred_location_type = options.get("preferred_location_type")
else:
preferred_location = getattr(options, "preferred_location", None)
preferred_location_type = getattr(options, "preferred_location_type", None)
if preferred_location_type in (None, "device") and isinstance(preferred_location, int) and preferred_location >= 0:
return preferred_location
return 0


def _require_ipc_mempool_devices(devices):
"""Return devices if they all support IPC-enabled mempools, otherwise skip."""
from helpers import supports_ipc_mempool
Expand Down
Empty file.
3 changes: 1 addition & 2 deletions cuda_core/tests/graph/test_graph_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
import helpers
import numpy as np
import pytest
from conftest import skipif_need_cuda_headers
from cuda_python_test_helpers.marks import requires_module
from cuda_python_test_helpers.marks import requires_module, skipif_need_cuda_headers
from helpers.graph_kernels import compile_common_kernels, compile_conditional_kernels
from helpers.misc import try_create_condition
from packaging.version import Version
Expand Down
2 changes: 1 addition & 1 deletion cuda_core/tests/graph/test_graph_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
from dataclasses import dataclass, field

import pytest
from conftest import xfail_on_graph_mempool_oom
from helpers.graph_kernels import compile_common_kernels
from helpers.memory import xfail_on_graph_mempool_oom
from helpers.misc import try_create_condition

from cuda.core import Device, LaunchConfig
Expand Down
2 changes: 1 addition & 1 deletion cuda_core/tests/graph/test_graph_definition_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import ctypes

import pytest
from conftest import xfail_on_graph_mempool_oom
from helpers.graph_kernels import compile_common_kernels
from helpers.memory import xfail_on_graph_mempool_oom
from helpers.misc import try_create_condition

from cuda.core import Device, LaunchConfig
Expand Down
2 changes: 1 addition & 1 deletion cuda_core/tests/graph/test_graph_definition_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import numpy as np
import pytest
from conftest import xfail_on_graph_mempool_oom
from helpers.memory import xfail_on_graph_mempool_oom

from cuda.core import Device, EventOptions, LaunchConfig, Program, ProgramOptions
from cuda.core._utils.cuda_utils import driver, handle_return
Expand Down
2 changes: 1 addition & 1 deletion cuda_core/tests/graph/test_graph_definition_lifetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
import weakref

import pytest
from conftest import xfail_on_graph_mempool_oom
from helpers.graph_kernels import compile_common_kernels
from helpers.memory import xfail_on_graph_mempool_oom
from helpers.misc import try_create_condition

from cuda_python_test_helpers import under_compute_sanitizer
Expand Down
2 changes: 1 addition & 1 deletion cuda_core/tests/graph/test_graph_memory_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"""Tests for GraphMemoryResource allocation and attributes during graph capture."""

import pytest
from conftest import xfail_on_graph_mempool_oom
from helpers.buffers import compare_buffer_to_constant, make_scratch_buffer, set_buffer
from helpers.memory import xfail_on_graph_mempool_oom

from cuda.core import (
Device,
Expand Down
91 changes: 91 additions & 0 deletions cuda_core/tests/helpers/memory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Memory-related test helpers (skip/xfail guards and resource factories)."""

from contextlib import contextmanager

import pytest
from cuda_python_test_helpers.mempool import xfail_if_mempool_oom

from cuda.core import ManagedMemoryResource, PinnedMemoryResource
from cuda.core._utils.cuda_utils import CUDAError


def skip_if_pinned_memory_unsupported(device):
try:
if not device.properties.host_memory_pools_supported:
pytest.skip("Device does not support host mempool operations")
except AttributeError:
pytest.skip("PinnedMemoryResource requires CUDA 13.0 or later")


def skip_if_managed_memory_unsupported(device):
try:
if not device.properties.memory_pools_supported or not device.properties.concurrent_managed_access:
pytest.skip("Device does not support managed memory pool operations")
except AttributeError:
pytest.skip("ManagedMemoryResource requires CUDA 13.0 or later")
try:
ManagedMemoryResource()
except CUDAError as e:
xfail_if_mempool_oom(e, device)
raise
except RuntimeError as e:
if "requires CUDA 13.0" in str(e):
pytest.skip("ManagedMemoryResource requires CUDA 13.0 or later")
raise


def _device_id_from_resource_options(device, args, kwargs):
if device is not None:
return device
options = kwargs.get("options")
if options is None and args:
options = args[0]
if options is None:
return 0
if isinstance(options, dict):
preferred_location = options.get("preferred_location")
preferred_location_type = options.get("preferred_location_type")
else:
preferred_location = getattr(options, "preferred_location", None)
preferred_location_type = getattr(options, "preferred_location_type", None)
if preferred_location_type in (None, "device") and isinstance(preferred_location, int) and preferred_location >= 0:
return preferred_location
return 0


def create_managed_memory_resource_or_skip(*args, xfail_device=None, **kwargs):
# Keep the established "skip" helper name for call-site readability, even though
# Windows MCDM mempool OOM setup failures are xfailed instead of skipped.
try:
return ManagedMemoryResource(*args, **kwargs)
except CUDAError as e:
xfail_if_mempool_oom(e, _device_id_from_resource_options(xfail_device, args, kwargs))
if "CUDA_ERROR_NOT_SUPPORTED" in str(e):
pytest.skip("ManagedMemoryResource is not supported on this platform/device")
raise
except RuntimeError as e:
if "requires CUDA 13.0" in str(e):
pytest.skip("ManagedMemoryResource requires CUDA 13.0 or later")
if "concurrent managed access is not available" in str(e).lower():
pytest.skip("Device does not support concurrent managed memory access")
raise


def create_pinned_memory_resource_or_xfail(*args, xfail_device=None, **kwargs):
try:
return PinnedMemoryResource(*args, **kwargs)
except CUDAError as e:
xfail_if_mempool_oom(e, xfail_device)
raise


@contextmanager
def xfail_on_graph_mempool_oom(device=0):
try:
yield
except CUDAError as e:
xfail_if_mempool_oom(e, "cuGraphAddMemAllocNode", device)
raise
3 changes: 0 additions & 3 deletions cuda_core/tests/memory/__init__.py

This file was deleted.

10 changes: 5 additions & 5 deletions cuda_core/tests/memory/test_copy_batch_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
"""

import pytest

# Shared with test_managed_ops.py: handles the CUDA 13 requirement, mempool
# OOM, and CUDA_ERROR_NOT_SUPPORTED (managed pools are unavailable on
# Windows), so the location-hint tests skip rather than error there.
from conftest import create_managed_memory_resource_or_skip
from helpers.buffers import compare_buffer_to_constant, set_buffer
from helpers.copy_batch import (
COPY_BATCH_SIZE,
assert_managed_holds,
)

# Shared with test_managed_ops.py: handles the CUDA 13 requirement, mempool
# OOM, and CUDA_ERROR_NOT_SUPPORTED (managed pools are unavailable on
# Windows), so the location-hint tests skip rather than error there.
from helpers.memory import create_managed_memory_resource_or_skip

from cuda.core import Host, LegacyPinnedMemoryResource
from cuda.core._memory._copy_enums import _attr_run_starts, _reject_unsupported_during_api_call
from cuda.core._memory._copy_ops import (
Expand Down
2 changes: 1 addition & 1 deletion cuda_core/tests/memory/test_copy_single_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"""CopyOptions support for Buffer.copy_to / Buffer.copy_from (issue #2365)."""

import pytest
from conftest import create_managed_memory_resource_or_skip
from helpers.buffers import compare_equal_buffers, make_scratch_buffer, set_buffer
from helpers.copy_batch import assert_managed_holds
from helpers.memory import create_managed_memory_resource_or_skip

from cuda.core import Device, Host, LegacyPinnedMemoryResource
from cuda.core._stream import LEGACY_DEFAULT_STREAM, PER_THREAD_DEFAULT_STREAM
Expand Down
9 changes: 5 additions & 4 deletions cuda_core/tests/memory/test_managed_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import mmap

import pytest
from conftest import create_managed_memory_resource_or_skip
from helpers.buffers import DummyDeviceMemoryResource, DummyUnifiedMemoryResource
from helpers.memory import create_managed_memory_resource_or_skip

from cuda.bindings import driver
from cuda.core import Device, Host, ManagedBuffer
Expand Down Expand Up @@ -37,9 +37,10 @@ def _page_base(buf):


def _skip_if_raw_managed_alloc_unsupported(device):
# Raw `cuMemAllocManaged` capability — distinct from conftest's
# `skip_if_managed_memory_unsupported`, which gates `ManagedMemoryResource`
# pool creation. Used by tests that exercise `DummyUnifiedMemoryResource`.
# Raw `cuMemAllocManaged` capability — distinct from
# `helpers.memory.skip_if_managed_memory_unsupported`, which gates
# `ManagedMemoryResource` pool creation. Used by tests that exercise
# `DummyUnifiedMemoryResource`.
try:
if not device.properties.managed_memory:
pytest.skip("Device does not support managed memory operations")
Expand Down
3 changes: 0 additions & 3 deletions cuda_core/tests/memory_ipc/__init__.py

This file was deleted.

3 changes: 0 additions & 3 deletions cuda_core/tests/system/__init__.py

This file was deleted.

3 changes: 1 addition & 2 deletions cuda_core/tests/test_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import ctypes

import helpers
from cuda_python_test_helpers.marks import requires_module
from cuda_python_test_helpers.marks import requires_module, skipif_need_cuda_headers
from helpers.misc import StreamWrapper

try:
Expand All @@ -13,7 +13,6 @@
cp = None
import numpy as np
import pytest
from conftest import skipif_need_cuda_headers

from cuda.core import (
Device,
Expand Down
3 changes: 2 additions & 1 deletion cuda_core/tests/test_managed_memory_warning.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
import warnings

import pytest
from conftest import create_managed_memory_resource_or_skip, xfail_if_mempool_oom
from cuda_python_test_helpers.mempool import xfail_if_mempool_oom
from helpers.memory import create_managed_memory_resource_or_skip

import cuda.bindings
from cuda.core import Device, ManagedMemoryResource, ManagedMemoryResourceOptions
Expand Down
Loading
Loading