Coverage for cuda/core/_dlpack.pyx: 92.68%

123 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-13 01:38 +0000

1# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 

2# 

3# SPDX-License-Identifier: Apache-2.0 

4  

5  

6from enum import IntEnum 

7  

8  

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

27  

28  

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

37  

38  

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+,-

47  

48  

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 

61  

62  

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 

75  

76  

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+,-

90  

91  

92def classify_dl_device(buf: object) -> tuple[int, int]: 

93 """Classify a buffer into a DLPack (device_type, device_id) pair. 

94  

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.:

107  

108  

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+,-

115  

116  

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+,-

123  

124  

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+,-

132  

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

155  

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+,-

167  

168  

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