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

712 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-07-29 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  

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 Any # no-cython-lint # used in string annotations below 

20  

21import numpy 

22  

23from cuda.bindings cimport cydriver 

24from cuda.core._resource_handles cimport ( 

25 EventHandle, 

26 create_event_handle_noctx, 

27 as_cu, 

28) 

29  

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

31from cuda.core._utils.cuda_utils cimport HANDLE_RETURN 

32  

33  

34from cuda.core._memory import Buffer 

35  

36  

37# --------------------------------------------------------------------------- 

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

39# --------------------------------------------------------------------------- 

40  

41cdef object _tensor_bridge = None 

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

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

44cdef dict _torch_type_cache = {} 

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

46cdef object _torch_version_ok = None 

47  

48cdef inline bint _torch_version_check(): 

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

50  

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

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

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

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

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

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

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

58 after verifying a new PyTorch release. 

59 """ 

60 global _torch_version_ok 

61 if _torch_version_ok is not None: 

62 return <bint>_torch_version_ok 

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

64 if torch is None: 

65 _torch_version_ok = False 

66 return False 

67 try: 

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

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

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

71 except (ValueError, IndexError): 

72 _torch_version_ok = False 

73 return <bint>_torch_version_ok 

74  

75  

76cdef inline bint _is_torch_tensor(object obj): 

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

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

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

80 return <bint>cached 2! X R L M N O P S T U V W z A y $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a

81 cdef str mod = tp.__module__ or "" 24 5 Y x / Kbab7 b h a Ob

82 cdef bint result = mod.startswith("torch") and hasattr(obj, "data_ptr") \ 24 5 Y x / Kbab7 b h a Ob

83 and _torch_version_check() 

84 _torch_type_cache[tp] = result # setdefault not needed for bools 24 5 Y x / Kbab7 b h a Ob

85 return result 24 5 Y x / Kbab7 b h a Ob

86  

87  

88cdef object _get_tensor_bridge(): 

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

90 global _tensor_bridge 

91 if _tensor_bridge is not None: 

92 return _tensor_bridge 

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

94 if torch_C is None: 

95 raise RuntimeError( 

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

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

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

99 from cuda.core import _tensor_bridge as tb 

100 _tensor_bridge = tb 

101 return _tensor_bridge 

102  

103  

104try: 

105 from ml_dtypes import bfloat16 

106except ImportError: 

107 bfloat16 = None 

108  

109# TODO(leofang): support NumPy structured dtypes 

110  

111  

112cdef extern from "Python.h": 

113 ctypedef struct PyTypeObject: 

114 void* tp_dict 

115 void PyType_Modified(PyTypeObject*) 

116  

117  

118cdef DLPackExchangeAPI _SMV_DLPACK_EXCHANGE_API 

119cdef bint _SMV_DLPACK_EXCHANGE_API_INITED = False 

120_SMV_DLPACK_EXCHANGE_API_CAPSULE = cpython.PyCapsule_New( 

121 <void*>&_SMV_DLPACK_EXCHANGE_API, 

122 b"dlpack_exchange_api", 

123 NULL, 

124) 

125  

126  

127cdef class StridedMemoryView: 

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

129  

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

131  

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

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

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

135 :meth:`from_buffer` classmethod) 

136  

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

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

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

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

141 supported. 

142  

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

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

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

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

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

148  

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

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

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

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

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

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

155  

156 Parameters 

157 ---------- 

158 obj : Any 

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

160 Interface (v3). 

161 stream_ptr: int 

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

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

164  

165  

166 Attributes 

167 ----------- 

168 ptr : int 

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

170 device_id : int 

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

172 (meaning those only accessible from the host). 

173 is_device_accessible : bool 

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

175 readonly: bool 

176 Whether the tensor data can be modified in place. 

177 exporting_obj : Any 

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

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

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

181  

182 """ 

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

184 cdef str clsname = self.__class__.__name__ 2Z 0 1 2 3 Qbbb

185 if obj is not None: 2B Z 0 1 2 3 Qbbb

186 # populate self's attributes 

187 if check_has_dlpack(obj): 2Z 0 1 2 3 bb

188 warnings.warn( 1Z0123

189 f"Constructing a {clsname} directly from a DLPack-supporting object is deprecated; " 1Z0123

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

191 DeprecationWarning, 1Z0123

192 stacklevel=2, 

193 ) 

194 view_as_dlpack(obj, stream_ptr, self) 1BZ0123

195 else: 

196 warnings.warn( 2bb

197 f"Constructing a {clsname} directly from a CUDA-array-interface-supporting object is deprecated; " 2bb

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

199 DeprecationWarning, 2bb

200 stacklevel=2, 

201 ) 

202 view_as_cai(obj, stream_ptr, self) 2bb

203 else: 

204 warnings.warn( 2Qb

205 f"Constructing an empty {clsname} is deprecated; " 2Qb

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

207 "to construct a StridedMemoryView from an object", 

208 DeprecationWarning, 2Qb

209 stacklevel=2, 

210 ) 

211  

212 @classmethod 

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

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

215  

216 Parameters 

217 ---------- 

218 obj : object 

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

220 (via ``__dlpack__``). 

221 stream_ptr : int, optional 

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

223 """ 

224 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 24 5 Y ! X R L M N O P S T U V W z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a Ob

225 if _is_torch_tensor(obj): 24 5 Y ! X R L M N O P S T U V W z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a Ob

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

227 return buf 

228 view_as_dlpack(obj, stream_ptr, buf) 24 5 Y ! X R L M N O P S T U V W z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a Ob

229 return buf 145Y!XRLMNOPSTUVWzAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

230  

231 @classmethod 

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

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

234  

235 Parameters 

236 ---------- 

237 obj : object 

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

239 stream_ptr : int, optional 

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

241 """ 

242 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2x / Kbab7

243 if _is_torch_tensor(obj): 2x / Kbab7

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

245 return buf 

246 view_as_cai(obj, stream_ptr, buf) 2B x / Kbab7

247 return buf 2x / ab7

248  

249 @classmethod 

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

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

252  

253 Parameters 

254 ---------- 

255 obj : object 

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

257 """ 

258 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2B $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

259 if _is_torch_tensor(obj): 2$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

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

261 return buf 

262 view_as_array_interface(obj, buf) 2$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

263 return buf 1B$%:';(=)*+,?@[]^_`-{|}~.

264  

265 @classmethod 

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

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

268  

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

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

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

272 regardless of which protocol is selected. 

273  

274 Parameters 

275 ---------- 

276 obj : object 

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

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

279 stream_ptr : int, optional 

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

281 """ 

282 if check_has_dlpack(obj): 24 5 Y ! X R S T U V W 1bz A y 8 9 i K 6 J C c u e f j k l q r s t m n o p g w v d b h a

283 return cls.from_dlpack(obj, stream_ptr) 145Y!XRSTUVWzAy89iK6JCcuefjklqrstmnopgwvdbha

284 return cls.from_cuda_array_interface(obj, stream_ptr) 

285  

286 @classmethod 

287 def from_buffer( 

288 cls, 

289 buffer : Buffer, 

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

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

292 *, 

293 itemsize : int | None = None, 

294 dtype : numpy.dtype | None = None, 

295 is_readonly : bool = False 

296 ) -> StridedMemoryView: 

297 """ 

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

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

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

301  

302 .. caution:: 

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

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

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

306  

307 Parameters 

308 ---------- 

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

310 The buffer to create the view from. 

311 shape : :obj:`tuple` 

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

313 the buffer. 

314 strides : :obj:`tuple` 

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

316 the buffer. 

317 dtype : :obj:`numpy.dtype` 

318 Optional dtype. 

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

320 is_readonly : bool, optional 

321 Whether the mark the view as readonly. 

322 """ 

323 cdef StridedMemoryView view = StridedMemoryView.__new__(cls) 2TbUbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbWbSbcbdbPbLbQ #

324 if itemsize is None and dtype is None: 2TbUbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbWbSbcbdbPbLbQ #

325 raise ValueError("Either itemsize or dtype must be specified") 2Wb

326 if itemsize is not None and dtype is not None and itemsize != dtype.itemsize: 2TbUbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbSbcbdbPbLbQ #

327 raise ValueError( 2Sb

328 f"itemsize ({itemsize}) does not match dtype.itemsize ({dtype.itemsize})" 2Sb

329 ) 

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

331 view_buffer_strided( 2ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbcbdbPbLbQ #

332 view, 

333 buffer, 

334 _StridedLayout(shape=shape, strides=strides, itemsize=getattr(dtype, "itemsize", itemsize)), 2TbUbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbcbdbPbLbQ #

335 dtype, 

336 is_readonly, 

337 ) 

338 return view 2B ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ #

339  

340 def __dealloc__(self) -> None: 

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

342 return 2TbUbx z A y $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . MbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbWbSbcbdbPbLb/ KbabQ Qbbb# 6 J 7 D E F G H I NbOb

343  

344 if cpython.PyCapsule_IsValid( 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICuefjklqrstmnopgwvdbha

345 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME): 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICuefjklqrstmnopgwvdbha

346 data = cpython.PyCapsule_GetPointer( 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICuefjklqrstmnopgwvdha

347 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME) 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICuefjklqrstmnopgwvdha

348 dlm_tensor_ver = <DLManagedTensorVersioned*>data 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICuefjklqrstmnopgwvdha

349 if dlm_tensor_ver.deleter != NULL: 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICuefjklqrstmnopgwvdha

350 dlm_tensor_ver.deleter(dlm_tensor_ver) 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICuefjklqrstmnopgwvda

351 elif cpython.PyCapsule_IsValid( 1Bba

352 self.metadata, DLPACK_TENSOR_USED_NAME): 1ba

353 data = cpython.PyCapsule_GetPointer( 1ba

354 self.metadata, DLPACK_TENSOR_USED_NAME) 1ba

355 dlm_tensor = <DLManagedTensor*>data 1ba

356 if dlm_tensor.deleter != NULL: 1ba

357 dlm_tensor.deleter(dlm_tensor) 1a

358  

359 def view( 

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

361 ) -> StridedMemoryView: 

362 """ 

363 Creates a new view with adjusted layout and dtype. 

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

365 """ 

366 cdef StridedMemoryView view = StridedMemoryView.__new__(self.__class__) 2z A y cbdb6 J D E F G H I

367 if layout is None and dtype is None: 2z A y cbdb6 J D E F G H I

368 return self 16

369 if layout is None: 2z A y cbdbJ D E F G H I

370 layout = self.get_layout() 1BzAyJ

371 if dtype is None: 2z A y cbdbJ D E F G H I

372 dtype = self.get_dtype() 2cbdbD E F G H I

373 view_buffer_strided(view, self.get_buffer(), layout, dtype, self.readonly) 2z A y cbdbJ D E F G H I

374 return view 2z A y cbdbJ D E F G H I

375  

376 def as_tensor_map( 

377 self, 

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

379 *, 

380 options: object = None, 

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

382 data_type: object = None, 

383 interleave: object = None, 

384 swizzle: object = None, 

385 l2_promotion: object = None, 

386 oob_fill: object = None, 

387 ) -> object: 

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

389  

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

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

392 individual keyword arguments directly, or provide bundled tiled 

393 options via ``options=``. 

394 """ 

395 from cuda.core._tensor_map import TensorMapDescriptor 1R

396  

397 kwargs = {} 1R

398 if options is not None: 1R

399 kwargs["options"] = options 

400 if element_strides is not None: 1R

401 kwargs["element_strides"] = element_strides 1BR

402 if data_type is not None: 1R

403 kwargs["data_type"] = data_type 1R

404 if interleave is not None: 1R

405 kwargs["interleave"] = interleave 

406 if swizzle is not None: 1R

407 kwargs["swizzle"] = swizzle 1R

408 if l2_promotion is not None: 1R

409 kwargs["l2_promotion"] = l2_promotion 1R

410 if oob_fill is not None: 1R

411 kwargs["oob_fill"] = oob_fill 1R

412 return TensorMapDescriptor._from_tiled(self, box_dim, **kwargs) 1R

413  

414 def copy_from( 

415 self, 

416 other: StridedMemoryView, 

417 stream: Stream, 

418 allocator: object = None, 

419 blocking: bool | None = None, 

420 ) -> None: 

421 """ 

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

423  

424 The copy can be performed between following memory spaces: 

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

426  

427 Parameters 

428 ---------- 

429 other : StridedMemoryView 

430 The view to copy data from. 

431 stream : Stream | None, optional 

432 The stream to schedule the copy on. 

433 allocator : MemoryResource | None, optional 

434 If temporary buffers are needed, the specified memory resources 

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

436 resources will be used. 

437 blocking : bool | None, optional 

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

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

440 blocking until the copy is complete. 

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

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

443 still synchronize with the host if necessary. 

444 * ``None`` (default): 

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

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

447 """ 

448 raise NotImplementedError("Sorry, not supported: copy_from") 18

449  

450 def copy_to( 

451 self, 

452 other: StridedMemoryView, 

453 stream: Stream | None = None, 

454 allocator: object = None, 

455 blocking: bool | None = None, 

456 ) -> None: 

457 """ 

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

459  

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

461 """ 

462 raise NotImplementedError("Sorry, not supported: copy_to") 19

463  

464 def __dlpack__( 

465 self, 

466 *, 

467 stream: int | None = None, 

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

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

470 copy: bool | None = None, 

471 ) -> object: 

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

473 if dl_device is not None: 1YxzAyiQuefjklqrstmnopgwvdbha

474 raise BufferError("Sorry, not supported: dl_device other than None") 1Y

475 if copy is True: 1YxzAyiQuefjklqrstmnopgwvdbha

476 raise BufferError("Sorry, not supported: copy=True") 1Y

477  

478 cdef bint versioned 

479 if max_version is None: 1YxzAyiQuefjklqrstmnopgwvdbha

480 versioned = False 1xzAyQvba

481 else: 

482 if not isinstance(max_version, tuple) or len(max_version) != 2: 1Yiuefjklqrstmnopgwdha

483 raise BufferError(f"Expected max_version tuple[int, int], got {max_version}") 1Y

484 versioned = max_version >= (1, 0) 1iuefjklqrstmnopgwdha

485  

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

487 cdef object capsule = _smv_make_py_capsule(self, versioned) 1xzAyiQuefjklqrstmnopgwvdbha

488 return capsule 1xiuefjklqrstmnopgwvdbha

489  

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

491 cdef _DLDeviceType device_type 

492 cdef int32_t device_id 

493 _smv_get_dl_device(self, &device_type, &device_id) 145xibha

494 return (<int>device_type, int(device_id)) 145xibha

495  

496 @property 

497 def _layout(self) -> _StridedLayout: 

498 """ 

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

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

501 """ 

502 return self.get_layout() 2ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbQbJ D E F G H I

503  

504 @property 

505 def size(self) -> int: 

506 return self.get_layout().get_volume() 1LMNOPSTUVWZ0123$%:';(=)*+,?@[]^_`-{|}~./

507  

508 @property 

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

510 """ 

511 Shape of the tensor. 

512 """ 

513 return self.get_layout().get_shape_tuple() 2X L M N O P S T U V W Z 0 1 2 3 $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdb/ abbb# K 7 D E F G H I c

514  

515 @property 

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

517 """ 

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

519 """ 

520 return self.get_layout().get_strides_tuple() 2X L M N O P S T U V W Z 0 1 2 3 $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJb/ ab# K

521  

522 @property 

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

524 """ 

525 Data type of the tensor. 

526  

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

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

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

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

531 """ 

532 return self.get_dtype() 2$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbLb# K J D E F G H I

533  

534 def __repr__(self) -> str: 

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

536 + f" shape={self.shape},\n" 1#K

537 + f" strides={self.strides},\n" 1#K

538 + f" itemsize={self._layout.itemsize},\n" 1#K

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

540 + f" device_id={self.device_id},\n" 1#K

541 + f" is_device_accessible={self.is_device_accessible},\n" 1B#K

542 + f" readonly={self.readonly},\n" 1#K

543 + f" exporting_obj={get_simple_repr(self.exporting_obj)})") 1#K

544  

545 @cython.critical_section 

546 cdef inline _StridedLayout get_layout(self): 

547 if self._layout is None: 2X L M N O P S T U V W Z 0 1 2 3 x z A y $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . MbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdb/ Kbabi Q Qbbb# K J 7 D E F G H I C c u e f j k l q r s t m n o p g w v d b h a

548 if self.dl_tensor: 2B X L M N O P S T U V W Z 0 1 2 3 x z A y $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb/ Kbabi QbbbK J 7 D E F G H I C c u e f j k l q r s t m n o p g w v d b h a

549 self._layout = layout_from_dlpack(self.dl_tensor) 1XLMNOPSTUVWZ0123zAyiKJDEFGHICcuefjklqrstmnopgwvdbha

550 elif self.metadata is not None: 2x $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb/ KbabQbbb7

551 self._layout = layout_from_cai(self.metadata) 2x $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb/ Kbabbb7

552 else: 

553 raise ValueError("Cannot infer layout from the exporting object") 2Qb

554 return self._layout 2X L M N O P S T U V W Z 0 1 2 3 x z A y $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdb/ abi Q bb# K J 7 D E F G H I C c u e f j k l q r s t m n o p g w v d b h a

555  

556 @cython.critical_section 

557 cdef inline object get_buffer(self): 

558 """ 

559 Returns Buffer instance with the underlying data. 

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

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

562 """ 

563 if self._buffer is None: 2x z A y cbdbJ D E F G H I

564 if isinstance(self.exporting_obj, Buffer): 1xzAyJDEFGHI

565 self._buffer = self.exporting_obj 

566 else: 

567 self._buffer = Buffer.from_handle(self.ptr, 0, owner=self.exporting_obj) 1xzAyJDEFGHI

568 return self._buffer 2x z A y cbdbJ D E F G H I

569  

570 @cython.critical_section 

571 cdef inline object get_dtype(self): 

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

573 if self.dl_tensor != NULL: 1x$%:';(=)*+,?@[]^_`-{|}~.iQ#KDEFGHICcuefjklqrstmnopgwvdbha

574 self._dtype = dtype_dlpack_to_numpy(&self.dl_tensor.dtype) 1iKDEFGHICcuefjklqrstmnopgwvdbha

575 elif isinstance(self.metadata, int): 1x$%:';(=)*+,?@[]^_`-{|}~.Q#

576 # AOTI dtype code stored by the torch tensor bridge 

577 self._dtype = _get_tensor_bridge().resolve_aoti_dtype( 

578 self.metadata) 

579 elif self.metadata is not None: 1x$%:';(=)*+,?@[]^_`-{|}~.Q#

580 self._dtype = _typestr2dtype(self.metadata["typestr"]) 1x$%:';(=)*+,?@[]^_`-{|}~.

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

582  

583  

584cdef void _smv_pycapsule_deleter(object capsule) noexcept: 

585 cdef DLManagedTensor* dlm_tensor 

586 cdef DLManagedTensorVersioned* dlm_tensor_ver 

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

588 if cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME): 1xiuefjklqrstmnopgwvda

589 dlm_tensor = <DLManagedTensor*>( 1xv

590 cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME) 1xv

591 ) 

592 if dlm_tensor.deleter: 1xv

593 dlm_tensor.deleter(dlm_tensor) 1xv

594 elif cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 1iuefjklqrstmnopgwda

595 dlm_tensor_ver = <DLManagedTensorVersioned*>( 1Bd

596 cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 1d

597 ) 

598 if dlm_tensor_ver.deleter: 1d

599 dlm_tensor_ver.deleter(dlm_tensor_ver) 1d

600  

601  

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

603 if shape_ptr: 1xzAyiQuefjklqrstmnopgwvdbha

604 stdlib.free(shape_ptr) 1xiuefjklqrstmnopgvdbha

605 if manager_ctx: 1xzAyiQuefjklqrstmnopgwvdbha

606 cpython.Py_DECREF(<object>manager_ctx) 1xzAyiQuefjklqrstmnopgwvdbha

607  

608  

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

610 if tensor: 1xzAyQvba

611 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1xzAyQvba

612 tensor.manager_ctx = NULL 1xzAyQvba

613 stdlib.free(tensor) 1BxzAyQvba

614  

615  

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

617 if tensor: 1zAyiQuefjklqrstmnopgwdha

618 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1iuefjklqrstmnopgwdha

619 tensor.manager_ctx = NULL 1iuefjklqrstmnopgwdha

620 stdlib.free(tensor) 1iuefjklqrstmnopgwdha

621  

622  

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

624 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1icuefjklqrstmnopgwdha

625 dlm_tensor_ver = <DLManagedTensorVersioned*>stdlib.malloc(sizeof(DLManagedTensorVersioned)) 1icuefjklqrstmnopgwdha

626 if dlm_tensor_ver == NULL: 1icuefjklqrstmnopgwdha

627 raise MemoryError() 

628 dlm_tensor_ver.dl_tensor.shape = NULL 1icuefjklqrstmnopgwdha

629 dlm_tensor_ver.manager_ctx = NULL 1icuefjklqrstmnopgwdha

630 return dlm_tensor_ver 1icuefjklqrstmnopgwdha

631  

632  

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

634 cdef DLManagedTensor* dlm_tensor = NULL 1xzAyQvba

635 dlm_tensor = <DLManagedTensor*>stdlib.malloc(sizeof(DLManagedTensor)) 1xzAyQvba

636 if dlm_tensor == NULL: 1xzAyQvba

637 raise MemoryError() 

638 dlm_tensor.dl_tensor.shape = NULL 1xzAyQvba

639 dlm_tensor.manager_ctx = NULL 1xzAyQvba

640 return dlm_tensor 1BxzAyQvba

641  

642  

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

644 cdef object np_dtype = numpy.dtype(dtype_obj) 1xzAyiCcuefjklqrstmnopgwvdbha

645 if np_dtype.fields is not None: 1xzAyiCcuefjklqrstmnopgwvdbha

646 raise BufferError("Structured dtypes are not supported for DLPack export") 1A

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

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

649  

650 cdef str kind = np_dtype.kind 1xyiCcuefjklqrstmnopgwvdbha

651 cdef int bits = np_dtype.itemsize * 8 1xyiCcuefjklqrstmnopgwvdbha

652 cdef uint8_t code 

653 if kind == "b": 1xyiCcuefjklqrstmnopgwvdbha

654 if bits != 8: 1u

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

656 code = <uint8_t>kDLBool 1u

657 elif kind == "i": 1xyiCcefjklqrstmnopgwvdbha

658 if bits not in (8, 16, 32, 64): 1iCqrstvdbha

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

660 code = <uint8_t>kDLInt 1iCqrstvdbha

661 elif kind == "u": 1xycefjklmnopgw

662 if bits not in (8, 16, 32, 64): 1mnop

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

664 code = <uint8_t>kDLUInt 1mnop

665 elif kind == "f": 1xycefjklgw

666 if bits not in (16, 32, 64): 1xcjkl

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

668 code = <uint8_t>kDLFloat 1Bxcjkl

669 elif kind == "c": 1yefgw

670 if bits not in (64, 128): 1efgw

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

672 code = <uint8_t>kDLComplex 1efgw

673 else: 

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

675  

676 out_dtype.code = code 1xiCcuefjklqrstmnopgwvdbha

677 out_dtype.bits = <uint8_t>bits 1xiCcuefjklqrstmnopgwvdbha

678 out_dtype.lanes = <uint16_t>1 1BxiCcuefjklqrstmnopgwvdbha

679 return 0 1xiCcuefjklqrstmnopgwvdbha

680  

681  

682cdef inline int _smv_get_dl_device( 

683 StridedMemoryView view, 

684 _DLDeviceType* out_device_type, 

685 int32_t* out_device_id, 

686) except -1: 

687 cdef _DLDeviceType device_type 

688 cdef int32_t device_id 

689 cdef object buf 

690 if view.dl_tensor != NULL: 145xiCcuefjklqrstmnopgwvdbha

691 device_type = view.dl_tensor.device.device_type 145iCcuefjklqrstmnopgwvdbha

692 if device_type == _kDLCUDA: 145iCcuefjklqrstmnopgwvdbha

693 device_id = view.dl_tensor.device.device_id 

694 else: 

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

696 device_id = 0 145iCcuefjklqrstmnopgwvdbha

697 elif view.is_device_accessible: 1x

698 buf = view.get_buffer() 1x

699 dev_type, dev_id = classify_dl_device(buf) 1x

700 device_type = <_DLDeviceType>dev_type 1x

701 device_id = <int32_t>dev_id 1x

702 else: 

703 device_type = _kDLCPU 

704 device_id = 0 

705  

706 out_device_type[0] = device_type 145xiCcuefjklqrstmnopgwvdbha

707 out_device_id[0] = device_id 145xiCcuefjklqrstmnopgwvdbha

708 return 0 145xiCcuefjklqrstmnopgwvdbha

709  

710  

711cdef inline int _smv_setup_dl_tensor_common( 

712 DLTensor* dl_tensor, 

713 StridedMemoryView view, 

714 _StridedLayout layout, 

715) except -1: 

716 cdef object dtype_obj = view.get_dtype() 1xzAyiQCcuefjklqrstmnopgwvdbha

717 if dtype_obj is None: 1xzAyiQCcuefjklqrstmnopgwvdbha

718 raise BufferError( 1Q

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

720 "create the view with dtype specified." 

721 ) 

722 _smv_dtype_numpy_to_dlpack(dtype_obj, &dl_tensor.dtype) 1xzAyiCcuefjklqrstmnopgwvdbha

723 _smv_get_dl_device(view, &dl_tensor.device.device_type, &dl_tensor.device.device_id) 1xiCcuefjklqrstmnopgwvdbha

724  

725 cdef int ndim = layout.base.ndim 1xiCcuefjklqrstmnopgwvdbha

726 dl_tensor.ndim = ndim 1xiCcuefjklqrstmnopgwvdbha

727 if layout.get_volume() == 0: 1xiCcuefjklqrstmnopgwvdbha

728 dl_tensor.data = NULL 1g

729 else: 

730 dl_tensor.data = <void*><intptr_t>view.ptr 1xiCcuefjklqrstmnopwvdbha

731 dl_tensor.byte_offset = 0 1xiCcuefjklqrstmnopgwvdbha

732 return 0 1xiCcuefjklqrstmnopgwvdbha

733  

734  

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

736 cdef _StridedLayout layout = view.get_layout() 1xzAyiQcuefjklqrstmnopgwvdbha

737 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1xzAyiQcuefjklqrstmnopgwvdbha

738  

739 cdef int i 

740 cdef int64_t* shape_strides = NULL 1xicuefjklqrstmnopgwvdbha

741 cdef int64_t* strides_src = NULL 1xicuefjklqrstmnopgwvdbha

742 cdef int ndim = dl_tensor.ndim 1xicuefjklqrstmnopgwvdbha

743 if ndim == 0: 1xicuefjklqrstmnopgwvdbha

744 dl_tensor.shape = NULL 1w

745 dl_tensor.strides = NULL 1w

746 else: 

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

748 shape_strides = <int64_t*>stdlib.malloc(sizeof(int64_t) * 2 * ndim) 1xicuefjklqrstmnopgvdbha

749 if shape_strides == NULL: 1xicuefjklqrstmnopgvdbha

750 raise MemoryError() 

751 try: 1xicuefjklqrstmnopgvdbha

752 strides_src = get_strides_ptr(layout.base) 1xicuefjklqrstmnopgvdbha

753 for i in range(ndim): 1xicuefjklqrstmnopgvdbha

754 shape_strides[i] = layout.base.shape[i] 1xicuefjklqrstmnopgvdbha

755 shape_strides[i + ndim] = strides_src[i] 1xicuefjklqrstmnopgvdbha

756 except Exception: 

757 stdlib.free(shape_strides) 

758 raise 

759 dl_tensor.shape = shape_strides 1xicuefjklqrstmnopgvdbha

760 dl_tensor.strides = shape_strides + ndim 1xicuefjklqrstmnopgvdbha

761 return 0 1xicuefjklqrstmnopgwvdbha

762  

763  

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

765 cdef _StridedLayout layout = view.get_layout() 1C

766 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1C

767  

768 if dl_tensor.ndim == 0: 1C

769 dl_tensor.shape = NULL 

770 dl_tensor.strides = NULL 

771 else: 

772 dl_tensor.shape = layout.base.shape 1C

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

774 dl_tensor.strides = get_strides_ptr(layout.base) 1C

775 return 0 1C

776  

777  

778cdef inline int _smv_fill_managed_tensor_versioned( 

779 DLManagedTensorVersioned* dlm_tensor_ver, 

780 StridedMemoryView view, 

781) except -1: 

782 cpython.Py_INCREF(view) 1icuefjklqrstmnopgwdha

783 dlm_tensor_ver.manager_ctx = <void*>view 1icuefjklqrstmnopgwdha

784 dlm_tensor_ver.deleter = _smv_versioned_deleter 1icuefjklqrstmnopgwdha

785 dlm_tensor_ver.version.major = DLPACK_MAJOR_VERSION 1icuefjklqrstmnopgwdha

786 dlm_tensor_ver.version.minor = DLPACK_MINOR_VERSION 1icuefjklqrstmnopgwdha

787 dlm_tensor_ver.flags = DLPACK_FLAG_BITMASK_READ_ONLY if view.readonly else 0 1icuefjklqrstmnopgwdha

788 _smv_setup_dl_tensor(&dlm_tensor_ver.dl_tensor, view) 1icuefjklqrstmnopgwdha

789 return 0 1icuefjklqrstmnopgwdha

790  

791  

792cdef inline int _smv_fill_managed_tensor( 

793 DLManagedTensor* dlm_tensor, 

794 StridedMemoryView view, 

795) except -1: 

796 cpython.Py_INCREF(view) 1xzAyQvba

797 dlm_tensor.manager_ctx = <void*>view 1xzAyQvba

798 dlm_tensor.deleter = _smv_deleter 1xzAyQvba

799 _smv_setup_dl_tensor(&dlm_tensor.dl_tensor, view) 1xzAyQvba

800 return 0 1xvba

801  

802  

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

804 cdef DLManagedTensor* dlm_tensor = NULL 1xzAyiQuefjklqrstmnopgwvdbha

805 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1xzAyiQuefjklqrstmnopgwvdbha

806 cdef object capsule = None 1xzAyiQuefjklqrstmnopgwvdbha

807 cdef void* tensor_ptr = NULL 1xzAyiQuefjklqrstmnopgwvdbha

808 cdef const char* capsule_name 

809 try: 1xzAyiQuefjklqrstmnopgwvdbha

810 if versioned: 1xzAyiQuefjklqrstmnopgwvdbha

811 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1iuefjklqrstmnopgwdha

812 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, view) 1iuefjklqrstmnopgwdha

813 tensor_ptr = <void*>dlm_tensor_ver 1iuefjklqrstmnopgwdha

814 capsule_name = DLPACK_VERSIONED_TENSOR_UNUSED_NAME 1iuefjklqrstmnopgwdha

815 else: 

816 dlm_tensor = _smv_allocate_dlm_tensor() 1xzAyQvba

817 _smv_fill_managed_tensor(dlm_tensor, view) 1xzAyQvba

818 tensor_ptr = <void*>dlm_tensor 1xvba

819 capsule_name = DLPACK_TENSOR_UNUSED_NAME 1xvba

820 capsule = cpython.PyCapsule_New(tensor_ptr, capsule_name, _smv_pycapsule_deleter) 1xiuefjklqrstmnopgwvdbha

821 except Exception: 1zAyQ

822 if capsule is None: 1zAyQ

823 _smv_deleter(dlm_tensor) 1zAyQ

824 _smv_versioned_deleter(dlm_tensor_ver) 1zAyQ

825 raise 1zAyQ

826 return capsule 1xiuefjklqrstmnopgwvdbha

827  

828  

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

830 cdef void* data = NULL 1c

831 cdef DLTensor* dl_tensor = NULL 1c

832 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1c

833 cdef DLManagedTensor* dlm_tensor = NULL 1c

834 cdef bint is_readonly = False 1c

835 cdef const char* used_name = NULL 1c

836 if cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 1c

837 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 1c

838 dlm_tensor_ver = <DLManagedTensorVersioned*>data 1c

839 dl_tensor = &dlm_tensor_ver.dl_tensor 1c

840 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 1c

841 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 1c

842 elif cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME): 

843 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME) 

844 dlm_tensor = <DLManagedTensor*>data 

845 dl_tensor = &dlm_tensor.dl_tensor 

846 is_readonly = False 

847 used_name = DLPACK_TENSOR_USED_NAME 

848 else: 

849 raise BufferError("Invalid DLPack capsule") 

850  

851 cpython.PyCapsule_SetName(capsule, used_name) 1c

852  

853 cdef StridedMemoryView view = StridedMemoryView.__new__(StridedMemoryView) 1c

854 view.dl_tensor = dl_tensor 1c

855 view.metadata = capsule 1c

856 view.ptr = <intptr_t>(dl_tensor.data) + <intptr_t>(dl_tensor.byte_offset) 1c

857 view.readonly = is_readonly 1c

858 view.exporting_obj = exporting_obj 1c

859 if dl_tensor.device.device_type == _kDLCPU: 1c

860 view.device_id = -1 1c

861 view.is_device_accessible = False 1c

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

863 view.device_id = dl_tensor.device.device_id 

864 view.is_device_accessible = True 

865 else: 

866 raise BufferError("device not supported") 

867 return view 1c

868  

869  

870cdef int _smv_managed_tensor_allocator( 

871 DLTensor* prototype, 

872 DLManagedTensorVersioned** out, 

873 void* error_ctx, 

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

875) noexcept with gil: 

876 if out != NULL: 2Xb

877 out[0] = NULL 2Xb

878 if SetError != NULL: 2Xb

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

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

881 return -1 2Xb

882  

883  

884cdef int _smv_managed_tensor_from_py_object_no_sync( 

885 void* py_object, 

886 DLManagedTensorVersioned** out, 

887) noexcept with gil: 

888 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1c

889 if out == NULL: 1c

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

891 return -1 

892 out[0] = NULL 1c

893 cdef object obj = <object>py_object 1c

894 if not isinstance(obj, StridedMemoryView): 1c

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

896 return -1 

897 try: 1c

898 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1c

899 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, <StridedMemoryView>obj) 1c

900 except Exception: 

901 _smv_versioned_deleter(dlm_tensor_ver) 

902 return -1 

903 out[0] = dlm_tensor_ver 1c

904 return 0 1c

905  

906  

907cdef int _smv_managed_tensor_to_py_object_no_sync( 

908 DLManagedTensorVersioned* tensor, 

909 void** out_py_object, 

910) noexcept with gil: 

911 cdef object capsule 

912 cdef object py_view 

913 if out_py_object == NULL: 2c Yb

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

915 return -1 

916 out_py_object[0] = NULL 2c Yb

917 if tensor == NULL: 2c Yb

918 cpython.PyErr_SetString(RuntimeError, b"tensor cannot be NULL") 2Yb

919 return -1 2Yb

920 try: 1c

921 capsule = cpython.PyCapsule_New( 1c

922 <void*>tensor, 

923 DLPACK_VERSIONED_TENSOR_UNUSED_NAME, 

924 _smv_pycapsule_deleter, 

925 ) 

926 py_view = _smv_from_dlpack_capsule(capsule, capsule) 1c

927 cpython.Py_INCREF(py_view) 1c

928 out_py_object[0] = <void*>py_view 1c

929 except Exception: 

930 return -1 

931 return 0 1c

932  

933  

934cdef int _smv_dltensor_from_py_object_no_sync( 

935 void* py_object, 

936 DLTensor* out, 

937) noexcept with gil: 

938 if out == NULL: 2ZbC

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

940 return -1 

941 cdef object obj = <object>py_object 2ZbC

942 if not isinstance(obj, StridedMemoryView): 2ZbC

943 cpython.PyErr_SetString(TypeError, b"py_object must be a StridedMemoryView") 2Zb

944 return -1 2Zb

945 try: 1C

946 _smv_setup_dltensor_borrowed(out, <StridedMemoryView>obj) 1C

947 except Exception: 

948 return -1 

949 return 0 1C

950  

951  

952cdef int _smv_current_work_stream( 

953 _DLDeviceType device_type, 

954 int32_t device_id, 

955 void** out_current_stream, 

956) noexcept with gil: 

957 if out_current_stream == NULL: 24b

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

959 return -1 

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

961 out_current_stream[0] = NULL 24b

962 return 0 24b

963  

964  

965cdef void _init_smv_dlpack_exchange_api(): 

966 global _SMV_DLPACK_EXCHANGE_API_INITED 

967 if _SMV_DLPACK_EXCHANGE_API_INITED: 

968 return 

969 _SMV_DLPACK_EXCHANGE_API.header.version.major = DLPACK_MAJOR_VERSION 

970 _SMV_DLPACK_EXCHANGE_API.header.version.minor = DLPACK_MINOR_VERSION 

971 _SMV_DLPACK_EXCHANGE_API.header.prev_api = NULL 

972 _SMV_DLPACK_EXCHANGE_API.managed_tensor_allocator = _smv_managed_tensor_allocator 

973 _SMV_DLPACK_EXCHANGE_API.managed_tensor_from_py_object_no_sync = _smv_managed_tensor_from_py_object_no_sync 

974 _SMV_DLPACK_EXCHANGE_API.managed_tensor_to_py_object_no_sync = _smv_managed_tensor_to_py_object_no_sync 

975 _SMV_DLPACK_EXCHANGE_API.dltensor_from_py_object_no_sync = _smv_dltensor_from_py_object_no_sync 

976 _SMV_DLPACK_EXCHANGE_API.current_work_stream = _smv_current_work_stream 

977 _SMV_DLPACK_EXCHANGE_API_INITED = True 

978  

979  

980_init_smv_dlpack_exchange_api() 

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

982# directly into the type dict. 

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

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

985PyType_Modified(<PyTypeObject*>StridedMemoryView) 

986  

987  

988cdef str get_simple_repr(obj): 

989 # TODO: better handling in np.dtype objects 

990 cdef object obj_class 

991 cdef str obj_repr 

992 if isinstance(obj, type): 1#K

993 obj_class = obj 

994 else: 

995 obj_class = obj.__class__ 1#K

996 if obj_class.__module__ in (None, "builtins"): 1#K

997 obj_repr = obj_class.__name__ 1#

998 else: 

999 obj_repr = f"{obj_class.__module__}.{obj_class.__name__}" 1#K

1000 return obj_repr 1#K

1001  

1002  

1003  

1004cdef bint check_has_dlpack(obj) except*: 

1005 cdef bint has_dlpack 

1006 if hasattr(obj, "__dlpack__") and hasattr(obj, "__dlpack_device__"): 24 5 Y ! X R L M N O P S T U V W Z 0 1 2 3 1bz A y 8 9 i bbVbK 6 J C c u e f j k l q r s t m n o p g w v d b h a

1007 has_dlpack = True 145Y!XRLMNOPSTUVWZ0123zAy89iK6JCcuefjklqrstmnopgwvdbha

1008 elif hasattr(obj, "__cuda_array_interface__"): 21bbbVb

1009 has_dlpack = False 2bbVb

1010 else: 

1011 raise BufferError( 21b

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

1013 return has_dlpack 24 5 Y ! X R L M N O P S T U V W Z 0 1 2 3 z A y 8 9 i bbVbK 6 J C c u e f j k l q r s t m n o p g w v d b h a

1014  

1015  

1016cdef class _StridedMemoryViewProxy: 

1017 cdef readonly: 

1018 object obj 

1019 bint has_dlpack 

1020  

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

1022 self.obj = obj 2L M N O P Vb

1023 self.has_dlpack = check_has_dlpack(obj) 2L M N O P Vb

1024  

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

1026 if self.has_dlpack: 1LMNOP

1027 return StridedMemoryView.from_dlpack(self.obj, stream_ptr) 1LMNOP

1028 else: 

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

1030  

1031  

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

1033 cdef int dldevice, device_id 

1034 cdef bint is_device_accessible, is_readonly 

1035 is_device_accessible = False 24 5 Y ! X R L M N O P S T U V W Z 0 1 2 3 z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a Ob

1036 dldevice, device_id = obj.__dlpack_device__() 24 5 Y ! X R L M N O P S T U V W Z 0 1 2 3 z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a Ob

1037 if dldevice == _kDLCPU: 24 5 Y ! X R L M N O P S T U V W Z 0 1 2 3 z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a Ob

1038 assert device_id == 0 2Y ! X R L M N O P S T U V W Z 0 1 2 3 z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a

1039 device_id = -1 2Y ! X R L M N O P S T U V W Z 0 1 2 3 z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a

1040 if stream_ptr is None: 2Y ! X R L M N O P S T U V W Z 0 1 2 3 z A y 8 9 i K 6 J D E F G H I C c u e f j k l q r s t m n o p g w v d Nbb h a

1041 raise BufferError("stream=None is ambiguous with view()") 2Nb

1042 elif stream_ptr == -1: 1Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1043 stream_ptr = None 1Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1044 elif dldevice == _kDLCUDA: 

1045 assert device_id >= 0 

1046 is_device_accessible = True 

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

1048 if stream_ptr is None: 

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

1050 elif dldevice in (_kDLCUDAHost, _kDLCUDAManaged): 

1051 is_device_accessible = True 145

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

1053 # accessed on both host and device 

1054 else: 

1055 raise BufferError("device not supported") 2Ob

1056  

1057 cdef object capsule 

1058 try: 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1059 capsule = obj.__dlpack__( 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1060 stream=int(stream_ptr) if stream_ptr else None, 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1061 max_version=(DLPACK_MAJOR_VERSION, DLPACK_MINOR_VERSION)) 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1062 except TypeError: 1ba

1063 capsule = obj.__dlpack__( 1ba

1064 stream=int(stream_ptr) if stream_ptr else None) 1ba

1065  

1066 cdef void* data = NULL 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1067 cdef DLTensor* dl_tensor 

1068 cdef DLManagedTensorVersioned* dlm_tensor_ver 

1069 cdef DLManagedTensor* dlm_tensor 

1070 cdef const char *used_name 

1071 if cpython.PyCapsule_IsValid( 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1072 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 

1073 data = cpython.PyCapsule_GetPointer( 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1074 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 

1075 dlm_tensor_ver = <DLManagedTensorVersioned*>data 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1076 dl_tensor = &dlm_tensor_ver.dl_tensor 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1077 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1078 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1079 elif cpython.PyCapsule_IsValid( 1ba

1080 capsule, DLPACK_TENSOR_UNUSED_NAME): 

1081 data = cpython.PyCapsule_GetPointer( 1ba

1082 capsule, DLPACK_TENSOR_UNUSED_NAME) 

1083 dlm_tensor = <DLManagedTensor*>data 1ba

1084 dl_tensor = &dlm_tensor.dl_tensor 1ba

1085 is_readonly = False 1ba

1086 used_name = DLPACK_TENSOR_USED_NAME 1ba

1087 else: 

1088 assert False 

1089  

1090 cpython.PyCapsule_SetName(capsule, used_name) 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1091  

1092 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1093 buf.dl_tensor = dl_tensor 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1094 buf.metadata = capsule 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1095 buf.ptr = <intptr_t>(dl_tensor.data) 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1096 buf.device_id = device_id 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1097 buf.is_device_accessible = is_device_accessible 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1098 buf.readonly = is_readonly 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1099 buf.exporting_obj = obj 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1100  

1101 return buf 145Y!XRLMNOPSTUVWZ0123zAy89iK6JDEFGHICcuefjklqrstmnopgwvdbha

1102  

1103  

1104@functools.lru_cache 

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

1106 return numpy.dtype(typestr) 1$%'()*+,-./

1107  

1108  

1109@functools.lru_cache 

1110def _typestr2itemsize(str typestr) -> int: 

1111 return _typestr2dtype(typestr).itemsize 1$%'()*+,-./

1112  

1113  

1114cdef object dtype_dlpack_to_numpy(DLDataType* dtype): 

1115 cdef int bits = dtype.bits 1iKDEFGHICcuefjklqrstmnopgwvdbha

1116 if dtype.lanes != 1: 1iKDEFGHICcuefjklqrstmnopgwvdbha

1117 # TODO: return a NumPy structured dtype? 

1118 raise NotImplementedError( 

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

1120 if dtype.code == kDLUInt: 1iKDEFGHICcuefjklqrstmnopgwvdbha

1121 if bits == 8: 1mnop

1122 np_dtype = numpy.uint8 1m

1123 elif bits == 16: 

1124 np_dtype = numpy.uint16 1n

1125 elif bits == 32: 

1126 np_dtype = numpy.uint32 1o

1127 elif bits == 64: 

1128 np_dtype = numpy.uint64 1p

1129 else: 

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

1131 elif dtype.code == kDLInt: 

1132 if bits == 8: 1iKDEFGHICqrstvdbha

1133 np_dtype = numpy.int8 1q

1134 elif bits == 16: 

1135 np_dtype = numpy.int16 1r

1136 elif bits == 32: 

1137 np_dtype = numpy.int32 1iKDEFGHICsvdbha

1138 elif bits == 64: 

1139 np_dtype = numpy.int64 1t

1140 else: 

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

1142 elif dtype.code == kDLFloat: 

1143 if bits == 16: 1cjkl

1144 np_dtype = numpy.float16 1j

1145 elif bits == 32: 

1146 np_dtype = numpy.float32 1k

1147 elif bits == 64: 

1148 np_dtype = numpy.float64 1cl

1149 else: 

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

1151 elif dtype.code == kDLComplex: 

1152 # TODO(leofang): support complex32 

1153 if bits == 64: 1efgw

1154 np_dtype = numpy.complex64 1e

1155 elif bits == 128: 

1156 np_dtype = numpy.complex128 1fgw

1157 else: 

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

1159 elif dtype.code == kDLBool: 

1160 if bits == 8: 1u

1161 np_dtype = numpy.bool_ 1u

1162 else: 

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

1164 elif dtype.code == kDLBfloat: 

1165 if bfloat16 is not None: 

1166 np_dtype = numpy.dtype("bfloat16") 

1167 else: 

1168 raise NotImplementedError( 

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

1170 'to be installed.' 

1171 ) 

1172 else: 

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

1174  

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

1176 return numpy.dtype(np_dtype) 1iKDEFGHICcuefjklqrstmnopgwvdbha

1177  

1178  

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

1180 cdef dict cai_data = obj.__cuda_array_interface__ 22b0b5b6bx / Kbabbb7

1181 if cai_data.get("version", 0) < 3: 22b0b5b6bx / Kbabbb7

1182 raise BufferError("only CUDA Array Interface v3 or above is supported") 25b6b

1183 if cai_data.get("mask") is not None: 22b0bx / Kbabbb7

1184 raise BufferError("mask is not supported") 22b

1185 if stream_ptr is None: 20bx / Kbabbb7

1186 raise BufferError("stream=None is ambiguous with view()") 20b

1187  

1188 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2x / Kbabbb7

1189 buf.exporting_obj = obj 2x / Kbabbb7

1190 buf.metadata = cai_data 2x / Kbabbb7

1191 buf.dl_tensor = NULL 2x / Kbabbb7

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

1193 buf.get_layout() 2x / Kbabbb7

1194 buf.ptr, buf.readonly = cai_data["data"] 2x / abbb7

1195 buf.is_device_accessible = True 2x / abbb7

1196 if buf.ptr != 0: 2x / abbb7

1197 buf.device_id = handle_return( 1x7

1198 driver.cuPointerGetAttribute( 1x7

1199 driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL, 1x7

1200 buf.ptr)) 1x7

1201 else: 

1202 buf.device_id = handle_return(driver.cuCtxGetDevice()) 2/ abbb

1203  

1204 cdef intptr_t producer_s, consumer_s 

1205 cdef EventHandle h_event 

1206 stream_ptr = int(stream_ptr) 2x / abbb7

1207 if stream_ptr != -1: 2x / abbb7

1208 stream = cai_data.get("stream") 17

1209 if stream is not None: 17

1210 producer_s = <intptr_t>(stream) 17

1211 consumer_s = <intptr_t>(stream_ptr) 17

1212 assert producer_s > 0 17

1213 # establish stream order 

1214 if producer_s != consumer_s: 17

1215 with nogil: 17

1216 h_event = create_event_handle_noctx(cydriver.CUevent_flags.CU_EVENT_DISABLE_TIMING) 17

1217 HANDLE_RETURN(cydriver.cuEventRecord( 17

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

1219 HANDLE_RETURN(cydriver.cuStreamWaitEvent( 17

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

1221 elif _is_torch_tensor(obj): 

1222 # PyTorch's __cuda_array_interface__ reports version 2 and 

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

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

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

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

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

1228 # event-based stream ordering. 

1229 _get_tensor_bridge().sync_torch_stream( 

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

1231  

1232 return buf 2x / abbb7

1233  

1234  

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

1236 cdef dict data = obj.__array_interface__ 23b7b8b$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

1237 if data.get("version", 0) < 3: 23b7b8b$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

1238 raise BufferError("only NumPy Array Interface v3 or above is supported") 27b8b

1239 if data.get("mask") is not None: 23b$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

1240 raise BufferError("mask is not supported") 23b

1241  

1242 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

1243 buf.exporting_obj = obj 2$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

1244 buf.metadata = data 2$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

1245 buf.dl_tensor = NULL 2$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

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

1247 buf.get_layout() 2$ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb

1248 buf.ptr, buf.readonly = data["data"] 1$%:';(=)*+,?@[]^_`-{|}~.

1249 buf.is_device_accessible = False 1$%:';(=)*+,?@[]^_`-{|}~.

1250 buf.device_id = handle_return(driver.cuCtxGetDevice()) 1$%:';(=)*+,?@[]^_`-{|}~.

1251 return buf 1$%:';(=)*+,?@[]^_`-{|}~.

1252  

1253  

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

1255 """ 

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

1257 specified positional arguments. 

1258  

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

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

1261 desired). 

1262  

1263 Inside the decorated function, the specified arguments become instances 

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

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

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

1267 example: 

1268  

1269 .. code-block:: python 

1270  

1271 @args_viewable_as_strided_memory((1,)) 

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

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

1274 view = arg1.view(stream.handle) 

1275 assert isinstance(view, StridedMemoryView) 

1276 ... 

1277  

1278 Parameters 

1279 ---------- 

1280 arg_indices : tuple 

1281 The indices of the target positional arguments. 

1282 """ 

1283 def wrapped_func_with_indices(func: "Callable") -> "Callable": 1LMNOP

1284 @functools.wraps(func) 1LMNOP

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

1286 args = list(args) 1LMNOP

1287 cdef int idx 

1288 for idx in arg_indices: 1LMNOP

1289 args[idx] = _StridedMemoryViewProxy(args[idx]) 1LMNOP

1290 return func(*args, **kwargs) 1LMNOP

1291 return wrapped_func 1LMNOP

1292 return wrapped_func_with_indices 1LMNOP

1293  

1294  

1295cdef inline _StridedLayout layout_from_dlpack(DLTensor* dl_tensor): 

1296 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 1XLMNOPSTUVWZ0123zAyiKJDEFGHICcuefjklqrstmnopgwvdbha

1297 cdef int nbits = dl_tensor.dtype.bits * dl_tensor.dtype.lanes 1XLMNOPSTUVWZ0123zAyiKJDEFGHICcuefjklqrstmnopgwvdbha

1298 cdef int itemsize = nbits >> 3 1XLMNOPSTUVWZ0123zAyiKJDEFGHICcuefjklqrstmnopgwvdbha

1299 if (itemsize << 3) != nbits: 1XLMNOPSTUVWZ0123zAyiKJDEFGHICcuefjklqrstmnopgwvdbha

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

1301 layout.init_from_ptr(dl_tensor.ndim, dl_tensor.shape, dl_tensor.strides, itemsize) 1XLMNOPSTUVWZ0123zAyiKJDEFGHICcuefjklqrstmnopgwvdbha

1302 return layout 1XLMNOPSTUVWZ0123zAyiKJDEFGHICcuefjklqrstmnopgwvdbha

1303  

1304  

1305cdef _StridedLayout layout_from_cai(object metadata): 

1306 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 2x $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb/ Kbabbb7

1307 cdef object shape = metadata["shape"] 2x $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb/ Kbabbb7

1308 cdef object strides = metadata.get("strides") 2x $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb/ Kbabbb7

1309 cdef int itemsize = _typestr2itemsize(metadata["typestr"]) 2x $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb/ Kbabbb7

1310 layout.init_from_tuple(shape, strides, itemsize, True) 2x $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . Mb/ Kbabbb7

1311 return layout 2x $ % : ' ; ( = ) * + , ? @ [ ] ^ _ ` - { | } ~ . / abbb7

1312  

1313  

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

1315 return <intptr_t>(int(buffer.handle)) + layout.get_slice_offset_in_bytes() 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1316  

1317  

1318cdef inline int view_buffer_strided( 

1319 StridedMemoryView view, 

1320 object buffer, 

1321 _StridedLayout layout, 

1322 object dtype, 

1323 bint is_readonly, 

1324) except -1: 

1325 if dtype is not None: 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbcbdbPbLbQ # J D E F G H I

1326 dtype = numpy.dtype(dtype) 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbcbdbPbLbJ D E F G H I

1327 if dtype.itemsize != layout.itemsize: 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbcbdbPbLbJ D E F G H I

1328 raise ValueError( 

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

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

1331 ) 

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

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

1334 # The required_size_in_bytes fails if min_offset < 0. 

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

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

1337 # while neither is reported by the packages. 

1338 cdef bint is_allocated = buffer.memory_resource is not None 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbcbdbPbLbQ # J D E F G H I

1339 if is_allocated and buffer.size < layout.get_required_size_in_bytes(): 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbRbcbdbPbLbQ # J D E F G H I

1340 raise ValueError( 2Pb

1341 f"Buffer size is too small for the layout. " 2Pb

1342 f"Expected at least {layout.get_required_size_in_bytes()} bytes, " 2Pb

1343 f"got {buffer.size} bytes." 2Pb

1344 ) 

1345 # set the public attributes 

1346 view.ptr = get_data_ptr(buffer, layout) 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1347 view.device_id = buffer.device_id 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1348 view.is_device_accessible = buffer.is_device_accessible 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1349 view.readonly = is_readonly 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1350 view.exporting_obj = view._buffer = buffer 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1351 # no dlpack/cai metadata 

1352 view.dl_tensor = NULL 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1353 view.metadata = None 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1354 # we get the layout from the caller 

1355 view._layout = layout 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1356 view._dtype = dtype 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I

1357 return 0 2z A y ebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbcbdbLbQ # J D E F G H I