Coverage for cuda/core/_memoryview.pyx: 85.18%

722 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-03 02:41 +0000

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

2# 

3# SPDX-License-Identifier: Apache-2.0 

4  

5from __future__ import annotations 

6  

7cimport cython 

8from ._dlpack cimport * 

9from ._dlpack import classify_dl_device 

10from libc.stdint cimport intptr_t 

11from cuda.core._layout cimport _StridedLayout, get_strides_ptr 

12from cuda.core._stream import Stream 

13  

14import ctypes 

15import functools 

16import sys 

17import warnings 

18from collections.abc import Callable # no-cython-lint # used in string annotations below 

19from typing import TYPE_CHECKING, Any # no-cython-lint # used in string annotations below 

20  

21if TYPE_CHECKING: 

22 from cuda.core._tensor_map import TensorMapDescriptorOptions 

23  

24import numpy 

25  

26from cuda.bindings cimport cydriver 

27from cuda.core._resource_handles cimport ( 

28 EventHandle, 

29 create_event_handle_noctx, 

30 as_cu, 

31) 

32  

33from cuda.core._utils.cuda_utils import handle_return, driver 

34from cuda.core._utils.cuda_utils cimport HANDLE_RETURN 

35  

36  

37from cuda.core._memory import Buffer 

38from cuda.core._memory._buffer cimport Buffer as cyBuffer, Buffer_check_open 

39  

40  

41# --------------------------------------------------------------------------- 

42# Lazy tensor bridge (avoids loading _tensor_bridge.so until torch is used) 

43# --------------------------------------------------------------------------- 

44  

45cdef object _tensor_bridge = None 

46# Cache: type(obj) -> True/False for the torch tensor check. 

47# Once a type is seen, we never re-check. 

48cdef dict _torch_type_cache = {} 

49# Tri-state: None = not checked, True/False = result of version check 

50cdef object _torch_version_ok = None 

51  

52cdef inline bint _torch_version_check(): 

53 """Return True if 2.3 <= torch <= 2.12 (known AOTI ABI range). Memoized. 

54  

55 Lower bound: AOTI functions we use were introduced in PyTorch 2.3. 

56 Upper bound: the ``pyobj_to_aten_handle`` trick relies on the 

57 THPVariable struct layout (PyObject_HEAD followed by at::Tensor cdata) 

58 and the identity ``AtenTensorHandle == at::Tensor*``. Both are 

59 undocumented internals that could change in a future PyTorch version. 

60 We cap at the latest version we have tested against; unknown versions 

61 fall back to the standard DLPack/CAI paths. Bump the upper bound 

62 after verifying a new PyTorch release. 

63 """ 

64 global _torch_version_ok 

65 if _torch_version_ok is not None: 

66 return <bint>_torch_version_ok 

67 torch = sys.modules.get("torch") 

68 if torch is None: 

69 _torch_version_ok = False 

70 return False 

71 try: 

72 major, minor = int(torch.__version__.split(".")[0]), \ 

73 int(torch.__version__.split(".")[1]) 

74 _torch_version_ok = (2, 3) <= (major, minor) <= (2, 12) 

75 except (ValueError, IndexError): 

76 _torch_version_ok = False 

77 return <bint>_torch_version_ok 

78  

79  

80cdef inline bint _is_torch_tensor(object obj): 

81 cdef type tp = type(obj) 25 6 7 9 Z T N O P Q R U V W X Y z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdb$ % k M ! L 8 F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

82 cdef object cached = _torch_type_cache.get(tp) 25 6 7 9 Z T N O P Q R U V W X Y z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdb$ % k M ! L 8 F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

83 if cached is not None: 25 6 7 9 Z T N O P Q R U V W X Y z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdb$ % k M ! L 8 F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

84 return <bint>cached 27 9 Z T N O P Q R U V W X Y B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb$ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a

85 cdef str mod = tp.__module__ or "" 25 6 9 z bbMbdb8 b e c j a Tb

86 cdef bint result = mod.startswith("torch") and hasattr(obj, "data_ptr") \ 25 6 9 z bbMbdb8 b e c j a Tb

87 and _torch_version_check() 

88 _torch_type_cache[tp] = result # setdefault not needed for bools 25 6 9 z bbMbdb8 b e c j a Tb

89 return result 25 6 9 z bbMbdb8 b e c j a Tb

90  

91  

92cdef object _get_tensor_bridge(): 

93 """Bootstrap AOTI symbols, then import _tensor_bridge on first use.""" 

94 global _tensor_bridge 

95 if _tensor_bridge is not None: 

96 return _tensor_bridge 

97 torch_C = sys.modules.get("torch._C") 

98 if torch_C is None: 

99 raise RuntimeError( 

100 "torch._C is not loaded; cannot initialise the tensor bridge. " 

101 "Make sure PyTorch is imported before passing a torch.Tensor.") 

102 ctypes.CDLL(torch_C.__file__, mode=ctypes.RTLD_GLOBAL) 

103 from cuda.core import _tensor_bridge as tb 

104 _tensor_bridge = tb 

105 return _tensor_bridge 

106  

107  

108try: 

109 from ml_dtypes import bfloat16 

110except ImportError: 

111 bfloat16 = None 

112  

113# TODO(leofang): support NumPy structured dtypes 

114  

115  

116cdef extern from "Python.h": 

117 ctypedef struct PyTypeObject: 

118 void* tp_dict 

119 void PyType_Modified(PyTypeObject*) 

120  

121  

122cdef DLPackExchangeAPI _SMV_DLPACK_EXCHANGE_API 

123cdef bint _SMV_DLPACK_EXCHANGE_API_INITED = False 

124_SMV_DLPACK_EXCHANGE_API_CAPSULE = cpython.PyCapsule_New( 

125 <void*>&_SMV_DLPACK_EXCHANGE_API, 

126 b"dlpack_exchange_api", 

127 NULL, 

128) 

129  

130  

131cdef class StridedMemoryView: 

132 """A class holding metadata of a strided dense array/tensor. 

133  

134 A :obj:`StridedMemoryView` instance can be created in three ways: 

135  

136 1. Using the :obj:`args_viewable_as_strided_memory` decorator (recommended) 

137 2. Explicit construction relying on DLPack or CUDA Array Interface, see below. 

138 3. From :obj:`~_memory.Buffer` and shape and size tuples (see 

139 :meth:`from_buffer` classmethod) 

140  

141 ``StridedMemoryView(obj, stream_ptr)`` can be used to create a view from 

142 objects supporting either DLPack (up to v1.0) or CUDA Array Interface 

143 (CAI) v3. When wrapping an arbitrary object it will try the DLPack protocol 

144 first, then the CAI protocol. A :obj:`BufferError` is raised if neither is 

145 supported. 

146  

147 Since either way would take a consumer stream, for DLPack it is passed to 

148 ``obj.__dlpack__()`` as-is (except for :obj:`None`, see below); for CAI, a 

149 stream order will be established between the consumer stream and the 

150 producer stream (from ``obj.__cuda_array_interface__()["stream"]``), as if 

151 ``cudaStreamWaitEvent`` is called by this method. 

152  

153 To opt-out of the stream ordering operation in either DLPack or CAI, 

154 please pass ``stream_ptr=-1``. Note that this deviates (on purpose) 

155 from the semantics of ``obj.__dlpack__(stream=None, ...)`` since ``cuda.core`` 

156 does not encourage using the (legacy) default/null stream, but is 

157 consistent with the CAI's semantics. For DLPack, ``stream=-1`` will be 

158 internally passed to ``obj.__dlpack__()`` instead. 

159  

160 Parameters 

161 ---------- 

162 obj : Any 

163 Any objects that supports either DLPack (up to v1.0) or CUDA Array 

164 Interface (v3). 

165 stream_ptr: int 

166 The pointer address (as Python `int`) to the **consumer** stream. 

167 Stream ordering will be properly established unless ``-1`` is passed. 

168  

169  

170 Attributes 

171 ----------- 

172 ptr : int 

173 Pointer to the tensor buffer (as a Python `int`). 

174 device_id : int 

175 The device ID for where the tensor is located. It is -1 for CPU tensors 

176 (meaning those only accessible from the host). 

177 is_device_accessible : bool 

178 Whether the tensor data can be accessed on the GPU. 

179 readonly: bool 

180 Whether the tensor data can be modified in place. 

181 exporting_obj : Any 

182 A reference to the original tensor object that is being viewed. 

183 If the view is created with :meth:`from_buffer`, 

184 it will be the Buffer instance passed to the method. 

185  

186 """ 

187 def __init__(self, obj: object = None, stream_ptr: int | None = None) -> None: 

188 cdef str clsname = self.__class__.__name__ 20 1 2 3 4 Vbcb

189 if obj is not None: 20 1 2 3 4 Vbcb

190 # populate self's attributes 

191 if check_has_dlpack(obj): 20 1 2 3 4 cb

192 warnings.warn( 101234

193 f"Constructing a {clsname} directly from a DLPack-supporting object is deprecated; " 101234

194 "Use `StridedMemoryView.from_dlpack` or `StridedMemoryView.from_any_interface` instead.", 

195 DeprecationWarning, 101234

196 stacklevel=2, 

197 ) 

198 view_as_dlpack(obj, stream_ptr, self) 101234

199 else: 

200 warnings.warn( 2cb

201 f"Constructing a {clsname} directly from a CUDA-array-interface-supporting object is deprecated; " 2D cb

202 "Use `StridedMemoryView.from_cuda_array_interface` or `StridedMemoryView.from_any_interface` instead.", 

203 DeprecationWarning, 2cb

204 stacklevel=2, 

205 ) 

206 view_as_cai(obj, stream_ptr, self) 2cb

207 else: 

208 warnings.warn( 2Vb

209 f"Constructing an empty {clsname} is deprecated; " 2Vb

210 "use one of the classmethods `from_dlpack`, `from_cuda_array_interface` or `from_any_interface` " 

211 "to construct a StridedMemoryView from an object", 

212 DeprecationWarning, 2Vb

213 stacklevel=2, 

214 ) 

215  

216 @classmethod 

217 def from_dlpack(cls, obj: object, stream_ptr: int | None=None) -> StridedMemoryView: 

218 """Create a view from an object supporting the `DLPack <https://dmlc.github.io/dlpack/latest/>`_ protocol. 

219  

220 Parameters 

221 ---------- 

222 obj : object 

223 An object implementing the `DLPack <https://dmlc.github.io/dlpack/latest/>`_ protocol 

224 (via ``__dlpack__``). 

225 stream_ptr : int, optional 

226 Stream pointer for synchronization. If ``None``, no synchronization is performed. 

227 """ 

228 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 25 6 7 9 Z T N O P Q R U V W X Y B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

229 if _is_torch_tensor(obj): 25 6 7 9 Z T N O P Q R U V W X Y B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

230 _get_tensor_bridge().view_as_torch_tensor(obj, stream_ptr, buf) 

231 return buf 

232 view_as_dlpack(obj, stream_ptr, buf) 2D 5 6 7 9 Z T N O P Q R U V W X Y B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

233 return buf 15679ZTNOPQRUVWXYBCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

234  

235 @classmethod 

236 def from_cuda_array_interface(cls, obj: object, stream_ptr: int | None=None) -> StridedMemoryView: 

237 """Create a view from an object supporting the `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_ protocol. 

238  

239 Parameters 

240 ---------- 

241 obj : object 

242 An object implementing the `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_ protocol. 

243 stream_ptr : int, optional 

244 Stream pointer for synchronization. If ``None``, no synchronization is performed. 

245 """ 

246 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2D z bbMbdb8

247 if _is_torch_tensor(obj): 2z bbMbdb8

248 _get_tensor_bridge().view_as_torch_tensor(obj, stream_ptr, buf) 

249 return buf 

250 view_as_cai(obj, stream_ptr, buf) 2z bbMbdb8

251 return buf 2D z bbdb8

252  

253 @classmethod 

254 def from_array_interface(cls, obj: object) -> StridedMemoryView: 

255 """Create a view from an object supporting the `__array_interface__ <https://numpy.org/doc/stable/reference/arrays.interface.html>`_ protocol. 

256  

257 Parameters 

258 ---------- 

259 obj : object 

260 An object implementing the `__array_interface__ <https://numpy.org/doc/stable/reference/arrays.interface.html>`_ protocol (e.g., a numpy array). 

261 """ 

262 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

263 if _is_torch_tensor(obj): 2D ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

264 _get_tensor_bridge().view_as_torch_tensor(obj, None, buf) 

265 return buf 

266 view_as_array_interface(obj, buf) 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

267 return buf 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab?

268  

269 @classmethod 

270 def from_any_interface(cls, obj: object, stream_ptr: int | None = None) -> StridedMemoryView: 

271 """Create a view by automatically selecting the best available protocol. 

272  

273 Tries `DLPack <https://dmlc.github.io/dlpack/latest/>`_ first, then falls back to 

274 `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_. 

275 ``torch.Tensor`` objects are transparently handled via a fast AOTI path 

276 regardless of which protocol is selected. 

277  

278 Parameters 

279 ---------- 

280 obj : object 

281 An object implementing `DLPack <https://dmlc.github.io/dlpack/latest/>`_ or 

282 `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_. 

283 stream_ptr : int, optional 

284 Stream pointer for synchronization. If ``None``, no synchronization is performed. 

285 """ 

286 if check_has_dlpack(obj): 25 6 7 9 Z T U V W X Y 3bB C A $ % k M ! L E d w g h l m n s t u v o p q r i y x f b e c j a

287 return cls.from_dlpack(obj, stream_ptr) 15679ZTUVWXYBCA$%kM!LEdwghlmnstuvopqriyxfbecja

288 return cls.from_cuda_array_interface(obj, stream_ptr) 

289  

290 @classmethod 

291 def from_buffer( 

292 cls, 

293 buffer : Buffer, 

294 shape : tuple[int, ...], 

295 strides : tuple[int, ...] | None = None, 

296 *, 

297 itemsize : int | None = None, 

298 dtype : numpy.dtype | None = None, 

299 is_readonly : bool = False 

300 ) -> StridedMemoryView: 

301 """ 

302 Creates a :obj:`StridedMemoryView` instance from a :obj:`~_memory.Buffer` and shape and strides tuples. 

303 The Buffer can be either allocation coming from a :obj:`MemoryResource` or an external allocation 

304 wrapped in a :obj:`~_memory.Buffer` object with ``Buffer.from_handle(ptr, size, owner=...)``. 

305  

306 .. caution:: 

307 When creating a :obj:`StridedMemoryView` from a :obj:`~_memory.Buffer`, 

308 no synchronization is performed. It is the user's responsibility to ensure 

309 the data in ``buffer`` is properly synchronized when consuming the view. 

310  

311 Parameters 

312 ---------- 

313 buffer : :obj:`~_memory.Buffer` 

314 The buffer to create the view from. 

315 shape : :obj:`tuple` 

316 The layout describing the shape, strides and itemsize of the elements in 

317 the buffer. 

318 strides : :obj:`tuple` 

319 The layout describing the shape, strides and itemsize of the elements in 

320 the buffer. 

321 dtype : :obj:`numpy.dtype` 

322 Optional dtype. 

323 If specified, the dtype's itemsize must match the layout's itemsize. 

324 is_readonly : bool, optional 

325 Whether the mark the view as readonly. 

326 """ 

327 cdef StridedMemoryView view = StridedMemoryView.__new__(cls) 2NbObgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbYbWbebfbRbPbS #

328 if itemsize is None and dtype is None: 2NbObgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbYbWbebfbRbPbS #

329 raise ValueError("Either itemsize or dtype must be specified") 2Yb

330 if itemsize is not None and dtype is not None and itemsize != dtype.itemsize: 2NbObgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbWbebfbRbPbS #

331 raise ValueError( 2Wb

332 f"itemsize ({itemsize}) does not match dtype.itemsize ({dtype.itemsize})" 2Wb

333 ) 

334 # (itemsize is None XOR dtype is None) OR they are equal 

335 view_buffer_strided( 2NbObgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbS #

336 view, 

337 buffer, 

338 _StridedLayout(shape=shape, strides=strides, itemsize=getattr(dtype, "itemsize", itemsize)), 2D NbObgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbS #

339 dtype, 

340 is_readonly, 

341 ) 

342 return view 2NbObgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS #

343  

344 def __dealloc__(self) -> None: 

345 if self.dl_tensor == NULL: 2NbOb5 6 7 9 Z T N O P Q R U V W X Y 0 1 2 3 4 z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbYbWbebfbRbPbbbMbdb$ % k S Vbcb# M ! L 8 F G H I J K E w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

346 return 2NbObz B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbYbWbebfbRbPbbbMbdbS Vbcb# ! L 8 F G H I J K SbTb

347  

348 if cpython.PyCapsule_IsValid( 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEwghlmnstuvopqriyxfbecja

349 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME): 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEwghlmnstuvopqriyxfbecja

350 data = cpython.PyCapsule_GetPointer( 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEwghlmnstuvopqriyxfeja

351 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME) 1D5679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEwghlmnstuvopqriyxfeja

352 dlm_tensor_ver = <DLManagedTensorVersioned*>data 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEwghlmnstuvopqriyxfeja

353 if dlm_tensor_ver.deleter != NULL: 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEwghlmnstuvopqriyxfeja

354 dlm_tensor_ver.deleter(dlm_tensor_ver) 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEwghlmnstuvopqriyxfea

355 elif cpython.PyCapsule_IsValid( 1bca

356 self.metadata, DLPACK_TENSOR_USED_NAME): 1bca

357 data = cpython.PyCapsule_GetPointer( 1bca

358 self.metadata, DLPACK_TENSOR_USED_NAME) 1Dbca

359 dlm_tensor = <DLManagedTensor*>data 1bca

360 if dlm_tensor.deleter != NULL: 1bca

361 dlm_tensor.deleter(dlm_tensor) 1ba

362  

363 def view( 

364 self, layout : _StridedLayout | None = None, dtype : numpy.dtype | None = None 

365 ) -> StridedMemoryView: 

366 """ 

367 Creates a new view with adjusted layout and dtype. 

368 Same as calling :meth:`from_buffer` with the current buffer. 

369 """ 

370 cdef StridedMemoryView view = StridedMemoryView.__new__(self.__class__) 2D B C A ebfb! L F G H I J K

371 if layout is None and dtype is None: 2B C A ebfb! L F G H I J K

372 return self 1!

373 if layout is None: 2B C A ebfbL F G H I J K

374 layout = self.get_layout() 1BCAL

375 if dtype is None: 2B C A ebfbL F G H I J K

376 dtype = self.get_dtype() 2ebfbF G H I J K

377 view_buffer_strided(view, self.get_buffer(), layout, dtype, self.readonly) 2B C A ebfbL F G H I J K

378 return view 2D B C A ebfbL F G H I J K

379  

380 def as_tensor_map( 

381 self, 

382 box_dim: tuple[int, ...] | None = None, 

383 *, 

384 options: TensorMapDescriptorOptions | None = None, 

385 element_strides: tuple[int, ...] | None = None, 

386 data_type: object = None, 

387 interleave: object = None, 

388 swizzle: object = None, 

389 l2_promotion: object = None, 

390 oob_fill: object = None, 

391 ) -> object: 

392 """Create a tiled :obj:`TensorMapDescriptor` from this view. 

393  

394 This is the public entry point for creating tiled tensor map 

395 descriptors in ``cuda.core``. Pass either ``box_dim`` and the 

396 individual keyword arguments directly, or provide bundled tiled 

397 options via ``options=``. 

398 """ 

399 from cuda.core._tensor_map import TensorMapDescriptor 1T

400  

401 kwargs = {} 1DT

402 if options is not None: 1T

403 kwargs["options"] = options 

404 if element_strides is not None: 1T

405 kwargs["element_strides"] = element_strides 1T

406 if data_type is not None: 1T

407 kwargs["data_type"] = data_type 1T

408 if interleave is not None: 1T

409 kwargs["interleave"] = interleave 

410 if swizzle is not None: 1T

411 kwargs["swizzle"] = swizzle 1T

412 if l2_promotion is not None: 1T

413 kwargs["l2_promotion"] = l2_promotion 1DT

414 if oob_fill is not None: 1T

415 kwargs["oob_fill"] = oob_fill 1T

416 return TensorMapDescriptor._from_tiled(self, box_dim, **kwargs) 1T

417  

418 def copy_from( 

419 self, 

420 other: StridedMemoryView, 

421 stream: Stream, 

422 allocator: object = None, 

423 blocking: bool | None = None, 

424 ) -> None: 

425 """ 

426 Copies the data from the other view into this view. 

427  

428 The copy can be performed between following memory spaces: 

429 host-to-device, device-to-host, device-to-device (on the same device). 

430  

431 Parameters 

432 ---------- 

433 other : StridedMemoryView 

434 The view to copy data from. 

435 stream : Stream | None, optional 

436 The stream to schedule the copy on. 

437 allocator : MemoryResource | None, optional 

438 If temporary buffers are needed, the specified memory resources 

439 will be used to allocate the memory. If not specified, default 

440 resources will be used. 

441 blocking : bool | None, optional 

442 Whether the call should block until the copy is complete. 

443 * ``True``: the ``stream`` is synchronized with the host at the end of the call, 

444 blocking until the copy is complete. 

445 * ``False``: if possible, the call returns immediately once the copy is scheduled. 

446 However, in some cases of host-to-device or device-to-host copies, the call may 

447 still synchronize with the host if necessary. 

448 * ``None`` (default): 

449 * for device-to-device, it defaults to ``False`` (non-blocking), 

450 * for host-to-device or device-to-host, it defaults to ``True`` (blocking). 

451 """ 

452 raise NotImplementedError("Sorry, not supported: copy_from") 1$

453  

454 def copy_to( 

455 self, 

456 other: StridedMemoryView, 

457 stream: Stream | None = None, 

458 allocator: object = None, 

459 blocking: bool | None = None, 

460 ) -> None: 

461 """ 

462 Copies the data from this view into the ``other`` view. 

463  

464 For details, see :meth:`copy_from`. 

465 """ 

466 raise NotImplementedError("Sorry, not supported: copy_to") 1%

467  

468 def __dlpack__( 

469 self, 

470 *, 

471 stream: int | None = None, 

472 max_version: tuple[int, int] | None = None, 

473 dl_device: tuple[int, int] | None = None, 

474 copy: bool | None = None, 

475 ) -> object: 

476 # Similar to Buffer.__dlpack__: no implicit synchronization is performed. 

477 if dl_device is not None: 17zBCAkSwghlmnstuvopqriyxfbecja

478 raise BufferError("Sorry, not supported: dl_device other than None") 17

479 if copy is True: 17zBCAkSwghlmnstuvopqriyxfbecja

480 raise BufferError("Sorry, not supported: copy=True") 17

481  

482 cdef bint versioned 

483 if max_version is None: 17zBCAkSwghlmnstuvopqriyxfbecja

484 versioned = False 1zBCASxbca

485 else: 

486 if not isinstance(max_version, tuple) or len(max_version) != 2: 17kwghlmnstuvopqriyfbeja

487 raise BufferError(f"Expected max_version tuple[int, int], got {max_version}") 17

488 versioned = max_version >= (1, 0) 1kwghlmnstuvopqriyfbeja

489  

490 # NOTE: stream is accepted for protocol compatibility but not used. 

491 cdef object capsule = _smv_make_py_capsule(self, versioned) 1zBCAkSwghlmnstuvopqriyxfbecja

492 return capsule 1zkwghlmnstuvopqriyxfbecja

493  

494 def __dlpack_device__(self) -> tuple[int, int]: 

495 cdef _DLDeviceType device_type 

496 cdef int32_t device_id 

497 _smv_get_dl_device(self, &device_type, &device_id) 1D56zkbecja

498 return (<int>device_type, int(device_id)) 156zkbecja

499  

500 @property 

501 def _layout(self) -> _StridedLayout: 

502 """ 

503 The layout of the tensor. For StridedMemoryView created from DLPack or CAI, 

504 the layout is inferred from the tensor object's metadata. 

505 """ 

506 return self.get_layout() 2gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbVbL F G H I J K

507  

508 @property 

509 def size(self) -> int: 

510 return self.get_layout().get_volume() 2N O P Q R U V W X Y 0 1 2 3 4 ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? bb

511  

512 @property 

513 def shape(self) -> tuple[int, ...]: 

514 """ 

515 Shape of the tensor. 

516 """ 

517 return self.get_layout().get_shape_tuple() 2NbObZ N O P Q R U V W X Y 0 1 2 3 4 ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbbbdbcb# M 8 F G H I J K d b e

518  

519 @property 

520 def strides(self) -> tuple[int, ...] | None: 

521 """ 

522 Strides of the tensor (in **counts**, not bytes). 

523 """ 

524 return self.get_layout().get_strides_tuple() 2Z N O P Q R U V W X Y 0 1 2 3 4 ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbbbdb# M

525  

526 @property 

527 def dtype(self) -> numpy.dtype | None: 

528 """ 

529 Data type of the tensor. 

530  

531 Supports standard NumPy dtypes as well as narrow data types (e.g., ``bfloat16``) 

532 when the optional `ml_dtypes <https://github.com/jax-ml/ml_dtypes>`_ package is 

533 installed. If ``ml_dtypes`` is not available and such a tensor is encountered, 

534 a :obj:`NotImplementedError` will be raised. 

535 """ 

536 return self.get_dtype() 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbPb# M L F G H I J K

537  

538 def __repr__(self) -> str: 

539 return (f"StridedMemoryView(ptr={self.ptr},\n" 1#M

540 + f" shape={self.shape},\n" 1#M

541 + f" strides={self.strides},\n" 1D#M

542 + f" itemsize={self._layout.itemsize},\n" 1#M

543 + f" dtype={get_simple_repr(self.dtype)},\n" 1#M

544 + f" device_id={self.device_id},\n" 1#M

545 + f" is_device_accessible={self.is_device_accessible},\n" 1#M

546 + f" readonly={self.readonly},\n" 1#M

547 + f" exporting_obj={get_simple_repr(self.exporting_obj)})") 1#M

548  

549 @cython.critical_section 

550 cdef inline _StridedLayout get_layout(self): 

551 cdef _StridedLayout layout 

552 if self._layout is None: 2NbObZ N O P Q R U V W X Y 0 1 2 3 4 z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbbbMbdbk S Vbcb# M L 8 F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

553 if self.dl_tensor: 2Z N O P Q R U V W X Y 0 1 2 3 4 z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdbk VbcbM L 8 F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

554 layout = layout_from_dlpack(self.dl_tensor) 1ZNOPQRUVWXY01234BCAkMLFGHIJKEdwghlmnstuvopqriyxfbecja

555 elif self.metadata is not None: 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdbVbcb8

556 layout = layout_from_cai(self.metadata) 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdbcb8

557 else: 

558 raise ValueError("Cannot infer layout from the exporting object") 2Vb

559 if self._layout is None: 2Z N O P Q R U V W X Y 0 1 2 3 4 z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? bbdbk cbM L 8 F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

560 self._layout = layout 2Z N O P Q R U V W X Y 0 1 2 3 4 z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? bbdbk cbM L 8 F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

561 return self._layout 2NbObZ N O P Q R U V W X Y 0 1 2 3 4 z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbbbdbk S cb# M L 8 F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

562  

563 @cython.critical_section 

564 cdef inline object get_buffer(self): 

565 """ 

566 Returns Buffer instance with the underlying data. 

567 If the SMV was created from a Buffer, it will return the same Buffer instance. 

568 Otherwise, it will create a new instance with owner set to the exporting object. 

569 """ 

570 cdef object buffer 

571 if self._buffer is None: 2z B C A ebfbL F G H I J K

572 if isinstance(self.exporting_obj, Buffer): 1zBCALFGHIJK

573 buffer = self.exporting_obj 

574 else: 

575 buffer = Buffer.from_handle(self.ptr, 0, owner=self.exporting_obj) 1zBCALFGHIJK

576 if self._buffer is None: 1zBCALFGHIJK

577 self._buffer = buffer 1zBCALFGHIJK

578 return self._buffer 2z B C A ebfbL F G H I J K

579  

580 @cython.critical_section 

581 cdef inline object get_dtype(self): 

582 cdef object dtype 

583 if self._dtype is None: 2D z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbk S # M L F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

584 dtype = None 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? k S # M F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

585 if self.dl_tensor != NULL: 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? k S # M F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

586 dtype = dtype_dlpack_to_numpy(&self.dl_tensor.dtype) 1kMFGHIJKEdwghlmnstuvopqriyxfbecja

587 elif isinstance(self.metadata, int): 2D z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? S #

588 # AOTI dtype code stored by the torch tensor bridge 

589 dtype = _get_tensor_bridge().resolve_aoti_dtype( 

590 self.metadata) 

591 elif self.metadata is not None: 2D z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? S #

592 dtype = _typestr2dtype(self.metadata["typestr"]) 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab?

593 if self._dtype is None: 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? k S # M F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

594 self._dtype = dtype 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? k S # M F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

595 return self._dtype 2D z B C A ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbk S # M L F G H I J K E d w g h l m n s t u v o p q r i y x f b e c j a

596  

597  

598cdef void _smv_pycapsule_deleter(object capsule) noexcept: 

599 cdef DLManagedTensor* dlm_tensor 

600 cdef DLManagedTensorVersioned* dlm_tensor_ver 

601 # Do not invoke the deleter on a used capsule. 

602 if cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME): 1zkwghlmnstuvopqriyxfbea

603 dlm_tensor = <DLManagedTensor*>( 1zx

604 cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME) 1zx

605 ) 

606 if dlm_tensor.deleter: 1zx

607 dlm_tensor.deleter(dlm_tensor) 1zx

608 elif cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 1kwghlmnstuvopqriyfbea

609 dlm_tensor_ver = <DLManagedTensorVersioned*>( 1Df

610 cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 1f

611 ) 

612 if dlm_tensor_ver.deleter: 1f

613 dlm_tensor_ver.deleter(dlm_tensor_ver) 1Df

614  

615  

616cdef inline void _smv_release_export_resources(void* manager_ctx, int64_t* shape_ptr) noexcept with gil: 

617 if shape_ptr: 1zBCAkSwghlmnstuvopqriyxfbecja

618 stdlib.free(shape_ptr) 1zkwghlmnstuvopqrixfbecja

619 if manager_ctx: 1zBCAkSwghlmnstuvopqriyxfbecja

620 cpython.Py_DECREF(<object>manager_ctx) 1zBCAkSwghlmnstuvopqriyxfbecja

621  

622  

623cdef void _smv_deleter(DLManagedTensor* tensor) noexcept with gil: 

624 if tensor: 1zBCASxbca

625 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1zBCASxbca

626 tensor.manager_ctx = NULL 1zBCASxbca

627 stdlib.free(tensor) 1zBCASxbca

628  

629  

630cdef void _smv_versioned_deleter(DLManagedTensorVersioned* tensor) noexcept with gil: 

631 if tensor: 1BCAkSwghlmnstuvopqriyfbeja

632 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1Dkwghlmnstuvopqriyfbeja

633 tensor.manager_ctx = NULL 1kwghlmnstuvopqriyfbeja

634 stdlib.free(tensor) 1kwghlmnstuvopqriyfbeja

635  

636  

637cdef inline DLManagedTensorVersioned* _smv_allocate_dlm_tensor_versioned() except? NULL: 

638 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1kdwghlmnstuvopqriyfbeja

639 dlm_tensor_ver = <DLManagedTensorVersioned*>stdlib.malloc(sizeof(DLManagedTensorVersioned)) 1kdwghlmnstuvopqriyfbeja

640 if dlm_tensor_ver == NULL: 1Dkdwghlmnstuvopqriyfbeja

641 raise MemoryError() 

642 dlm_tensor_ver.dl_tensor.shape = NULL 1kdwghlmnstuvopqriyfbeja

643 dlm_tensor_ver.manager_ctx = NULL 1kdwghlmnstuvopqriyfbeja

644 return dlm_tensor_ver 1kdwghlmnstuvopqriyfbeja

645  

646  

647cdef inline DLManagedTensor* _smv_allocate_dlm_tensor() except? NULL: 

648 cdef DLManagedTensor* dlm_tensor = NULL 1DzBCASxbca

649 dlm_tensor = <DLManagedTensor*>stdlib.malloc(sizeof(DLManagedTensor)) 1zBCASxbca

650 if dlm_tensor == NULL: 1zBCASxbca

651 raise MemoryError() 

652 dlm_tensor.dl_tensor.shape = NULL 1zBCASxbca

653 dlm_tensor.manager_ctx = NULL 1zBCASxbca

654 return dlm_tensor 1zBCASxbca

655  

656  

657cdef inline int _smv_dtype_numpy_to_dlpack(object dtype_obj, DLDataType* out_dtype) except -1: 

658 cdef object np_dtype = numpy.dtype(dtype_obj) 1zBCAkEdwghlmnstuvopqriyxfbecja

659 if np_dtype.fields is not None: 1zBCAkEdwghlmnstuvopqriyxfbecja

660 raise BufferError("Structured dtypes are not supported for DLPack export") 1C

661 if not np_dtype.isnative and np_dtype.byteorder not in ("=", "|"): 1zBAkEdwghlmnstuvopqriyxfbecja

662 raise BufferError("Non-native-endian dtypes are not supported for DLPack export") 1B

663  

664 cdef str kind = np_dtype.kind 1zAkEdwghlmnstuvopqriyxfbecja

665 cdef int bits = np_dtype.itemsize * 8 1zAkEdwghlmnstuvopqriyxfbecja

666 cdef uint8_t code 

667 if kind == "b": 1zAkEdwghlmnstuvopqriyxfbecja

668 if bits != 8: 1Dw

669 raise BufferError(f"Unsupported bool dtype itemsize: {np_dtype.itemsize}") 

670 code = <uint8_t>kDLBool 1w

671 elif kind == "i": 1zAkEdghlmnstuvopqriyxfbecja

672 if bits not in (8, 16, 32, 64): 1kEstuvxfbecja

673 raise BufferError(f"Unsupported signed integer dtype: {np_dtype}") 

674 code = <uint8_t>kDLInt 1kEstuvxfbecja

675 elif kind == "u": 1zAdghlmnopqriy

676 if bits not in (8, 16, 32, 64): 1opqr

677 raise BufferError(f"Unsupported unsigned integer dtype: {np_dtype}") 

678 code = <uint8_t>kDLUInt 1Dopqr

679 elif kind == "f": 1zAdghlmniy

680 if bits not in (16, 32, 64): 1zdlmn

681 raise BufferError(f"Unsupported floating dtype: {np_dtype}") 

682 code = <uint8_t>kDLFloat 1zdlmn

683 elif kind == "c": 1DAghiy

684 if bits not in (64, 128): 1ghiy

685 raise BufferError(f"Unsupported complex dtype: {np_dtype}") 

686 code = <uint8_t>kDLComplex 1ghiy

687 else: 

688 raise BufferError(f"Unsupported dtype for DLPack export: {np_dtype}") 1A

689  

690 out_dtype.code = code 1zkEdwghlmnstuvopqriyxfbecja

691 out_dtype.bits = <uint8_t>bits 1zkEdwghlmnstuvopqriyxfbecja

692 out_dtype.lanes = <uint16_t>1 1zkEdwghlmnstuvopqriyxfbecja

693 return 0 1zkEdwghlmnstuvopqriyxfbecja

694  

695  

696cdef inline int _smv_get_dl_device( 

697 StridedMemoryView view, 

698 _DLDeviceType* out_device_type, 

699 int32_t* out_device_id, 

700) except -1: 

701 cdef _DLDeviceType device_type 

702 cdef int32_t device_id 

703 cdef object buf 

704 if view.dl_tensor != NULL: 156zkEdwghlmnstuvopqriyxfbecja

705 device_type = view.dl_tensor.device.device_type 156kEdwghlmnstuvopqriyxfbecja

706 if device_type == _kDLCUDA: 156kEdwghlmnstuvopqriyxfbecja

707 device_id = view.dl_tensor.device.device_id 

708 else: 

709 # CPU, CUDAHost, and CUDAManaged use device_id=0 in DLPack. 

710 device_id = 0 156kEdwghlmnstuvopqriyxfbecja

711 elif view.is_device_accessible: 1z

712 buf = view.get_buffer() 1z

713 dev_type, dev_id = classify_dl_device(buf) 1z

714 device_type = <_DLDeviceType>dev_type 1z

715 device_id = <int32_t>dev_id 1z

716 else: 

717 device_type = _kDLCPU 

718 device_id = 0 

719  

720 out_device_type[0] = device_type 156zkEdwghlmnstuvopqriyxfbecja

721 out_device_id[0] = device_id 156zkEdwghlmnstuvopqriyxfbecja

722 return 0 156zkEdwghlmnstuvopqriyxfbecja

723  

724  

725cdef inline int _smv_setup_dl_tensor_common( 

726 DLTensor* dl_tensor, 

727 StridedMemoryView view, 

728 _StridedLayout layout, 

729) except -1: 

730 cdef object dtype_obj = view.get_dtype() 1zBCAkSEdwghlmnstuvopqriyxfbecja

731 if dtype_obj is None: 1zBCAkSEdwghlmnstuvopqriyxfbecja

732 raise BufferError( 1S

733 "Cannot export StridedMemoryView via DLPack without dtype information; " 

734 "create the view with dtype specified." 

735 ) 

736 _smv_dtype_numpy_to_dlpack(dtype_obj, &dl_tensor.dtype) 1zBCAkEdwghlmnstuvopqriyxfbecja

737 _smv_get_dl_device(view, &dl_tensor.device.device_type, &dl_tensor.device.device_id) 1zkEdwghlmnstuvopqriyxfbecja

738  

739 cdef int ndim = layout.base.ndim 1zkEdwghlmnstuvopqriyxfbecja

740 dl_tensor.ndim = ndim 1zkEdwghlmnstuvopqriyxfbecja

741 if layout.get_volume() == 0: 1zkEdwghlmnstuvopqriyxfbecja

742 dl_tensor.data = NULL 1i

743 else: 

744 dl_tensor.data = <void*><intptr_t>view.ptr 1zkEdwghlmnstuvopqryxfbecja

745 dl_tensor.byte_offset = 0 1zkEdwghlmnstuvopqriyxfbecja

746 return 0 1zkEdwghlmnstuvopqriyxfbecja

747  

748  

749cdef inline int _smv_setup_dl_tensor(DLTensor* dl_tensor, StridedMemoryView view) except -1: 

750 cdef _StridedLayout layout = view.get_layout() 1zBCAkSdwghlmnstuvopqriyxfbecja

751 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1zBCAkSdwghlmnstuvopqriyxfbecja

752  

753 cdef int i 

754 cdef int64_t* shape_strides = NULL 1zkdwghlmnstuvopqriyxfbecja

755 cdef int64_t* strides_src = NULL 1zkdwghlmnstuvopqriyxfbecja

756 cdef int ndim = dl_tensor.ndim 1zkdwghlmnstuvopqriyxfbecja

757 if ndim == 0: 1zkdwghlmnstuvopqriyxfbecja

758 dl_tensor.shape = NULL 1y

759 dl_tensor.strides = NULL 1y

760 else: 

761 # DLPack v1.2+ requires non-NULL strides for ndim != 0. 

762 shape_strides = <int64_t*>stdlib.malloc(sizeof(int64_t) * 2 * ndim) 1zkdwghlmnstuvopqrixfbecja

763 if shape_strides == NULL: 1zkdwghlmnstuvopqrixfbecja

764 raise MemoryError() 

765 try: 1zkdwghlmnstuvopqrixfbecja

766 strides_src = get_strides_ptr(layout.base) 1zkdwghlmnstuvopqrixfbecja

767 for i in range(ndim): 1zkdwghlmnstuvopqrixfbecja

768 shape_strides[i] = layout.base.shape[i] 1zkdwghlmnstuvopqrixfbecja

769 shape_strides[i + ndim] = strides_src[i] 1zkdwghlmnstuvopqrixfbecja

770 except Exception: 

771 stdlib.free(shape_strides) 

772 raise 

773 dl_tensor.shape = shape_strides 1zkdwghlmnstuvopqrixfbecja

774 dl_tensor.strides = shape_strides + ndim 1zkdwghlmnstuvopqrixfbecja

775 return 0 1zkdwghlmnstuvopqriyxfbecja

776  

777  

778cdef inline int _smv_setup_dltensor_borrowed(DLTensor* dl_tensor, StridedMemoryView view) except -1: 

779 cdef _StridedLayout layout = view.get_layout() 1E

780 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1E

781  

782 if dl_tensor.ndim == 0: 1E

783 dl_tensor.shape = NULL 

784 dl_tensor.strides = NULL 

785 else: 

786 dl_tensor.shape = layout.base.shape 1E

787 # For temporary/non-owning exchange we provide explicit strides. 

788 dl_tensor.strides = get_strides_ptr(layout.base) 1E

789 return 0 1E

790  

791  

792cdef inline int _smv_fill_managed_tensor_versioned( 

793 DLManagedTensorVersioned* dlm_tensor_ver, 

794 StridedMemoryView view, 

795) except -1: 

796 cpython.Py_INCREF(view) 1kdwghlmnstuvopqriyfbeja

797 dlm_tensor_ver.manager_ctx = <void*>view 1kdwghlmnstuvopqriyfbeja

798 dlm_tensor_ver.deleter = _smv_versioned_deleter 1kdwghlmnstuvopqriyfbeja

799 dlm_tensor_ver.version.major = DLPACK_MAJOR_VERSION 1kdwghlmnstuvopqriyfbeja

800 dlm_tensor_ver.version.minor = DLPACK_MINOR_VERSION 1kdwghlmnstuvopqriyfbeja

801 dlm_tensor_ver.flags = DLPACK_FLAG_BITMASK_READ_ONLY if view.readonly else 0 1kdwghlmnstuvopqriyfbeja

802 _smv_setup_dl_tensor(&dlm_tensor_ver.dl_tensor, view) 1kdwghlmnstuvopqriyfbeja

803 return 0 1kdwghlmnstuvopqriyfbeja

804  

805  

806cdef inline int _smv_fill_managed_tensor( 

807 DLManagedTensor* dlm_tensor, 

808 StridedMemoryView view, 

809) except -1: 

810 cpython.Py_INCREF(view) 1zBCASxbca

811 dlm_tensor.manager_ctx = <void*>view 1zBCASxbca

812 dlm_tensor.deleter = _smv_deleter 1zBCASxbca

813 _smv_setup_dl_tensor(&dlm_tensor.dl_tensor, view) 1zBCASxbca

814 return 0 1zxbca

815  

816  

817cdef object _smv_make_py_capsule(StridedMemoryView view, bint versioned): 

818 cdef DLManagedTensor* dlm_tensor = NULL 1zBCAkSwghlmnstuvopqriyxfbecja

819 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1zBCAkSwghlmnstuvopqriyxfbecja

820 cdef object capsule = None 1zBCAkSwghlmnstuvopqriyxfbecja

821 cdef void* tensor_ptr = NULL 1zBCAkSwghlmnstuvopqriyxfbecja

822 cdef const char* capsule_name 

823 try: 1zBCAkSwghlmnstuvopqriyxfbecja

824 if versioned: 1zBCAkSwghlmnstuvopqriyxfbecja

825 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1kwghlmnstuvopqriyfbeja

826 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, view) 1kwghlmnstuvopqriyfbeja

827 tensor_ptr = <void*>dlm_tensor_ver 1kwghlmnstuvopqriyfbeja

828 capsule_name = DLPACK_VERSIONED_TENSOR_UNUSED_NAME 1kwghlmnstuvopqriyfbeja

829 else: 

830 dlm_tensor = _smv_allocate_dlm_tensor() 1zBCASxbca

831 _smv_fill_managed_tensor(dlm_tensor, view) 1zBCASxbca

832 tensor_ptr = <void*>dlm_tensor 1zxbca

833 capsule_name = DLPACK_TENSOR_UNUSED_NAME 1zxbca

834 capsule = cpython.PyCapsule_New(tensor_ptr, capsule_name, _smv_pycapsule_deleter) 1zkwghlmnstuvopqriyxfbecja

835 except Exception: 1BCAS

836 if capsule is None: 1BCAS

837 _smv_deleter(dlm_tensor) 1BCAS

838 _smv_versioned_deleter(dlm_tensor_ver) 1BCAS

839 raise 1BCAS

840 return capsule 1zkwghlmnstuvopqriyxfbecja

841  

842  

843cdef inline StridedMemoryView _smv_from_dlpack_capsule(object capsule, object exporting_obj): 

844 cdef void* data = NULL 1d

845 cdef DLTensor* dl_tensor = NULL 1d

846 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1d

847 cdef DLManagedTensor* dlm_tensor = NULL 1d

848 cdef bint is_readonly = False 1d

849 cdef const char* used_name = NULL 1d

850 if cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 1d

851 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 1d

852 dlm_tensor_ver = <DLManagedTensorVersioned*>data 1d

853 dl_tensor = &dlm_tensor_ver.dl_tensor 1d

854 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 1d

855 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 1d

856 elif cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME): 

857 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME) 

858 dlm_tensor = <DLManagedTensor*>data 

859 dl_tensor = &dlm_tensor.dl_tensor 

860 is_readonly = False 

861 used_name = DLPACK_TENSOR_USED_NAME 

862 else: 

863 raise BufferError("Invalid DLPack capsule") 

864  

865 cpython.PyCapsule_SetName(capsule, used_name) 1d

866  

867 cdef StridedMemoryView view = StridedMemoryView.__new__(StridedMemoryView) 1d

868 view.dl_tensor = dl_tensor 1d

869 view.metadata = capsule 1d

870 view.ptr = <intptr_t>(dl_tensor.data) + <intptr_t>(dl_tensor.byte_offset) 1d

871 view.readonly = is_readonly 1d

872 view.exporting_obj = exporting_obj 1d

873 if dl_tensor.device.device_type == _kDLCPU: 1d

874 view.device_id = -1 1d

875 view.is_device_accessible = False 1d

876 elif dl_tensor.device.device_type in (_kDLCUDA, _kDLCUDAHost, _kDLCUDAManaged): 

877 view.device_id = dl_tensor.device.device_id 

878 view.is_device_accessible = True 

879 else: 

880 raise BufferError("device not supported") 

881 return view 1d

882  

883  

884cdef int _smv_managed_tensor_allocator( 

885 DLTensor* prototype, 

886 DLManagedTensorVersioned** out, 

887 void* error_ctx, 

888 void (*SetError)(void* error_ctx, const char* kind, const char* message) noexcept, 

889) noexcept with gil: 

890 if out != NULL: 2Zb

891 out[0] = NULL 2Zb

892 if SetError != NULL: 2Zb

893 SetError(error_ctx, b"NotImplementedError", b"managed_tensor_allocator is not supported by StridedMemoryView") 

894 cpython.PyErr_SetString(NotImplementedError, b"managed_tensor_allocator is not supported by StridedMemoryView") 2Zb

895 return -1 2Zb

896  

897  

898cdef int _smv_managed_tensor_from_py_object_no_sync( 

899 void* py_object, 

900 DLManagedTensorVersioned** out, 

901) noexcept with gil: 

902 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1d

903 if out == NULL: 1d

904 cpython.PyErr_SetString(RuntimeError, b"out cannot be NULL") 

905 return -1 

906 out[0] = NULL 1d

907 cdef object obj = <object>py_object 1d

908 if not isinstance(obj, StridedMemoryView): 1d

909 cpython.PyErr_SetString(TypeError, b"py_object must be a StridedMemoryView") 

910 return -1 

911 try: 1d

912 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1d

913 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, <StridedMemoryView>obj) 1d

914 except Exception: 

915 _smv_versioned_deleter(dlm_tensor_ver) 

916 return -1 

917 out[0] = dlm_tensor_ver 1d

918 return 0 1d

919  

920  

921cdef int _smv_managed_tensor_to_py_object_no_sync( 

922 DLManagedTensorVersioned* tensor, 

923 void** out_py_object, 

924) noexcept with gil: 

925 cdef object capsule 

926 cdef object py_view 

927 if out_py_object == NULL: 2d 0b

928 cpython.PyErr_SetString(RuntimeError, b"out_py_object cannot be NULL") 

929 return -1 

930 out_py_object[0] = NULL 2d 0b

931 if tensor == NULL: 2d 0b

932 cpython.PyErr_SetString(RuntimeError, b"tensor cannot be NULL") 20b

933 return -1 20b

934 try: 1d

935 capsule = cpython.PyCapsule_New( 1d

936 <void*>tensor, 

937 DLPACK_VERSIONED_TENSOR_UNUSED_NAME, 

938 _smv_pycapsule_deleter, 

939 ) 

940 py_view = _smv_from_dlpack_capsule(capsule, capsule) 1d

941 cpython.Py_INCREF(py_view) 1d

942 out_py_object[0] = <void*>py_view 1d

943 except Exception: 

944 return -1 

945 return 0 1d

946  

947  

948cdef int _smv_dltensor_from_py_object_no_sync( 

949 void* py_object, 

950 DLTensor* out, 

951) noexcept with gil: 

952 if out == NULL: 21bE

953 cpython.PyErr_SetString(RuntimeError, b"out cannot be NULL") 

954 return -1 

955 cdef object obj = <object>py_object 21bE

956 if not isinstance(obj, StridedMemoryView): 21bE

957 cpython.PyErr_SetString(TypeError, b"py_object must be a StridedMemoryView") 21b

958 return -1 21b

959 try: 1E

960 _smv_setup_dltensor_borrowed(out, <StridedMemoryView>obj) 1E

961 except Exception: 

962 return -1 

963 return 0 1E

964  

965  

966cdef int _smv_current_work_stream( 

967 _DLDeviceType device_type, 

968 int32_t device_id, 

969 void** out_current_stream, 

970) noexcept with gil: 

971 if out_current_stream == NULL: 26b

972 cpython.PyErr_SetString(RuntimeError, b"out_current_stream cannot be NULL") 

973 return -1 

974 # cuda.core has no global/current stream state today. 

975 out_current_stream[0] = NULL 26b

976 return 0 26b

977  

978  

979cdef void _init_smv_dlpack_exchange_api(): 

980 global _SMV_DLPACK_EXCHANGE_API_INITED 

981 if _SMV_DLPACK_EXCHANGE_API_INITED: 

982 return 

983 _SMV_DLPACK_EXCHANGE_API.header.version.major = DLPACK_MAJOR_VERSION 

984 _SMV_DLPACK_EXCHANGE_API.header.version.minor = DLPACK_MINOR_VERSION 

985 _SMV_DLPACK_EXCHANGE_API.header.prev_api = NULL 

986 _SMV_DLPACK_EXCHANGE_API.managed_tensor_allocator = _smv_managed_tensor_allocator 

987 _SMV_DLPACK_EXCHANGE_API.managed_tensor_from_py_object_no_sync = _smv_managed_tensor_from_py_object_no_sync 

988 _SMV_DLPACK_EXCHANGE_API.managed_tensor_to_py_object_no_sync = _smv_managed_tensor_to_py_object_no_sync 

989 _SMV_DLPACK_EXCHANGE_API.dltensor_from_py_object_no_sync = _smv_dltensor_from_py_object_no_sync 

990 _SMV_DLPACK_EXCHANGE_API.current_work_stream = _smv_current_work_stream 

991 _SMV_DLPACK_EXCHANGE_API_INITED = True 

992  

993  

994_init_smv_dlpack_exchange_api() 

995# cdef classes are immutable types in Cython 3, so inject these attributes 

996# directly into the type dict. 

997(<dict>(<PyTypeObject*>StridedMemoryView).tp_dict)["__dlpack_c_exchange_api__"] = _SMV_DLPACK_EXCHANGE_API_CAPSULE 

998(<dict>(<PyTypeObject*>StridedMemoryView).tp_dict)["__c_dlpack_exchange_api__"] = _SMV_DLPACK_EXCHANGE_API_CAPSULE 

999PyType_Modified(<PyTypeObject*>StridedMemoryView) 

1000  

1001  

1002cdef str get_simple_repr(obj): 

1003 # TODO: better handling in np.dtype objects 

1004 cdef object obj_class 

1005 cdef str obj_repr 

1006 if isinstance(obj, type): 1#M

1007 obj_class = obj 

1008 else: 

1009 obj_class = obj.__class__ 1#M

1010 if obj_class.__module__ in (None, "builtins"): 1#M

1011 obj_repr = obj_class.__name__ 1#

1012 else: 

1013 obj_repr = f"{obj_class.__module__}.{obj_class.__name__}" 1#M

1014 return obj_repr 1#M

1015  

1016  

1017  

1018cdef bint check_has_dlpack(obj) except*: 

1019 cdef bint has_dlpack 

1020 if hasattr(obj, "__dlpack__") and hasattr(obj, "__dlpack_device__"): 25 6 7 9 Z T N O P Q R U V W X Y 0 1 2 3 4 3bB C A $ % k cbXbM ! L E d w g h l m n s t u v o p q r i y x f b e c j a

1021 has_dlpack = True 15679ZTNOPQRUVWXY01234BCA$%kM!LEdwghlmnstuvopqriyxfbecja

1022 elif hasattr(obj, "__cuda_array_interface__"): 23bcbXb

1023 has_dlpack = False 2cbXb

1024 else: 

1025 raise BufferError( 23b

1026 "the input object does not support any data exchange protocol") 

1027 return has_dlpack 25 6 7 9 Z T N O P Q R U V W X Y 0 1 2 3 4 B C A $ % k cbXbM ! L E d w g h l m n s t u v o p q r i y x f b e c j a

1028  

1029  

1030cdef class _StridedMemoryViewProxy: 

1031 cdef readonly: 

1032 object obj 

1033 bint has_dlpack 

1034  

1035 def __init__(self, obj: object) -> None: 

1036 self.obj = obj 2N O P Q R Xb

1037 self.has_dlpack = check_has_dlpack(obj) 2N O P Q R Xb

1038  

1039 cpdef StridedMemoryView view(self, stream_ptr=None): 

1040 if self.has_dlpack: 1NOPQR

1041 return StridedMemoryView.from_dlpack(self.obj, stream_ptr) 1NOPQR

1042 else: 

1043 return StridedMemoryView.from_cuda_array_interface(self.obj, stream_ptr) 

1044  

1045  

1046cdef StridedMemoryView view_as_dlpack(obj, stream_ptr, view=None): 

1047 cdef int dldevice, device_id 

1048 cdef bint is_device_accessible, is_readonly 

1049 is_device_accessible = False 25 6 7 9 Z T N O P Q R U V W X Y 0 1 2 3 4 B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

1050 dldevice, device_id = obj.__dlpack_device__() 25 6 7 9 Z T N O P Q R U V W X Y 0 1 2 3 4 B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

1051 if dldevice == _kDLCPU: 25 6 7 9 Z T N O P Q R U V W X Y 0 1 2 3 4 B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a Tb

1052 assert device_id == 0 27 9 Z T N O P Q R U V W X Y 0 1 2 3 4 B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a

1053 device_id = -1 27 9 Z T N O P Q R U V W X Y 0 1 2 3 4 B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a

1054 if stream_ptr is None: 27 9 Z T N O P Q R U V W X Y 0 1 2 3 4 B C A $ % k M ! L F G H I J K E d w g h l m n s t u v o p q r i y x f Sbb e c j a

1055 raise BufferError("stream=None is ambiguous with view()") 2Sb

1056 elif stream_ptr == -1: 179ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1057 stream_ptr = None 179ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1058 elif dldevice == _kDLCUDA: 

1059 assert device_id >= 0 

1060 is_device_accessible = True 

1061 # no need to check other stream values, it's a pass-through 

1062 if stream_ptr is None: 

1063 raise BufferError("stream=None is ambiguous with view()") 

1064 elif dldevice in (_kDLCUDAHost, _kDLCUDAManaged): 

1065 is_device_accessible = True 156

1066 # just do a pass-through without any checks, as pinned/managed memory can be 

1067 # accessed on both host and device 

1068 else: 

1069 raise BufferError("device not supported") 2Tb

1070  

1071 cdef object capsule 

1072 try: 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1073 capsule = obj.__dlpack__( 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1074 stream=int(stream_ptr) if stream_ptr else None, 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1075 max_version=(DLPACK_MAJOR_VERSION, DLPACK_MINOR_VERSION)) 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1076 except TypeError: 1bca

1077 capsule = obj.__dlpack__( 1bca

1078 stream=int(stream_ptr) if stream_ptr else None) 1bca

1079  

1080 cdef void* data = NULL 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1081 cdef DLTensor* dl_tensor 

1082 cdef DLManagedTensorVersioned* dlm_tensor_ver 

1083 cdef DLManagedTensor* dlm_tensor 

1084 cdef const char *used_name 

1085 if cpython.PyCapsule_IsValid( 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1086 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 

1087 data = cpython.PyCapsule_GetPointer( 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1088 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 

1089 dlm_tensor_ver = <DLManagedTensorVersioned*>data 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1090 dl_tensor = &dlm_tensor_ver.dl_tensor 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1091 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1092 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1093 elif cpython.PyCapsule_IsValid( 1bca

1094 capsule, DLPACK_TENSOR_UNUSED_NAME): 

1095 data = cpython.PyCapsule_GetPointer( 1bca

1096 capsule, DLPACK_TENSOR_UNUSED_NAME) 

1097 dlm_tensor = <DLManagedTensor*>data 1bca

1098 dl_tensor = &dlm_tensor.dl_tensor 1bca

1099 is_readonly = False 1bca

1100 used_name = DLPACK_TENSOR_USED_NAME 1bca

1101 else: 

1102 assert False 

1103  

1104 cpython.PyCapsule_SetName(capsule, used_name) 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1105  

1106 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1107 buf.dl_tensor = dl_tensor 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1108 buf.metadata = capsule 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1109 buf.ptr = <intptr_t>(dl_tensor.data) + <intptr_t>(dl_tensor.byte_offset) 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1110 buf.device_id = device_id 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1111 buf.is_device_accessible = is_device_accessible 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1112 buf.readonly = is_readonly 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1113 buf.exporting_obj = obj 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1114  

1115 return buf 15679ZTNOPQRUVWXY01234BCA$%kM!LFGHIJKEdwghlmnstuvopqriyxfbecja

1116  

1117  

1118@functools.lru_cache 

1119def _typestr2dtype(str typestr) -> numpy.dtype: 

1120 return numpy.dtype(typestr) 2' ( ) * + , - . / : ; = ? cb

1121  

1122  

1123@functools.lru_cache 

1124def _typestr2itemsize(str typestr) -> int: 

1125 return _typestr2dtype(typestr).itemsize 2' ( ) * + , - . / : ; = ? cb

1126  

1127  

1128cdef object dtype_dlpack_to_numpy(DLDataType* dtype): 

1129 cdef int bits = dtype.bits 1kMFGHIJKEdwghlmnstuvopqriyxfbecja

1130 if dtype.lanes != 1: 1kMFGHIJKEdwghlmnstuvopqriyxfbecja

1131 # TODO: return a NumPy structured dtype? 

1132 raise NotImplementedError( 

1133 f'vector dtypes (lanes={dtype.lanes}) is not supported') 

1134 if dtype.code == kDLUInt: 1kMFGHIJKEdwghlmnstuvopqriyxfbecja

1135 if bits == 8: 1opqr

1136 np_dtype = numpy.uint8 1o

1137 elif bits == 16: 

1138 np_dtype = numpy.uint16 1p

1139 elif bits == 32: 

1140 np_dtype = numpy.uint32 1q

1141 elif bits == 64: 

1142 np_dtype = numpy.uint64 1r

1143 else: 

1144 raise TypeError('uint{} is not supported.'.format(bits)) 

1145 elif dtype.code == kDLInt: 

1146 if bits == 8: 1kMFGHIJKEstuvxfbecja

1147 np_dtype = numpy.int8 1s

1148 elif bits == 16: 

1149 np_dtype = numpy.int16 1t

1150 elif bits == 32: 

1151 np_dtype = numpy.int32 1kMFGHIJKEuxfbecja

1152 elif bits == 64: 

1153 np_dtype = numpy.int64 1v

1154 else: 

1155 raise TypeError('int{} is not supported.'.format(bits)) 

1156 elif dtype.code == kDLFloat: 

1157 if bits == 16: 1dlmn

1158 np_dtype = numpy.float16 1l

1159 elif bits == 32: 

1160 np_dtype = numpy.float32 1m

1161 elif bits == 64: 

1162 np_dtype = numpy.float64 1dn

1163 else: 

1164 raise TypeError('float{} is not supported.'.format(bits)) 

1165 elif dtype.code == kDLComplex: 

1166 # TODO(leofang): support complex32 

1167 if bits == 64: 1ghiy

1168 np_dtype = numpy.complex64 1g

1169 elif bits == 128: 

1170 np_dtype = numpy.complex128 1hiy

1171 else: 

1172 raise TypeError('complex{} is not supported.'.format(bits)) 

1173 elif dtype.code == kDLBool: 

1174 if bits == 8: 1w

1175 np_dtype = numpy.bool_ 1w

1176 else: 

1177 raise TypeError(f'{bits}-bit bool is not supported') 

1178 elif dtype.code == kDLBfloat: 

1179 if bfloat16 is not None: 

1180 np_dtype = numpy.dtype("bfloat16") 

1181 else: 

1182 raise NotImplementedError( 

1183 'Support for bfloat16 within cuda-core requires `ml_dtypes`' 

1184 'to be installed.' 

1185 ) 

1186 else: 

1187 raise TypeError('Unsupported dtype. dtype code: {}'.format(dtype.code)) 

1188  

1189 # We want the dtype object not just the type object 

1190 return numpy.dtype(np_dtype) 1kMFGHIJKEdwghlmnstuvopqriyxfbecja

1191  

1192  

1193cpdef StridedMemoryView view_as_cai(obj, stream_ptr, view=None): 

1194 cdef dict cai_data = obj.__cuda_array_interface__ 24b2b7b8bz bbMbdbcb8

1195 if cai_data.get("version", 0) < 3: 24b2b7b8bz bbMbdbcb8

1196 raise BufferError("only CUDA Array Interface v3 or above is supported") 27b8b

1197 if cai_data.get("mask") is not None: 24b2bz bbMbdbcb8

1198 raise BufferError("mask is not supported") 24b

1199 if stream_ptr is None: 22bz bbMbdbcb8

1200 raise BufferError("stream=None is ambiguous with view()") 22b

1201  

1202 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2z bbMbdbcb8

1203 buf.exporting_obj = obj 2z bbMbdbcb8

1204 buf.metadata = cai_data 2z bbMbdbcb8

1205 buf.dl_tensor = NULL 2z bbMbdbcb8

1206 # Validate shape/strides/typestr eagerly so constructor paths fail fast. 

1207 buf.get_layout() 2z bbMbdbcb8

1208 buf.ptr, buf.readonly = cai_data["data"] 2z bbdbcb8

1209 buf.is_device_accessible = True 2z bbdbcb8

1210 if buf.ptr != 0: 2z bbdbcb8

1211 buf.device_id = handle_return( 1z8

1212 driver.cuPointerGetAttribute( 1z8

1213 driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL, 1z8

1214 buf.ptr)) 1z8

1215 else: 

1216 buf.device_id = handle_return(driver.cuCtxGetDevice()) 2bbdbcb

1217  

1218 cdef intptr_t producer_s, consumer_s 

1219 cdef EventHandle h_event 

1220 stream_ptr = int(stream_ptr) 2z bbdbcb8

1221 if stream_ptr != -1: 2z bbdbcb8

1222 stream = cai_data.get("stream") 18

1223 if stream is not None: 18

1224 producer_s = <intptr_t>(stream) 18

1225 consumer_s = <intptr_t>(stream_ptr) 18

1226 assert producer_s > 0 18

1227 # establish stream order 

1228 if producer_s != consumer_s: 18

1229 with nogil: 18

1230 h_event = create_event_handle_noctx(cydriver.CUevent_flags.CU_EVENT_DISABLE_TIMING) 18

1231 HANDLE_RETURN(cydriver.cuEventRecord( 18

1232 as_cu(h_event), <cydriver.CUstream>producer_s)) 

1233 HANDLE_RETURN(cydriver.cuStreamWaitEvent( 18

1234 <cydriver.CUstream>consumer_s, as_cu(h_event), 0)) 

1235 elif _is_torch_tensor(obj): 

1236 # PyTorch's __cuda_array_interface__ reports version 2 and 

1237 # omits the "stream" field, so the standard CAI sync path 

1238 # above is a no-op for torch tensors. This is unsafe: the 

1239 # consumer has no guarantee that the producer's work is 

1240 # visible. We fix this by querying PyTorch's current CUDA 

1241 # stream via the AOTI stable C ABI and performing the same 

1242 # event-based stream ordering. 

1243 _get_tensor_bridge().sync_torch_stream( 

1244 buf.device_id, <intptr_t>(stream_ptr)) 

1245  

1246 return buf 2z bbdbcb8

1247  

1248  

1249cpdef StridedMemoryView view_as_array_interface(obj, view=None): 

1250 cdef dict data = obj.__array_interface__ 25b9b!b' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

1251 if data.get("version", 0) < 3: 25b9b!b' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

1252 raise BufferError("only NumPy Array Interface v3 or above is supported") 29b!b

1253 if data.get("mask") is not None: 25b' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

1254 raise BufferError("mask is not supported") 25b

1255  

1256 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

1257 buf.exporting_obj = obj 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

1258 buf.metadata = data 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

1259 buf.dl_tensor = NULL 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

1260 # Validate shape/strides/typestr eagerly so constructor paths fail fast. 

1261 buf.get_layout() 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? Qb

1262 buf.ptr, buf.readonly = data["data"] 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab?

1263 buf.is_device_accessible = False 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab?

1264 buf.device_id = handle_return(driver.cuCtxGetDevice()) 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab?

1265 return buf 2' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab?

1266  

1267  

1268def args_viewable_as_strided_memory(arg_indices: tuple[int, ...]) -> Callable[[Callable[..., Any]], Callable[..., Any]]: 

1269 """ 

1270 Decorator to create proxy objects to :obj:`StridedMemoryView` for the 

1271 specified positional arguments. 

1272  

1273 This allows array/tensor attributes to be accessed inside the function 

1274 implementation, while keeping the function body array-library-agnostic (if 

1275 desired). 

1276  

1277 Inside the decorated function, the specified arguments become instances 

1278 of an (undocumented) proxy type, regardless of its original source. A 

1279 :obj:`StridedMemoryView` instance can be obtained by passing the (consumer) 

1280 stream pointer (as a Python `int`) to the proxies's ``view()`` method. For 

1281 example: 

1282  

1283 .. code-block:: python 

1284  

1285 @args_viewable_as_strided_memory((1,)) 

1286 def my_func(arg0, arg1, arg2, stream: Stream): 

1287 # arg1 can be any object supporting DLPack or CUDA Array Interface 

1288 view = arg1.view(stream.handle) 

1289 assert isinstance(view, StridedMemoryView) 

1290 ... 

1291  

1292 Parameters 

1293 ---------- 

1294 arg_indices : tuple 

1295 The indices of the target positional arguments. 

1296 """ 

1297 def wrapped_func_with_indices(func: "Callable") -> "Callable": 1NOPQR

1298 @functools.wraps(func) 1NOPQR

1299 def wrapped_func(*args, **kwargs) -> object: 

1300 args = list(args) 1NOPQR

1301 cdef int idx 

1302 for idx in arg_indices: 1NOPQR

1303 args[idx] = _StridedMemoryViewProxy(args[idx]) 1NOPQR

1304 return func(*args, **kwargs) 1NOPQR

1305 return wrapped_func 1NOPQR

1306 return wrapped_func_with_indices 1NOPQR

1307  

1308  

1309cdef inline _StridedLayout layout_from_dlpack(DLTensor* dl_tensor): 

1310 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 1ZNOPQRUVWXY01234BCAkMLFGHIJKEdwghlmnstuvopqriyxfbecja

1311 cdef int nbits = dl_tensor.dtype.bits * dl_tensor.dtype.lanes 1ZNOPQRUVWXY01234BCAkMLFGHIJKEdwghlmnstuvopqriyxfbecja

1312 cdef int itemsize = nbits >> 3 1ZNOPQRUVWXY01234BCAkMLFGHIJKEdwghlmnstuvopqriyxfbecja

1313 if (itemsize << 3) != nbits: 1ZNOPQRUVWXY01234BCAkMLFGHIJKEdwghlmnstuvopqriyxfbecja

1314 raise ValueError("dl_tensor.dtype.bits must be a multiple of 8") 

1315 layout.init_from_ptr(dl_tensor.ndim, dl_tensor.shape, dl_tensor.strides, itemsize) 1ZNOPQRUVWXY01234BCAkMLFGHIJKEdwghlmnstuvopqriyxfbecja

1316 return layout 1ZNOPQRUVWXY01234BCAkMLFGHIJKEdwghlmnstuvopqriyxfbecja

1317  

1318  

1319cdef _StridedLayout layout_from_cai(object metadata): 

1320 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdbcb8

1321 cdef object shape = metadata["shape"] 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdbcb8

1322 cdef object strides = metadata.get("strides") 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdbcb8

1323 cdef int itemsize = _typestr2itemsize(metadata["typestr"]) 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdbcb8

1324 layout.init_from_tuple(shape, strides, itemsize, True) 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? QbbbMbdbcb8

1325 return layout 2z ' ( ) * @ + [ , - . / ] ^ _ : ; ` = { | } ~ ab? bbdbcb8

1326  

1327  

1328cdef inline intptr_t get_data_ptr(object buffer, _StridedLayout layout) except? 0: 

1329 return <intptr_t>(int(buffer.handle)) + layout.get_slice_offset_in_bytes() 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1330  

1331  

1332cdef inline int view_buffer_strided( 

1333 StridedMemoryView view, 

1334 object buffer, 

1335 _StridedLayout layout, 

1336 object dtype, 

1337 bint is_readonly, 

1338) except -1: 

1339 if isinstance(buffer, Buffer): 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbS # L F G H I J K

1340 Buffer_check_open(<cyBuffer>buffer) 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbS # L F G H I J K

1341 if dtype is not None: 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbS # L F G H I J K

1342 dtype = numpy.dtype(dtype) 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbL F G H I J K

1343 if dtype.itemsize != layout.itemsize: 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbL F G H I J K

1344 raise ValueError( 

1345 f"The dtype's itemsize ({dtype.itemsize}) does not match the layout's " 

1346 f"itemsize ({layout.itemsize})." 

1347 ) 

1348 # Check the layout's offset range [min_offset, max_offset] fits 

1349 # within the [0, buffer.size - 1] range. 

1350 # The required_size_in_bytes fails if min_offset < 0. 

1351 # NB. For external memory, both positive and negative offsets can be valid, 

1352 # but for a proper check we'd need to know both size and data offset, 

1353 # while neither is reported by the packages. 

1354 cdef bint is_allocated = buffer.memory_resource is not None 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbS # L F G H I J K

1355 if is_allocated and buffer.size < layout.get_required_size_in_bytes(): 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbUbebfbRbPbS # L F G H I J K

1356 raise ValueError( 2Rb

1357 f"Buffer size is too small for the layout. " 2Rb

1358 f"Expected at least {layout.get_required_size_in_bytes()} bytes, " 2Rb

1359 f"got {buffer.size} bytes." 2Rb

1360 ) 

1361 # set the public attributes 

1362 view.ptr = get_data_ptr(buffer, layout) 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1363 view.device_id = buffer.device_id 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1364 view.is_device_accessible = buffer.is_device_accessible 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1365 view.readonly = is_readonly 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1366 view.exporting_obj = view._buffer = buffer 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1367 # no dlpack/cai metadata 

1368 view.dl_tensor = NULL 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1369 view.metadata = None 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1370 # we get the layout from the caller 

1371 view._layout = layout 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1372 view._dtype = dtype 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K

1373 return 0 2NbObB C A gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbebfbPbS # L F G H I J K