Coverage for cuda / core / experimental / _dlpack.pyx: 92%
118 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-10 01:19 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-10 01:19 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from enum import IntEnum
8cdef void pycapsule_deleter(object capsule) noexcept:
9 cdef DLManagedTensor* dlm_tensor
10 cdef DLManagedTensorVersioned* dlm_tensor_ver
11 # Do not invoke the deleter on a used capsule.
12 if cpython.PyCapsule_IsValid(
13 capsule, DLPACK_TENSOR_UNUSED_NAME):
14 dlm_tensor = <DLManagedTensor*>(
15 cpython.PyCapsule_GetPointer(
16 capsule, DLPACK_TENSOR_UNUSED_NAME))
17 if dlm_tensor.deleter:
18 dlm_tensor.deleter(dlm_tensor)
19 elif cpython.PyCapsule_IsValid(
20 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME):
21 dlm_tensor_ver = <DLManagedTensorVersioned*>(
22 cpython.PyCapsule_GetPointer(
23 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME))
24 if dlm_tensor_ver.deleter:
25 dlm_tensor_ver.deleter(dlm_tensor_ver)
28cdef void deleter(DLManagedTensor* tensor) noexcept with gil:
29 if tensor:
30 if tensor.dl_tensor.shape:
31 stdlib.free(tensor.dl_tensor.shape)
32 if tensor.manager_ctx:
33 cpython.Py_DECREF(<object>tensor.manager_ctx)
34 tensor.manager_ctx = NULL
35 stdlib.free(tensor)
38cdef void versioned_deleter(DLManagedTensorVersioned* tensor) noexcept with gil:
39 if tensor:
40 if tensor.dl_tensor.shape:
41 stdlib.free(tensor.dl_tensor.shape)
42 if tensor.manager_ctx:
43 cpython.Py_DECREF(<object>tensor.manager_ctx)
44 tensor.manager_ctx = NULL
45 stdlib.free(tensor)
48cdef inline DLManagedTensorVersioned* allocate_dlm_tensor_versioned() except? NULL:
49 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL
50 try:
51 dlm_tensor_ver = <DLManagedTensorVersioned*>(
52 stdlib.malloc(sizeof(DLManagedTensorVersioned)))
53 dlm_tensor_ver.dl_tensor.shape = NULL
54 dlm_tensor_ver.manager_ctx = NULL
55 return dlm_tensor_ver
56 except:
57 if dlm_tensor_ver:
58 stdlib.free(dlm_tensor_ver)
59 raise
62cdef inline DLManagedTensor* allocate_dlm_tensor() except? NULL:
63 cdef DLManagedTensor* dlm_tensor = NULL
64 try:
65 dlm_tensor = <DLManagedTensor*>(
66 stdlib.malloc(sizeof(DLManagedTensor)))
67 dlm_tensor.dl_tensor.shape = NULL
68 dlm_tensor.manager_ctx = NULL
69 return dlm_tensor
70 except:
71 if dlm_tensor:
72 stdlib.free(dlm_tensor)
73 raise
76cdef inline int setup_dl_tensor_layout(DLTensor* dl_tensor, object buf) except -1:
77 dl_tensor.ndim = 1
78 cdef int64_t* shape_strides = \
79 <int64_t*>stdlib.malloc(sizeof(int64_t) * 2)
80 shape_strides[0] = <int64_t>buf.size
81 shape_strides[1] = 1 # redundant
82 dl_tensor.shape = shape_strides
83 dl_tensor.strides = NULL
84 dl_tensor.byte_offset = 0
85 return 0
88cdef inline int setup_dl_tensor_device(DLTensor* dl_tensor, object buf) except -1:
89 cdef DLDevice* device = &dl_tensor.device
90 # buf should be a Buffer instance
91 if buf.is_device_accessible and not buf.is_host_accessible:
92 device.device_type = _kDLCUDA
93 device.device_id = buf.device_id
94 elif buf.is_device_accessible and buf.is_host_accessible:
95 device.device_type = _kDLCUDAHost
96 device.device_id = 0
97 elif not buf.is_device_accessible and buf.is_host_accessible:
98 device.device_type = _kDLCPU
99 device.device_id = 0
100 else: # not buf.is_device_accessible and not buf.is_host_accessible
101 raise BufferError("invalid buffer")
102 return 0
105cdef inline int setup_dl_tensor_dtype(DLTensor* dl_tensor) except -1 nogil:
106 cdef DLDataType* dtype = &dl_tensor.dtype
107 dtype.code = <uint8_t>kDLInt
108 dtype.lanes = <uint16_t>1
109 dtype.bits = <uint8_t>8
110 return 0
113cpdef object make_py_capsule(object buf, bint versioned):
114 cdef DLManagedTensor* dlm_tensor = NULL
115 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL
116 cdef DLTensor* dl_tensor
117 cdef void* tensor_ptr
118 cdef const char* capsule_name
119 cdef object ret = None
121 try:
122 if versioned:
123 dlm_tensor_ver = allocate_dlm_tensor_versioned()
124 # Transfer the reference to manager_ctx
125 cpython.Py_INCREF(buf)
126 dlm_tensor_ver.manager_ctx = <void*>buf
127 dlm_tensor_ver.deleter = versioned_deleter
128 dlm_tensor_ver.version.major = DLPACK_MAJOR_VERSION
129 dlm_tensor_ver.version.minor = DLPACK_MINOR_VERSION
130 dlm_tensor_ver.flags = 0
131 dl_tensor = &dlm_tensor_ver.dl_tensor
132 tensor_ptr = dlm_tensor_ver
133 capsule_name = DLPACK_VERSIONED_TENSOR_UNUSED_NAME
134 else:
135 dlm_tensor = allocate_dlm_tensor()
136 # Transfer the reference to manager_ctx
137 cpython.Py_INCREF(buf)
138 dlm_tensor.manager_ctx = <void*>buf
139 dlm_tensor.deleter = deleter
140 dl_tensor = &dlm_tensor.dl_tensor
141 tensor_ptr = dlm_tensor
142 capsule_name = DLPACK_TENSOR_UNUSED_NAME
144 dl_tensor.data = <void*><intptr_t>(int(buf.handle))
145 setup_dl_tensor_layout(dl_tensor, buf)
146 setup_dl_tensor_device(dl_tensor, buf)
147 setup_dl_tensor_dtype(dl_tensor)
148 ret = cpython.PyCapsule_New(tensor_ptr, capsule_name, pycapsule_deleter)
149 except:
150 if ret is None:
151 deleter(dlm_tensor)
152 versioned_deleter(dlm_tensor_ver)
153 raise
154 return ret
157class DLDeviceType(IntEnum):
158 kDLCPU = _kDLCPU
159 kDLCUDA = _kDLCUDA
160 kDLCUDAHost = _kDLCUDAHost
161 kDLCUDAManaged = _kDLCUDAManaged