Coverage for cuda/core/_dlpack.pyx: 92.68%
123 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-19 01:12 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-19 01:12 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
6from enum import IntEnum
9cdef void pycapsule_deleter(object capsule) noexcept:
10 cdef DLManagedTensor* dlm_tensor
11 cdef DLManagedTensorVersioned* dlm_tensor_ver
12 # Do not invoke the deleter on a used capsule.
13 if cpython.PyCapsule_IsValid( 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
14 capsule, DLPACK_TENSOR_UNUSED_NAME):
15 dlm_tensor = <DLManagedTensor*>( 1a
16 cpython.PyCapsule_GetPointer( 1a
17 capsule, DLPACK_TENSOR_UNUSED_NAME))
18 if dlm_tensor.deleter: 1a
19 dlm_tensor.deleter(dlm_tensor) 1a
20 elif cpython.PyCapsule_IsValid( 1]bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
21 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME):
22 dlm_tensor_ver = <DLManagedTensorVersioned*>( 1a
23 cpython.PyCapsule_GetPointer( 1a
24 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME))
25 if dlm_tensor_ver.deleter: 1a
26 dlm_tensor_ver.deleter(dlm_tensor_ver) 1]a
29cdef void deleter(DLManagedTensor* tensor) noexcept with gil:
30 if tensor: 1[a
31 if tensor.dl_tensor.shape: 1[a
32 stdlib.free(tensor.dl_tensor.shape) 1[a
33 if tensor.manager_ctx: 1[a
34 cpython.Py_DECREF(<object>tensor.manager_ctx) 1[a
35 tensor.manager_ctx = NULL 1[a
36 stdlib.free(tensor) 1[a
39cdef void versioned_deleter(DLManagedTensorVersioned* tensor) noexcept with gil:
40 if tensor: 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
41 if tensor.dl_tensor.shape: 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
42 stdlib.free(tensor.dl_tensor.shape) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
43 if tensor.manager_ctx: 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
44 cpython.Py_DECREF(<object>tensor.manager_ctx) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
45 tensor.manager_ctx = NULL 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
46 stdlib.free(tensor) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
49cdef inline DLManagedTensorVersioned* allocate_dlm_tensor_versioned() except? NULL:
50 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
51 try: 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
52 dlm_tensor_ver = <DLManagedTensorVersioned*>( 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
53 stdlib.malloc(sizeof(DLManagedTensorVersioned)))
54 dlm_tensor_ver.dl_tensor.shape = NULL 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
55 dlm_tensor_ver.manager_ctx = NULL 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
56 return dlm_tensor_ver 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
57 except:
58 if dlm_tensor_ver:
59 stdlib.free(dlm_tensor_ver)
60 raise
63cdef inline DLManagedTensor* allocate_dlm_tensor() except? NULL:
64 cdef DLManagedTensor* dlm_tensor = NULL 1[a
65 try: 1[a
66 dlm_tensor = <DLManagedTensor*>( 1[a
67 stdlib.malloc(sizeof(DLManagedTensor)))
68 dlm_tensor.dl_tensor.shape = NULL 1[a
69 dlm_tensor.manager_ctx = NULL 1[a
70 return dlm_tensor 1[a
71 except:
72 if dlm_tensor:
73 stdlib.free(dlm_tensor)
74 raise
77cdef inline int setup_dl_tensor_layout(DLTensor* dl_tensor, object buf) except -1:
78 dl_tensor.ndim = 1 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
79 cdef int64_t* shape_strides = \
80 <int64_t*>stdlib.malloc(sizeof(int64_t) * 2) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
81 if shape_strides == NULL: 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
82 raise MemoryError()
83 # DLPack v1.2+ requires non-NULL strides for ndim != 0.
84 shape_strides[0] = <int64_t>buf.size 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
85 shape_strides[1] = 1 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
86 dl_tensor.shape = shape_strides 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
87 dl_tensor.strides = shape_strides + 1 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
88 dl_tensor.byte_offset = 0 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
89 return 0 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
92def classify_dl_device(buf: object) -> tuple[int, int]:
93 """Classify a buffer into a DLPack (device_type, device_id) pair.
95 ``buf`` must expose ``is_device_accessible``, ``is_host_accessible``,
96 ``is_managed``, and ``device_id`` attributes.
97 """
98 cdef bint d = buf.is_device_accessible 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[^|_`{a:;=?@}
99 cdef bint h = buf.is_host_accessible 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[^|_`{a:;=?@}
100 if d and not h: 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[^|_`{a:;=?@}
101 return (_kDLCUDA, buf.device_id) 1|a}
102 if d and h: 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[^_`{:;=?@
103 return (_kDLCUDAManaged if buf.is_managed else _kDLCUDAHost, 0) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./`{:;=?@
104 if not d and h: 1[^_
105 return (_kDLCPU, 0) 1_
106 raise BufferError("buffer is neither device-accessible nor host-accessible") 1[^
109cdef inline int setup_dl_tensor_device(DLTensor* dl_tensor, object buf) except -1:
110 cdef DLDevice* device = &dl_tensor.device 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
111 dev_type, dev_id = classify_dl_device(buf) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
112 device.device_type = <_DLDeviceType>dev_type 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
113 device.device_id = <int32_t>dev_id 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
114 return 0 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
117cdef inline int setup_dl_tensor_dtype(DLTensor* dl_tensor) except -1 nogil:
118 cdef DLDataType* dtype = &dl_tensor.dtype 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
119 dtype.code = <uint8_t>kDLInt 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
120 dtype.lanes = <uint16_t>1 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
121 dtype.bits = <uint8_t>8 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
122 return 0 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
125cpdef object make_py_capsule(object buf, bint versioned):
126 cdef DLManagedTensor* dlm_tensor = NULL 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
127 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
128 cdef DLTensor* dl_tensor
129 cdef void* tensor_ptr
130 cdef const char* capsule_name
131 cdef object ret = None 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
133 try: 1]bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
134 if versioned: 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
135 dlm_tensor_ver = allocate_dlm_tensor_versioned() 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
136 # Transfer the reference to manager_ctx
137 cpython.Py_INCREF(buf) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
138 dlm_tensor_ver.manager_ctx = <void*>buf 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
139 dlm_tensor_ver.deleter = versioned_deleter 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
140 dlm_tensor_ver.version.major = DLPACK_MAJOR_VERSION 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
141 dlm_tensor_ver.version.minor = DLPACK_MINOR_VERSION 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
142 dlm_tensor_ver.flags = 0 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
143 dl_tensor = &dlm_tensor_ver.dl_tensor 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
144 tensor_ptr = dlm_tensor_ver 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
145 capsule_name = DLPACK_VERSIONED_TENSOR_UNUSED_NAME 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
146 else:
147 dlm_tensor = allocate_dlm_tensor() 1[a
148 # Transfer the reference to manager_ctx
149 cpython.Py_INCREF(buf) 1[a
150 dlm_tensor.manager_ctx = <void*>buf 1[a
151 dlm_tensor.deleter = deleter 1[a
152 dl_tensor = &dlm_tensor.dl_tensor 1[a
153 tensor_ptr = dlm_tensor 1[a
154 capsule_name = DLPACK_TENSOR_UNUSED_NAME 1[a
156 dl_tensor.data = <void*><intptr_t>(int(buf.handle)) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
157 setup_dl_tensor_layout(dl_tensor, buf) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
158 setup_dl_tensor_device(dl_tensor, buf) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./[a:;=?@
159 setup_dl_tensor_dtype(dl_tensor) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
160 ret = cpython.PyCapsule_New(tensor_ptr, capsule_name, pycapsule_deleter) 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
161 except: 1[
162 if ret is None: 1[
163 deleter(dlm_tensor) 1[
164 versioned_deleter(dlm_tensor_ver) 1[
165 raise 1[
166 return ret 1bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()*+,-./a:;=?@
169# Values are fixed by the DLPack spec; see _include/dlpack.h. They are
170# hard-coded here (rather than referencing the cdef extern names) so that the
171# generated .pyi stub doesn't reference Cython-only identifiers.
172class DLDeviceType(IntEnum):
173 kDLCPU = 1
174 kDLCUDA = 2
175 kDLCUDAHost = 3
176 kDLCUDAManaged = 13