diff --git a/cuda_bindings/pixi.toml b/cuda_bindings/pixi.toml index 9d122d17413..89ee9a31046 100644 --- a/cuda_bindings/pixi.toml +++ b/cuda_bindings/pixi.toml @@ -28,7 +28,7 @@ cuda-python-test-helpers = { path = "../cuda_python_test_helpers", editable = tr [feature.docs.dependencies] cuda-bindings = "13.2.*" python = "3.12.*" -cython = ">=3.2.5,<3.3" +cython = ">=3.3,<3.4" enum_tools = "*" make = "*" myst-nb = "*" @@ -44,7 +44,7 @@ sphinx-copybutton = "*" sphinx-toolbox = "*" [feature.cython-tests.dependencies] -cython = ">=3.2.5,<3.3" # for tests that exercise APIs from cython +cython = ">=3.3,<3.4" # for tests that exercise APIs from cython setuptools = "*" # for distutils gxx = "*" # to compile the generated code # These are necessary because running the Cython tests requires compiling @@ -118,7 +118,7 @@ python = "*" cuda-version = "*" setuptools = ">=80" setuptools-scm = ">=8" -cython = ">=3.2.5,<3.3" +cython = ">=3.3,<3.4" cuda-pathfinder = { path = "../cuda_pathfinder" } cuda-cudart-static = "*" cuda-nvrtc-dev = "*" diff --git a/cuda_bindings/pyproject.toml b/cuda_bindings/pyproject.toml index eadc58949f7..1f8ce7fa5d3 100644 --- a/cuda_bindings/pyproject.toml +++ b/cuda_bindings/pyproject.toml @@ -4,7 +4,7 @@ requires = [ "setuptools>=80.0.0", "setuptools_scm[simple]>=8,!=10.1", - "cython>=3.2.5,<3.3", + "cython>=3.3,<3.4", "cuda-pathfinder>=1.5", ] build-backend = "build_hooks" @@ -43,7 +43,7 @@ all = [ [dependency-groups] test = [ - "cython>=3.2.5,<3.3", + "cython>=3.3,<3.4", "setuptools>=80.0.0", # TODO: remove the Python 3.15 guard once 3.15 is officially supported "matplotlib>=3.5.0,<=3.10.9; python_version < '3.15'", diff --git a/cuda_bindings/tests/test_cuda.py b/cuda_bindings/tests/test_cuda.py index 7bef2b844aa..fa008f12a97 100644 --- a/cuda_bindings/tests/test_cuda.py +++ b/cuda_bindings/tests/test_cuda.py @@ -579,12 +579,12 @@ def test_eglFrame(): assert int(val.frame.pArray[0]) == 0 assert int(val.frame.pArray[1]) == 0 assert int(val.frame.pArray[2]) == 0 - val.frame.pArray = [1, 2, 3] + val.frame.pArray = [cuda.CUarray(x) for x in (1, 2, 3)] # [, , ] assert int(val.frame.pArray[0]) == 1 assert int(val.frame.pArray[1]) == 2 assert int(val.frame.pArray[2]) == 3 - val.frame.pArray = [cuda.CUarray(4), 2, 3] + val.frame.pArray = [cuda.CUarray(x) for x in (4, 2, 3)] # [, , ] assert int(val.frame.pArray[0]) == 4 assert int(val.frame.pArray[1]) == 2 diff --git a/cuda_bindings/tests/test_cudart.py b/cuda_bindings/tests/test_cudart.py index 3dc4fba7461..fd3f918ea22 100644 --- a/cuda_bindings/tests/test_cudart.py +++ b/cuda_bindings/tests/test_cudart.py @@ -1285,12 +1285,12 @@ def test_cudart_eglFrame(): assert int(frame.frame.pArray[0]) == 0 assert int(frame.frame.pArray[1]) == 0 assert int(frame.frame.pArray[2]) == 0 - frame.frame.pArray = [1, 2, 3] + frame.frame.pArray = [cudart.cudaArray_t(x) for x in (1, 2, 3)] # [, , ] assert int(frame.frame.pArray[0]) == 1 assert int(frame.frame.pArray[1]) == 2 assert int(frame.frame.pArray[2]) == 3 - frame.frame.pArray = [1, 2, cudart.cudaArray_t(4)] + frame.frame.pArray = [cudart.cudaArray_t(x) for x in (1, 2, 4)] # [, , ] assert int(frame.frame.pArray[0]) == 1 assert int(frame.frame.pArray[1]) == 2 diff --git a/cuda_core/cuda/core/_device_resources.pyi b/cuda_core/cuda/core/_device_resources.pyi index a6837e837e9..7e8ce90df84 100644 --- a/cuda_core/cuda/core/_device_resources.pyi +++ b/cuda_core/cuda/core/_device_resources.pyi @@ -40,7 +40,7 @@ class SMResourceOptions: preferred_coscheduled_sm_count: int | SequenceABC[int] | None = None backfill: bool | SequenceABC[bool] = False -@dataclass +@dataclass(init=False) class WorkqueueResourceOptions: """Customizable :obj:`WorkqueueResource.configure` options. @@ -60,7 +60,7 @@ class WorkqueueResourceOptions: sharing_scope: WorkqueueSharingScopeType | str | None = None concurrency_limit: int | None = None - def __post_init__(self): ... + def __init__(self, sharing_scope: WorkqueueSharingScopeType | str | None=None, concurrency_limit: int | None=None): ... class SMResource: """Represent an SM (streaming multiprocessor) resource partition. diff --git a/cuda_core/cuda/core/_device_resources.pyx b/cuda_core/cuda/core/_device_resources.pyx index 15ca6c56685..50e12ca54b9 100644 --- a/cuda_core/cuda/core/_device_resources.pyx +++ b/cuda_core/cuda/core/_device_resources.pyx @@ -126,7 +126,12 @@ cdef class SMResourceOptions: backfill: bool | SequenceABC[bool] = False -@dataclass +# init=False: Cython 3.3 wraps the dataclass-generated __init__ in a +# critical_section and then warns (promoted to an error by our +# warning_errors=True build) that the __post_init__ call inside it is +# unprotected Python attribute access. A hand-written __init__ sidesteps +# that; construction of a not-yet-shared object needs no lock anyway. +@dataclass(init=False) cdef class WorkqueueResourceOptions: """Customizable :obj:`WorkqueueResource.configure` options. @@ -147,13 +152,19 @@ cdef class WorkqueueResourceOptions: sharing_scope: WorkqueueSharingScopeType | str | None = None concurrency_limit: int | None = None - def __post_init__(self): + def __init__( + self, + sharing_scope: WorkqueueSharingScopeType | str | None = None, + concurrency_limit: int | None = None, + ): from cuda.core.typing import WorkqueueSharingScopeType - check_str_enum(self.sharing_scope, WorkqueueSharingScopeType, allow_none=True) - if self.concurrency_limit is not None and self.concurrency_limit < 1: + check_str_enum(sharing_scope, WorkqueueSharingScopeType, allow_none=True) + if concurrency_limit is not None and concurrency_limit < 1: raise ValueError( - f"concurrency_limit must be >= 1, got {self.concurrency_limit}" + f"concurrency_limit must be >= 1, got {concurrency_limit}" ) + self.sharing_scope = sharing_scope + self.concurrency_limit = concurrency_limit cdef inline int _validate_split_field_length( diff --git a/cuda_core/cuda/core/_memory/_buffer.pyx b/cuda_core/cuda/core/_memory/_buffer.pyx index 316f07f2912..d23c177fa1b 100644 --- a/cuda_core/cuda/core/_memory/_buffer.pyx +++ b/cuda_core/cuda/core/_memory/_buffer.pyx @@ -404,16 +404,24 @@ cdef class Buffer: return _ipc.Buffer_from_ipc_descriptor(cls, mr, ipc_descriptor, stream) @property - @cython.critical_section def ipc_descriptor(self) -> IPCBufferDescriptor: """Descriptor for sharing this buffer with other processes.""" Buffer_check_open(self) cdef object ipc_data - if self._ipc_data is None: + # The critical section only protects the cdef-level check-and-set of + # self._ipc_data; the Python-level IPCDataForBuffer construction and + # .ipc_descriptor read happen outside the lock (Cython 3.3 warns that + # Python attribute access is not usefully protected by critical_section). + with cython.critical_section(self): + ipc_data = self._ipc_data + if ipc_data is None: ipc_data = IPCDataForBuffer(_ipc.Buffer_get_ipc_descriptor(self), False) - if self._ipc_data is None: - self._ipc_data = ipc_data - return self._ipc_data.ipc_descriptor + with cython.critical_section(self): + if self._ipc_data is None: + self._ipc_data = ipc_data + else: + ipc_data = self._ipc_data + return ipc_data.ipc_descriptor def close(self, stream: Stream | GraphBuilder | None = None) -> None: """Deallocate this buffer asynchronously on the given stream. diff --git a/cuda_core/cuda/core/_memoryview.pyx b/cuda_core/cuda/core/_memoryview.pyx index 6b287f68c1a..cdc8457ed20 100644 --- a/cuda_core/cuda/core/_memoryview.pyx +++ b/cuda_core/cuda/core/_memoryview.pyx @@ -560,7 +560,6 @@ cdef class StridedMemoryView: self._layout = layout return self._layout - @cython.critical_section cdef inline object get_buffer(self): """ Returns Buffer instance with the underlying data. @@ -568,20 +567,29 @@ cdef class StridedMemoryView: Otherwise, it will create a new instance with owner set to the exporting object. """ cdef object buffer - if self._buffer is None: + with cython.critical_section(self): + buffer = self._buffer + if buffer is None: if isinstance(self.exporting_obj, Buffer): buffer = self.exporting_obj else: buffer = Buffer.from_handle(self.ptr, 0, owner=self.exporting_obj) - if self._buffer is None: - self._buffer = buffer - return self._buffer + # The critical section only protects the cdef-level check-and-set + # of self._buffer; the Python-level Buffer construction above + # happens outside the lock (Cython 3.3 warns that Python attribute + # access is not usefully protected by critical_section). + with cython.critical_section(self): + if self._buffer is None: + self._buffer = buffer + else: + buffer = self._buffer + return buffer - @cython.critical_section cdef inline object get_dtype(self): cdef object dtype - if self._dtype is None: - dtype = None + with cython.critical_section(self): + dtype = self._dtype + if dtype is None: if self.dl_tensor != NULL: dtype = dtype_dlpack_to_numpy(&self.dl_tensor.dtype) elif isinstance(self.metadata, int): @@ -590,9 +598,16 @@ cdef class StridedMemoryView: self.metadata) elif self.metadata is not None: dtype = _typestr2dtype(self.metadata["typestr"]) - if self._dtype is None: - self._dtype = dtype - return self._dtype + # The critical section only protects the cdef-level check-and-set + # of self._dtype; the Python-level dtype resolution above happens + # outside the lock (Cython 3.3 warns that Python attribute access + # is not usefully protected by critical_section). + with cython.critical_section(self): + if self._dtype is None: + self._dtype = dtype + else: + dtype = self._dtype + return dtype cdef void _smv_pycapsule_deleter(object capsule) noexcept: diff --git a/cuda_core/pixi.toml b/cuda_core/pixi.toml index b2c6a3389c3..1407dc2dcd3 100644 --- a/cuda_core/pixi.toml +++ b/cuda_core/pixi.toml @@ -56,7 +56,7 @@ CUDA_HOME = "$CONDA_PREFIX/targets/sbsa-linux" CUDA_HOME = "$CONDA_PREFIX/Library" [feature.cython-tests.dependencies] -cython = ">=3.2.5,<3.3" # for tests that exercise APIs from cython +cython = ">=3.3,<3.4" # for tests that exercise APIs from cython setuptools = "*" # for distutils gxx = "*" # to compile the generated code # These are necessary because running the Cython tests requires compiling @@ -97,7 +97,7 @@ cuda-version = "12.*" [feature.docs.dependencies] cuda-core = { path = "." } -cython = ">=3.2.5,<3.3" +cython = ">=3.3,<3.4" myst-parser = "*" numpy = "*" numpydoc = "*" @@ -214,7 +214,7 @@ python = "*" cuda-version = "*" setuptools = ">=80" setuptools-scm = ">=8" -cython = ">=3.2.5,<3.3" +cython = ">=3.3,<3.4" cuda-nvrtc-dev = "*" cuda-bindings = "*" dlpack = "*" diff --git a/cuda_core/pyproject.toml b/cuda_core/pyproject.toml index e536f2bbf52..ef17e4dec50 100644 --- a/cuda_core/pyproject.toml +++ b/cuda_core/pyproject.toml @@ -6,7 +6,7 @@ requires = [ "setuptools>=80", "setuptools-scm[simple]>=8,!=10.1", - "Cython>=3.2.5,<3.3", + "Cython>=3.3,<3.4", "cuda-pathfinder>=1.5" ] build-backend = "build_hooks" @@ -59,7 +59,7 @@ cu13 = ["cuda-bindings[all]==13.*", "cuda-toolkit==13.*"] [dependency-groups] test = [ - "cython>=3.2.5,<3.3", + "cython>=3.3,<3.4", "setuptools>=80", "pytest==9.1.0", "pytest-benchmark==5.2.3", diff --git a/cuda_pathfinder/pixi.toml b/cuda_pathfinder/pixi.toml index 6236aead9b9..bb22e5f83a7 100644 --- a/cuda_pathfinder/pixi.toml +++ b/cuda_pathfinder/pixi.toml @@ -20,7 +20,7 @@ pytest-run-parallel = ">=0.4.1" # Keep this dependency set aligned with cuda_python/docs/environment-docs.yml. [feature.docs.dependencies] python = "3.12.*" -cython = ">=3.2.5,<3.3" +cython = ">=3.3,<3.4" enum_tools = "*" make = "*" myst-nb = "*" diff --git a/cuda_python/docs/environment-docs.yml b/cuda_python/docs/environment-docs.yml index 3152f0a3a93..2b6cf825ebc 100644 --- a/cuda_python/docs/environment-docs.yml +++ b/cuda_python/docs/environment-docs.yml @@ -7,7 +7,7 @@ channels: dependencies: # ATTENTION: This dependency list is duplicated in # toolshed/setup-docs-env.sh. Please KEEP THEM IN SYNC! - - cython >=3.2.5,<3.3 + - cython >=3.3,<3.4 - myst-parser - numpy - numpydoc diff --git a/toolshed/setup-docs-env.sh b/toolshed/setup-docs-env.sh index 9acbaa8e391..ed12ad19cd9 100755 --- a/toolshed/setup-docs-env.sh +++ b/toolshed/setup-docs-env.sh @@ -39,7 +39,7 @@ echo "Creating environment '${ENV_NAME}'…" # cuda_python/docs/environment-docs.yml. Please KEEP THEM IN SYNC! conda create -y -n "${ENV_NAME}" \ "python=${PYVER}" \ - "cython>=3.2.5,<3.3" \ + "cython>=3.3,<3.4" \ myst-parser \ numpy \ numpydoc \