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

710 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-07-19 01:12 +0000

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

2# 

3# SPDX-License-Identifier: Apache-2.0 

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) 21 2 3 8 V P J K L M N Q R S T U v x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} 6 7 g I 5 H 4 B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

78 cdef object cached = _torch_type_cache.get(tp) 21 2 3 8 V P J K L M N Q R S T U v x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} 6 7 g I 5 H 4 B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

79 if cached is not None: 21 2 3 8 V P J K L M N Q R S T U v x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} 6 7 g I 5 H 4 B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

80 return <bint>cached 23 8 V J K L M N Q R S T U x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba

81 cdef str mod = tp.__module__ or "" 21 2 P v | Ib} 4 a Mb

82 cdef bint result = mod.startswith("torch") and hasattr(obj, "data_ptr") \ 21 2 P v | Ib} 4 a Mb

83 and _torch_version_check() 

84 _torch_type_cache[tp] = result # setdefault not needed for bools 21 2 P v | Ib} 4 a Mb

85 return result 21 2 P v | Ib} 4 a Mb

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__ 2W X Y Z 0 Ob~

185 if obj is not None: 2z W X Y Z 0 Ob~

186 # populate self's attributes 

187 if check_has_dlpack(obj): 1WXYZ0~

188 warnings.warn( 1WXYZ0

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

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

191 DeprecationWarning, 1WXYZ0

192 stacklevel=2, 

193 ) 

194 view_as_dlpack(obj, stream_ptr, self) 1zWXYZ0

195 else: 

196 warnings.warn( 1~

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

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

199 DeprecationWarning, 1~

200 stacklevel=2, 

201 ) 

202 view_as_cai(obj, stream_ptr, self) 1~

203 else: 

204 warnings.warn( 2Ob

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

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, 2Ob

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) 21 2 3 8 V P J K L M N Q R S T U x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

225 if _is_torch_tensor(obj): 21 2 3 8 V P J K L M N Q R S T U x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

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

227 return buf 

228 view_as_dlpack(obj, stream_ptr, buf) 21 2 3 8 V P J K L M N Q R S T U x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

229 return buf 11238VPJKLMNQRSTUxyw67gI5HBCDEFGAbsdehijopqrklmnfutca

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) 2v | Ib} 4

243 if _is_torch_tensor(obj): 2v | Ib} 4

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

245 return buf 

246 view_as_cai(obj, stream_ptr, buf) 2z v | Ib} 4

247 return buf 1v|}4

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) 2z ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

259 if _is_torch_tensor(obj): 2! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

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

261 return buf 

262 view_as_array_interface(obj, buf) 2! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

263 return buf 1z!#-$.%'()*/:;=?@[]^+_`{,

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): 21 2 3 8 V P Q R S T U Zbx y w 6 7 g I 5 H A b s d e h i j o p q r k l m n f u t c a

283 return cls.from_dlpack(obj, stream_ptr) 11238VPQRSTUxyw67gI5HAbsdehijopqrklmnfutca

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) 2RbSbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbUbQbabbbNbJbO 9

324 if itemsize is None and dtype is None: 2RbSbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbUbQbabbbNbJbO 9

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

326 if itemsize is not None and dtype is not None and itemsize != dtype.itemsize: 2RbSbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbQbabbbNbJbO 9

327 raise ValueError( 2Qb

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

329 ) 

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

331 view_buffer_strided( 2cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbabbbNbJbO 9

332 view, 

333 buffer, 

334 _StridedLayout(shape=shape, strides=strides, itemsize=getattr(dtype, "itemsize", itemsize)), 2RbSbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbabbbNbJbO 9

335 dtype, 

336 is_readonly, 

337 ) 

338 return view 2z cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9

339  

340 def __dealloc__(self) -> None: 

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

342 return 2RbSbv x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , KbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbUbQbabbbNbJb| Ib} O Ob~ 9 5 H 4 B C D E F G LbMb

343  

344 if cpython.PyCapsule_IsValid( 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAsdehijopqrklmnfutca

345 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME): 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAsdehijopqrklmnfutca

346 data = cpython.PyCapsule_GetPointer( 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAsdehijopqrklmnfutca

347 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME) 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAsdehijopqrklmnfutca

348 dlm_tensor_ver = <DLManagedTensorVersioned*>data 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAsdehijopqrklmnfutca

349 dlm_tensor_ver.deleter(dlm_tensor_ver) 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAsdehijopqrklmnfutca

350 elif cpython.PyCapsule_IsValid( 1a

351 self.metadata, DLPACK_TENSOR_USED_NAME): 1za

352 data = cpython.PyCapsule_GetPointer( 1a

353 self.metadata, DLPACK_TENSOR_USED_NAME) 1a

354 dlm_tensor = <DLManagedTensor*>data 1a

355 dlm_tensor.deleter(dlm_tensor) 1a

356  

357 def view( 

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

359 ) -> StridedMemoryView: 

360 """ 

361 Creates a new view with adjusted layout and dtype. 

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

363 """ 

364 cdef StridedMemoryView view = StridedMemoryView.__new__(self.__class__) 2x y w abbb5 H B C D E F G

365 if layout is None and dtype is None: 2z x y w abbb5 H B C D E F G

366 return self 15

367 if layout is None: 2x y w abbbH B C D E F G

368 layout = self.get_layout() 1xywH

369 if dtype is None: 2x y w abbbH B C D E F G

370 dtype = self.get_dtype() 2z abbbB C D E F G

371 view_buffer_strided(view, self.get_buffer(), layout, dtype, self.readonly) 2x y w abbbH B C D E F G

372 return view 2x y w abbbH B C D E F G

373  

374 def as_tensor_map( 

375 self, 

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

377 *, 

378 options: object = None, 

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

380 data_type: object = None, 

381 interleave: object = None, 

382 swizzle: object = None, 

383 l2_promotion: object = None, 

384 oob_fill: object = None, 

385 ) -> object: 

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

387  

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

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

390 individual keyword arguments directly, or provide bundled tiled 

391 options via ``options=``. 

392 """ 

393 from cuda.core._tensor_map import TensorMapDescriptor 1zP

394  

395 kwargs = {} 1P

396 if options is not None: 1P

397 kwargs["options"] = options 

398 if element_strides is not None: 1P

399 kwargs["element_strides"] = element_strides 1P

400 if data_type is not None: 1P

401 kwargs["data_type"] = data_type 1zP

402 if interleave is not None: 1P

403 kwargs["interleave"] = interleave 

404 if swizzle is not None: 1P

405 kwargs["swizzle"] = swizzle 1P

406 if l2_promotion is not None: 1P

407 kwargs["l2_promotion"] = l2_promotion 1P

408 if oob_fill is not None: 1P

409 kwargs["oob_fill"] = oob_fill 1P

410 return TensorMapDescriptor._from_tiled(self, box_dim, **kwargs) 1P

411  

412 def copy_from( 

413 self, 

414 other: StridedMemoryView, 

415 stream: Stream, 

416 allocator: object = None, 

417 blocking: bool | None = None, 

418 ) -> None: 

419 """ 

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

421  

422 The copy can be performed between following memory spaces: 

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

424  

425 Parameters 

426 ---------- 

427 other : StridedMemoryView 

428 The view to copy data from. 

429 stream : Stream | None, optional 

430 The stream to schedule the copy on. 

431 allocator : MemoryResource | None, optional 

432 If temporary buffers are needed, the specified memory resources 

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

434 resources will be used. 

435 blocking : bool | None, optional 

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

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

438 blocking until the copy is complete. 

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

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

441 still synchronize with the host if necessary. 

442 * ``None`` (default): 

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

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

445 """ 

446 raise NotImplementedError("Sorry, not supported: copy_from") 16

447  

448 def copy_to( 

449 self, 

450 other: StridedMemoryView, 

451 stream: Stream | None = None, 

452 allocator: object = None, 

453 blocking: bool | None = None, 

454 ) -> None: 

455 """ 

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

457  

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

459 """ 

460 raise NotImplementedError("Sorry, not supported: copy_to") 17

461  

462 def __dlpack__( 

463 self, 

464 *, 

465 stream: int | None = None, 

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

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

468 copy: bool | None = None, 

469 ) -> object: 

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

471 if dl_device is not None: 13vxywgOsdehijopqrklmnfutca

472 raise BufferError("Sorry, not supported: dl_device other than None") 13

473 if copy is True: 13vxywgOsdehijopqrklmnfutca

474 raise BufferError("Sorry, not supported: copy=True") 13

475  

476 cdef bint versioned 

477 if max_version is None: 13vxywgOsdehijopqrklmnfutca

478 versioned = False 1vxywOta

479 else: 

480 if not isinstance(max_version, tuple) or len(max_version) != 2: 13gsdehijopqrklmnfuca

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

482 versioned = max_version >= (1, 0) 1gsdehijopqrklmnfuca

483  

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

485 cdef object capsule = _smv_make_py_capsule(self, versioned) 1vxywgOsdehijopqrklmnfutca

486 return capsule 1vgsdehijopqrklmnfutca

487  

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

489 cdef _DLDeviceType device_type 

490 cdef int32_t device_id 

491 _smv_get_dl_device(self, &device_type, &device_id) 112vga

492 return (<int>device_type, int(device_id)) 112vga

493  

494 @property 

495 def _layout(self) -> _StridedLayout: 

496 """ 

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

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

499 """ 

500 return self.get_layout() 2cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbObH B C D E F G

501  

502 @property 

503 def size(self) -> int: 

504 return self.get_layout().get_volume() 1JKLMNQRSTUWXYZ0!#-$.%'()*/:;=?@[]^+_`{,|

505  

506 @property 

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

508 """ 

509 Shape of the tensor. 

510 """ 

511 return self.get_layout().get_shape_tuple() 2V J K L M N Q R S T U W X Y Z 0 ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbb| } ~ 9 I 4 B C D E F G b

512  

513 @property 

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

515 """ 

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

517 """ 

518 return self.get_layout().get_strides_tuple() 2V J K L M N Q R S T U W X Y Z 0 ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHb| } 9 I

519  

520 @property 

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

522 """ 

523 Data type of the tensor. 

524  

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

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

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

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

529 """ 

530 return self.get_dtype() 2! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbJb9 I H B C D E F G

531  

532 def __repr__(self) -> str: 

533 return (f"StridedMemoryView(ptr={self.ptr},\n" 19I

534 + f" shape={self.shape},\n" 19I

535 + f" strides={self.strides},\n" 19I

536 + f" itemsize={self._layout.itemsize},\n" 19I

537 + f" dtype={get_simple_repr(self.dtype)},\n" 19I

538 + f" device_id={self.device_id},\n" 19I

539 + f" is_device_accessible={self.is_device_accessible},\n" 19I

540 + f" readonly={self.readonly},\n" 19I

541 + f" exporting_obj={get_simple_repr(self.exporting_obj)})") 1z9I

542  

543 @cython.critical_section 

544 cdef inline _StridedLayout get_layout(self): 

545 if self._layout is None: 2V J K L M N Q R S T U W X Y Z 0 v x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , KbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbb| Ib} g O Ob~ 9 I H 4 B C D E F G A b s d e h i j o p q r k l m n f u t c a

546 if self.dl_tensor: 2V J K L M N Q R S T U W X Y Z 0 v x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} g Ob~ I H 4 B C D E F G A b s d e h i j o p q r k l m n f u t c a

547 self._layout = layout_from_dlpack(self.dl_tensor) 1VJKLMNQRSTUWXYZ0xywgIHBCDEFGAbsdehijopqrklmnfutca

548 elif self.metadata is not None: 2z v ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} Ob~ 4

549 self._layout = layout_from_cai(self.metadata) 2v ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} ~ 4

550 else: 

551 raise ValueError("Cannot infer layout from the exporting object") 2Ob

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

553  

554 @cython.critical_section 

555 cdef inline object get_buffer(self): 

556 """ 

557 Returns Buffer instance with the underlying data. 

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

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

560 """ 

561 if self._buffer is None: 2v x y w abbbH B C D E F G

562 if isinstance(self.exporting_obj, Buffer): 1vxywHBCDEFG

563 self._buffer = self.exporting_obj 

564 else: 

565 self._buffer = Buffer.from_handle(self.ptr, 0, owner=self.exporting_obj) 1zvxywHBCDEFG

566 return self._buffer 2v x y w abbbH B C D E F G

567  

568 @cython.critical_section 

569 cdef inline object get_dtype(self): 

570 if self._dtype is None: 2v x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbg O 9 I H B C D E F G A b s d e h i j o p q r k l m n f u t c a

571 if self.dl_tensor != NULL: 1v!#-$.%'()*/:;=?@[]^+_`{,gO9IBCDEFGAbsdehijopqrklmnfutca

572 self._dtype = dtype_dlpack_to_numpy(&self.dl_tensor.dtype) 1gIBCDEFGAbsdehijopqrklmnfutca

573 elif isinstance(self.metadata, int): 1v!#-$.%'()*/:;=?@[]^+_`{,O9

574 # AOTI dtype code stored by the torch tensor bridge 

575 self._dtype = _get_tensor_bridge().resolve_aoti_dtype( 

576 self.metadata) 

577 elif self.metadata is not None: 1v!#-$.%'()*/:;=?@[]^+_`{,O9

578 self._dtype = _typestr2dtype(self.metadata["typestr"]) 1v!#-$.%'()*/:;=?@[]^+_`{,

579 return self._dtype 2v x y w ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbg O 9 I H B C D E F G A b s d e h i j o p q r k l m n f u t c a

580  

581  

582cdef void _smv_pycapsule_deleter(object capsule) noexcept: 

583 cdef DLManagedTensor* dlm_tensor 

584 cdef DLManagedTensorVersioned* dlm_tensor_ver 

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

586 if cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME): 1vgsdehijopqrklmnfutca

587 dlm_tensor = <DLManagedTensor*>( 1zvt

588 cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME) 1vt

589 ) 

590 if dlm_tensor.deleter: 1vt

591 dlm_tensor.deleter(dlm_tensor) 1zvt

592 elif cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 1gsdehijopqrklmnfuca

593 dlm_tensor_ver = <DLManagedTensorVersioned*>( 1c

594 cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 1c

595 ) 

596 if dlm_tensor_ver.deleter: 1c

597 dlm_tensor_ver.deleter(dlm_tensor_ver) 1c

598  

599  

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

601 if shape_ptr: 1vxywgOsdehijopqrklmnfutca

602 stdlib.free(shape_ptr) 1vgsdehijopqrklmnftca

603 if manager_ctx: 1vxywgOsdehijopqrklmnfutca

604 cpython.Py_DECREF(<object>manager_ctx) 1vxywgOsdehijopqrklmnfutca

605  

606  

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

608 if tensor: 1vxywOta

609 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1zvxywOta

610 tensor.manager_ctx = NULL 1vxywOta

611 stdlib.free(tensor) 1vxywOta

612  

613  

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

615 if tensor: 1xywgOsdehijopqrklmnfuca

616 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1gsdehijopqrklmnfuca

617 tensor.manager_ctx = NULL 1gsdehijopqrklmnfuca

618 stdlib.free(tensor) 1gsdehijopqrklmnfuca

619  

620  

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

622 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1gbsdehijopqrklmnfuca

623 dlm_tensor_ver = <DLManagedTensorVersioned*>stdlib.malloc(sizeof(DLManagedTensorVersioned)) 1gbsdehijopqrklmnfuca

624 if dlm_tensor_ver == NULL: 1gbsdehijopqrklmnfuca

625 raise MemoryError() 

626 dlm_tensor_ver.dl_tensor.shape = NULL 1gbsdehijopqrklmnfuca

627 dlm_tensor_ver.manager_ctx = NULL 1gbsdehijopqrklmnfuca

628 return dlm_tensor_ver 1gbsdehijopqrklmnfuca

629  

630  

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

632 cdef DLManagedTensor* dlm_tensor = NULL 1zvxywOta

633 dlm_tensor = <DLManagedTensor*>stdlib.malloc(sizeof(DLManagedTensor)) 1vxywOta

634 if dlm_tensor == NULL: 1vxywOta

635 raise MemoryError() 

636 dlm_tensor.dl_tensor.shape = NULL 1vxywOta

637 dlm_tensor.manager_ctx = NULL 1vxywOta

638 return dlm_tensor 1vxywOta

639  

640  

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

642 cdef object np_dtype = numpy.dtype(dtype_obj) 1vxywgAbsdehijopqrklmnfutca

643 if np_dtype.fields is not None: 1vxywgAbsdehijopqrklmnfutca

644 raise BufferError("Structured dtypes are not supported for DLPack export") 1y

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

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

647  

648 cdef str kind = np_dtype.kind 1zvwgAbsdehijopqrklmnfutca

649 cdef int bits = np_dtype.itemsize * 8 1vwgAbsdehijopqrklmnfutca

650 cdef uint8_t code 

651 if kind == "b": 1vwgAbsdehijopqrklmnfutca

652 if bits != 8: 1s

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

654 code = <uint8_t>kDLBool 1s

655 elif kind == "i": 1vwgAbdehijopqrklmnfutca

656 if bits not in (8, 16, 32, 64): 1gAopqrtca

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

658 code = <uint8_t>kDLInt 1gAopqrtca

659 elif kind == "u": 1vwbdehijklmnfu

660 if bits not in (8, 16, 32, 64): 1klmn

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

662 code = <uint8_t>kDLUInt 1klmn

663 elif kind == "f": 1vwbdehijfu

664 if bits not in (16, 32, 64): 1vbhij

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

666 code = <uint8_t>kDLFloat 1vbhij

667 elif kind == "c": 1wdefu

668 if bits not in (64, 128): 1zdefu

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

670 code = <uint8_t>kDLComplex 1defu

671 else: 

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

673  

674 out_dtype.code = code 1vgAbsdehijopqrklmnfutca

675 out_dtype.bits = <uint8_t>bits 1vgAbsdehijopqrklmnfutca

676 out_dtype.lanes = <uint16_t>1 1vgAbsdehijopqrklmnfutca

677 return 0 1vgAbsdehijopqrklmnfutca

678  

679  

680cdef inline int _smv_get_dl_device( 

681 StridedMemoryView view, 

682 _DLDeviceType* out_device_type, 

683 int32_t* out_device_id, 

684) except -1: 

685 cdef _DLDeviceType device_type 

686 cdef int32_t device_id 

687 cdef object buf 

688 if view.dl_tensor != NULL: 112vgAbsdehijopqrklmnfutca

689 device_type = view.dl_tensor.device.device_type 112gAbsdehijopqrklmnfutca

690 if device_type == _kDLCUDA: 112gAbsdehijopqrklmnfutca

691 device_id = view.dl_tensor.device.device_id 

692 else: 

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

694 device_id = 0 112gAbsdehijopqrklmnfutca

695 elif view.is_device_accessible: 1v

696 buf = view.get_buffer() 1v

697 dev_type, dev_id = classify_dl_device(buf) 1v

698 device_type = <_DLDeviceType>dev_type 1v

699 device_id = <int32_t>dev_id 1v

700 else: 

701 device_type = _kDLCPU 

702 device_id = 0 

703  

704 out_device_type[0] = device_type 112vgAbsdehijopqrklmnfutca

705 out_device_id[0] = device_id 112vgAbsdehijopqrklmnfutca

706 return 0 112vgAbsdehijopqrklmnfutca

707  

708  

709cdef inline int _smv_setup_dl_tensor_common( 

710 DLTensor* dl_tensor, 

711 StridedMemoryView view, 

712 _StridedLayout layout, 

713) except -1: 

714 cdef object dtype_obj = view.get_dtype() 1vxywgOAbsdehijopqrklmnfutca

715 if dtype_obj is None: 1vxywgOAbsdehijopqrklmnfutca

716 raise BufferError( 1O

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

718 "create the view with dtype specified." 

719 ) 

720 _smv_dtype_numpy_to_dlpack(dtype_obj, &dl_tensor.dtype) 1vxywgAbsdehijopqrklmnfutca

721 _smv_get_dl_device(view, &dl_tensor.device.device_type, &dl_tensor.device.device_id) 1vgAbsdehijopqrklmnfutca

722  

723 cdef int ndim = layout.base.ndim 1vgAbsdehijopqrklmnfutca

724 dl_tensor.ndim = ndim 1vgAbsdehijopqrklmnfutca

725 if layout.get_volume() == 0: 1vgAbsdehijopqrklmnfutca

726 dl_tensor.data = NULL 1f

727 else: 

728 dl_tensor.data = <void*><intptr_t>view.ptr 1vgAbsdehijopqrklmnutca

729 dl_tensor.byte_offset = 0 1vgAbsdehijopqrklmnfutca

730 return 0 1vgAbsdehijopqrklmnfutca

731  

732  

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

734 cdef _StridedLayout layout = view.get_layout() 1vxywgObsdehijopqrklmnfutca

735 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1vxywgObsdehijopqrklmnfutca

736  

737 cdef int i 

738 cdef int64_t* shape_strides = NULL 1vgbsdehijopqrklmnfutca

739 cdef int64_t* strides_src = NULL 1vgbsdehijopqrklmnfutca

740 cdef int ndim = dl_tensor.ndim 1vgbsdehijopqrklmnfutca

741 if ndim == 0: 1vgbsdehijopqrklmnfutca

742 dl_tensor.shape = NULL 1u

743 dl_tensor.strides = NULL 1u

744 else: 

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

746 shape_strides = <int64_t*>stdlib.malloc(sizeof(int64_t) * 2 * ndim) 1vgbsdehijopqrklmnftca

747 if shape_strides == NULL: 1vgbsdehijopqrklmnftca

748 raise MemoryError() 

749 try: 1vgbsdehijopqrklmnftca

750 strides_src = get_strides_ptr(layout.base) 1vgbsdehijopqrklmnftca

751 for i in range(ndim): 1vgbsdehijopqrklmnftca

752 shape_strides[i] = layout.base.shape[i] 1vgbsdehijopqrklmnftca

753 shape_strides[i + ndim] = strides_src[i] 1vgbsdehijopqrklmnftca

754 except Exception: 

755 stdlib.free(shape_strides) 

756 raise 

757 dl_tensor.shape = shape_strides 1vgbsdehijopqrklmnftca

758 dl_tensor.strides = shape_strides + ndim 1vgbsdehijopqrklmnftca

759 return 0 1vgbsdehijopqrklmnfutca

760  

761  

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

763 cdef _StridedLayout layout = view.get_layout() 1A

764 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1A

765  

766 if dl_tensor.ndim == 0: 1A

767 dl_tensor.shape = NULL 

768 dl_tensor.strides = NULL 

769 else: 

770 dl_tensor.shape = layout.base.shape 1A

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

772 dl_tensor.strides = get_strides_ptr(layout.base) 1A

773 return 0 1A

774  

775  

776cdef inline int _smv_fill_managed_tensor_versioned( 

777 DLManagedTensorVersioned* dlm_tensor_ver, 

778 StridedMemoryView view, 

779) except -1: 

780 cpython.Py_INCREF(view) 1gbsdehijopqrklmnfuca

781 dlm_tensor_ver.manager_ctx = <void*>view 1gbsdehijopqrklmnfuca

782 dlm_tensor_ver.deleter = _smv_versioned_deleter 1gbsdehijopqrklmnfuca

783 dlm_tensor_ver.version.major = DLPACK_MAJOR_VERSION 1gbsdehijopqrklmnfuca

784 dlm_tensor_ver.version.minor = DLPACK_MINOR_VERSION 1gbsdehijopqrklmnfuca

785 dlm_tensor_ver.flags = DLPACK_FLAG_BITMASK_READ_ONLY if view.readonly else 0 1gbsdehijopqrklmnfuca

786 _smv_setup_dl_tensor(&dlm_tensor_ver.dl_tensor, view) 1gbsdehijopqrklmnfuca

787 return 0 1gbsdehijopqrklmnfuca

788  

789  

790cdef inline int _smv_fill_managed_tensor( 

791 DLManagedTensor* dlm_tensor, 

792 StridedMemoryView view, 

793) except -1: 

794 cpython.Py_INCREF(view) 1vxywOta

795 dlm_tensor.manager_ctx = <void*>view 1vxywOta

796 dlm_tensor.deleter = _smv_deleter 1vxywOta

797 _smv_setup_dl_tensor(&dlm_tensor.dl_tensor, view) 1vxywOta

798 return 0 1vta

799  

800  

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

802 cdef DLManagedTensor* dlm_tensor = NULL 1vxywgOsdehijopqrklmnfutca

803 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1vxywgOsdehijopqrklmnfutca

804 cdef object capsule = None 1vxywgOsdehijopqrklmnfutca

805 cdef void* tensor_ptr = NULL 1vxywgOsdehijopqrklmnfutca

806 cdef const char* capsule_name 

807 try: 1vxywgOsdehijopqrklmnfutca

808 if versioned: 1vxywgOsdehijopqrklmnfutca

809 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1gsdehijopqrklmnfuca

810 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, view) 1gsdehijopqrklmnfuca

811 tensor_ptr = <void*>dlm_tensor_ver 1gsdehijopqrklmnfuca

812 capsule_name = DLPACK_VERSIONED_TENSOR_UNUSED_NAME 1gsdehijopqrklmnfuca

813 else: 

814 dlm_tensor = _smv_allocate_dlm_tensor() 1vxywOta

815 _smv_fill_managed_tensor(dlm_tensor, view) 1vxywOta

816 tensor_ptr = <void*>dlm_tensor 1vta

817 capsule_name = DLPACK_TENSOR_UNUSED_NAME 1vta

818 capsule = cpython.PyCapsule_New(tensor_ptr, capsule_name, _smv_pycapsule_deleter) 1vgsdehijopqrklmnfutca

819 except Exception: 1xywO

820 if capsule is None: 1xywO

821 _smv_deleter(dlm_tensor) 1xywO

822 _smv_versioned_deleter(dlm_tensor_ver) 1xywO

823 raise 1xywO

824 return capsule 1vgsdehijopqrklmnfutca

825  

826  

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

828 cdef void* data = NULL 1b

829 cdef DLTensor* dl_tensor = NULL 1b

830 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1b

831 cdef DLManagedTensor* dlm_tensor = NULL 1b

832 cdef bint is_readonly = False 1b

833 cdef const char* used_name = NULL 1b

834 if cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 1b

835 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 1b

836 dlm_tensor_ver = <DLManagedTensorVersioned*>data 1b

837 dl_tensor = &dlm_tensor_ver.dl_tensor 1b

838 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 1b

839 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 1b

840 elif cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME): 

841 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME) 

842 dlm_tensor = <DLManagedTensor*>data 

843 dl_tensor = &dlm_tensor.dl_tensor 

844 is_readonly = False 

845 used_name = DLPACK_TENSOR_USED_NAME 

846 else: 

847 raise BufferError("Invalid DLPack capsule") 

848  

849 cpython.PyCapsule_SetName(capsule, used_name) 1b

850  

851 cdef StridedMemoryView view = StridedMemoryView.__new__(StridedMemoryView) 1b

852 view.dl_tensor = dl_tensor 1b

853 view.metadata = capsule 1b

854 view.ptr = <intptr_t>(dl_tensor.data) + <intptr_t>(dl_tensor.byte_offset) 1b

855 view.readonly = is_readonly 1b

856 view.exporting_obj = exporting_obj 1b

857 if dl_tensor.device.device_type == _kDLCPU: 1b

858 view.device_id = -1 1b

859 view.is_device_accessible = False 1b

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

861 view.device_id = dl_tensor.device.device_id 

862 view.is_device_accessible = True 

863 else: 

864 raise BufferError("device not supported") 

865 return view 1b

866  

867  

868cdef int _smv_managed_tensor_allocator( 

869 DLTensor* prototype, 

870 DLManagedTensorVersioned** out, 

871 void* error_ctx, 

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

873) noexcept with gil: 

874 if out != NULL: 2Vb

875 out[0] = NULL 2Vb

876 if SetError != NULL: 2Vb

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

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

879 return -1 2Vb

880  

881  

882cdef int _smv_managed_tensor_from_py_object_no_sync( 

883 void* py_object, 

884 DLManagedTensorVersioned** out, 

885) noexcept with gil: 

886 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1b

887 if out == NULL: 1b

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

889 return -1 

890 out[0] = NULL 1b

891 cdef object obj = <object>py_object 1b

892 if not isinstance(obj, StridedMemoryView): 1b

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

894 return -1 

895 try: 1b

896 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1b

897 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, <StridedMemoryView>obj) 1b

898 except Exception: 

899 _smv_versioned_deleter(dlm_tensor_ver) 

900 return -1 

901 out[0] = dlm_tensor_ver 1b

902 return 0 1b

903  

904  

905cdef int _smv_managed_tensor_to_py_object_no_sync( 

906 DLManagedTensorVersioned* tensor, 

907 void** out_py_object, 

908) noexcept with gil: 

909 cdef object capsule 

910 cdef object py_view 

911 if out_py_object == NULL: 2b Wb

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

913 return -1 

914 out_py_object[0] = NULL 2b Wb

915 if tensor == NULL: 2b Wb

916 cpython.PyErr_SetString(RuntimeError, b"tensor cannot be NULL") 2Wb

917 return -1 2Wb

918 try: 1b

919 capsule = cpython.PyCapsule_New( 1b

920 <void*>tensor, 

921 DLPACK_VERSIONED_TENSOR_UNUSED_NAME, 

922 _smv_pycapsule_deleter, 

923 ) 

924 py_view = _smv_from_dlpack_capsule(capsule, capsule) 1b

925 cpython.Py_INCREF(py_view) 1b

926 out_py_object[0] = <void*>py_view 1b

927 except Exception: 

928 return -1 

929 return 0 1b

930  

931  

932cdef int _smv_dltensor_from_py_object_no_sync( 

933 void* py_object, 

934 DLTensor* out, 

935) noexcept with gil: 

936 if out == NULL: 2XbA

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

938 return -1 

939 cdef object obj = <object>py_object 2XbA

940 if not isinstance(obj, StridedMemoryView): 2XbA

941 cpython.PyErr_SetString(TypeError, b"py_object must be a StridedMemoryView") 2Xb

942 return -1 2Xb

943 try: 1A

944 _smv_setup_dltensor_borrowed(out, <StridedMemoryView>obj) 1A

945 except Exception: 

946 return -1 

947 return 0 1A

948  

949  

950cdef int _smv_current_work_stream( 

951 _DLDeviceType device_type, 

952 int32_t device_id, 

953 void** out_current_stream, 

954) noexcept with gil: 

955 if out_current_stream == NULL: 22b

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

957 return -1 

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

959 out_current_stream[0] = NULL 22b

960 return 0 22b

961  

962  

963cdef void _init_smv_dlpack_exchange_api(): 

964 global _SMV_DLPACK_EXCHANGE_API_INITED 

965 if _SMV_DLPACK_EXCHANGE_API_INITED: 

966 return 

967 _SMV_DLPACK_EXCHANGE_API.header.version.major = DLPACK_MAJOR_VERSION 

968 _SMV_DLPACK_EXCHANGE_API.header.version.minor = DLPACK_MINOR_VERSION 

969 _SMV_DLPACK_EXCHANGE_API.header.prev_api = NULL 

970 _SMV_DLPACK_EXCHANGE_API.managed_tensor_allocator = _smv_managed_tensor_allocator 

971 _SMV_DLPACK_EXCHANGE_API.managed_tensor_from_py_object_no_sync = _smv_managed_tensor_from_py_object_no_sync 

972 _SMV_DLPACK_EXCHANGE_API.managed_tensor_to_py_object_no_sync = _smv_managed_tensor_to_py_object_no_sync 

973 _SMV_DLPACK_EXCHANGE_API.dltensor_from_py_object_no_sync = _smv_dltensor_from_py_object_no_sync 

974 _SMV_DLPACK_EXCHANGE_API.current_work_stream = _smv_current_work_stream 

975 _SMV_DLPACK_EXCHANGE_API_INITED = True 

976  

977  

978_init_smv_dlpack_exchange_api() 

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

980# directly into the type dict. 

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

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

983PyType_Modified(<PyTypeObject*>StridedMemoryView) 

984  

985  

986cdef str get_simple_repr(obj): 

987 # TODO: better handling in np.dtype objects 

988 cdef object obj_class 

989 cdef str obj_repr 

990 if isinstance(obj, type): 19I

991 obj_class = obj 

992 else: 

993 obj_class = obj.__class__ 19I

994 if obj_class.__module__ in (None, "builtins"): 19I

995 obj_repr = obj_class.__name__ 19

996 else: 

997 obj_repr = f"{obj_class.__module__}.{obj_class.__name__}" 19I

998 return obj_repr 19I

999  

1000  

1001  

1002cdef bint check_has_dlpack(obj) except*: 

1003 cdef bint has_dlpack 

1004 if hasattr(obj, "__dlpack__") and hasattr(obj, "__dlpack_device__"): 21 2 3 8 V P J K L M N Q R S T U W X Y Z 0 Zbx y w 6 7 g ~ TbI 5 H A b s d e h i j o p q r k l m n f u t c a

1005 has_dlpack = True 11238VPJKLMNQRSTUWXYZ0xyw67gI5HAbsdehijopqrklmnfutca

1006 elif hasattr(obj, "__cuda_array_interface__"): 2Zb~ Tb

1007 has_dlpack = False 2~ Tb

1008 else: 

1009 raise BufferError( 2Zb

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

1011 return has_dlpack 21 2 3 8 V P J K L M N Q R S T U W X Y Z 0 x y w 6 7 g ~ TbI 5 H A b s d e h i j o p q r k l m n f u t c a

1012  

1013  

1014cdef class _StridedMemoryViewProxy: 

1015 cdef readonly: 

1016 object obj 

1017 bint has_dlpack 

1018  

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

1020 self.obj = obj 2J K L M N Tb

1021 self.has_dlpack = check_has_dlpack(obj) 2J K L M N Tb

1022  

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

1024 if self.has_dlpack: 1JKLMN

1025 return StridedMemoryView.from_dlpack(self.obj, stream_ptr) 1JKLMN

1026 else: 

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

1028  

1029  

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

1031 cdef int dldevice, device_id 

1032 cdef bint is_device_accessible, is_readonly 

1033 is_device_accessible = False 21 2 3 8 V P J K L M N Q R S T U W X Y Z 0 x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

1034 dldevice, device_id = obj.__dlpack_device__() 21 2 3 8 V P J K L M N Q R S T U W X Y Z 0 x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

1035 if dldevice == _kDLCPU: 21 2 3 8 V P J K L M N Q R S T U W X Y Z 0 x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba Mb

1036 assert device_id == 0 23 8 V P J K L M N Q R S T U W X Y Z 0 x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba

1037 device_id = -1 23 8 V P J K L M N Q R S T U W X Y Z 0 x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba

1038 if stream_ptr is None: 23 8 V P J K L M N Q R S T U W X Y Z 0 x y w 6 7 g I 5 H B C D E F G A b s d e h i j o p q r k l m n f u t c Lba

1039 raise BufferError("stream=None is ambiguous with view()") 2Lb

1040 elif stream_ptr == -1: 138VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1041 stream_ptr = None 138VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1042 elif dldevice == _kDLCUDA: 

1043 assert device_id >= 0 

1044 is_device_accessible = True 

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

1046 if stream_ptr is None: 

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

1048 elif dldevice in (_kDLCUDAHost, _kDLCUDAManaged): 

1049 is_device_accessible = True 112

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

1051 # accessed on both host and device 

1052 else: 

1053 raise BufferError("device not supported") 2Mb

1054  

1055 cdef object capsule 

1056 try: 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1057 capsule = obj.__dlpack__( 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1058 stream=int(stream_ptr) if stream_ptr else None, 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1059 max_version=(DLPACK_MAJOR_VERSION, DLPACK_MINOR_VERSION)) 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1060 except TypeError: 1a

1061 capsule = obj.__dlpack__( 1a

1062 stream=int(stream_ptr) if stream_ptr else None) 1a

1063  

1064 cdef void* data = NULL 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1065 cdef DLTensor* dl_tensor 

1066 cdef DLManagedTensorVersioned* dlm_tensor_ver 

1067 cdef DLManagedTensor* dlm_tensor 

1068 cdef const char *used_name 

1069 if cpython.PyCapsule_IsValid( 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1070 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 

1071 data = cpython.PyCapsule_GetPointer( 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1072 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 

1073 dlm_tensor_ver = <DLManagedTensorVersioned*>data 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1074 dl_tensor = &dlm_tensor_ver.dl_tensor 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1075 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1076 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1077 elif cpython.PyCapsule_IsValid( 1a

1078 capsule, DLPACK_TENSOR_UNUSED_NAME): 

1079 data = cpython.PyCapsule_GetPointer( 1a

1080 capsule, DLPACK_TENSOR_UNUSED_NAME) 

1081 dlm_tensor = <DLManagedTensor*>data 1a

1082 dl_tensor = &dlm_tensor.dl_tensor 1a

1083 is_readonly = False 1a

1084 used_name = DLPACK_TENSOR_USED_NAME 1a

1085 else: 

1086 assert False 

1087  

1088 cpython.PyCapsule_SetName(capsule, used_name) 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1089  

1090 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1091 buf.dl_tensor = dl_tensor 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1092 buf.metadata = capsule 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1093 buf.ptr = <intptr_t>(dl_tensor.data) 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1094 buf.device_id = device_id 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1095 buf.is_device_accessible = is_device_accessible 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1096 buf.readonly = is_readonly 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1097 buf.exporting_obj = obj 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1098  

1099 return buf 11238VPJKLMNQRSTUWXYZ0xyw67gI5HBCDEFGAbsdehijopqrklmnfutca

1100  

1101  

1102@functools.lru_cache 

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

1104 return numpy.dtype(typestr) 1!#$%'()*+,4

1105  

1106  

1107@functools.lru_cache 

1108def _typestr2itemsize(str typestr) -> int: 

1109 return _typestr2dtype(typestr).itemsize 1!#$%'()*+,4

1110  

1111  

1112cdef object dtype_dlpack_to_numpy(DLDataType* dtype): 

1113 cdef int bits = dtype.bits 1gIBCDEFGAbsdehijopqrklmnfutca

1114 if dtype.lanes != 1: 1gIBCDEFGAbsdehijopqrklmnfutca

1115 # TODO: return a NumPy structured dtype? 

1116 raise NotImplementedError( 

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

1118 if dtype.code == kDLUInt: 1gIBCDEFGAbsdehijopqrklmnfutca

1119 if bits == 8: 1klmn

1120 np_dtype = numpy.uint8 1k

1121 elif bits == 16: 

1122 np_dtype = numpy.uint16 1l

1123 elif bits == 32: 

1124 np_dtype = numpy.uint32 1m

1125 elif bits == 64: 

1126 np_dtype = numpy.uint64 1n

1127 else: 

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

1129 elif dtype.code == kDLInt: 

1130 if bits == 8: 1gIBCDEFGAopqrtca

1131 np_dtype = numpy.int8 1o

1132 elif bits == 16: 

1133 np_dtype = numpy.int16 1p

1134 elif bits == 32: 

1135 np_dtype = numpy.int32 1gIBCDEFGAqtca

1136 elif bits == 64: 

1137 np_dtype = numpy.int64 1r

1138 else: 

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

1140 elif dtype.code == kDLFloat: 

1141 if bits == 16: 1bhij

1142 np_dtype = numpy.float16 1h

1143 elif bits == 32: 

1144 np_dtype = numpy.float32 1i

1145 elif bits == 64: 

1146 np_dtype = numpy.float64 1bj

1147 else: 

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

1149 elif dtype.code == kDLComplex: 

1150 # TODO(leofang): support complex32 

1151 if bits == 64: 1defu

1152 np_dtype = numpy.complex64 1d

1153 elif bits == 128: 

1154 np_dtype = numpy.complex128 1efu

1155 else: 

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

1157 elif dtype.code == kDLBool: 

1158 if bits == 8: 1s

1159 np_dtype = numpy.bool_ 1s

1160 else: 

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

1162 elif dtype.code == kDLBfloat: 

1163 if bfloat16 is not None: 

1164 np_dtype = numpy.dtype("bfloat16") 

1165 else: 

1166 raise NotImplementedError( 

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

1168 'to be installed.' 

1169 ) 

1170 else: 

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

1172  

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

1174 return numpy.dtype(np_dtype) 1gIBCDEFGAbsdehijopqrklmnfutca

1175  

1176  

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

1178 cdef dict cai_data = obj.__cuda_array_interface__ 20bYb3bv | Ib} ~ 4

1179 if cai_data["version"] < 3: 20bYb3bv | Ib} ~ 4

1180 raise BufferError("only CUDA Array Interface v3 or above is supported") 23b

1181 if cai_data.get("mask") is not None: 20bYbv | Ib} ~ 4

1182 raise BufferError("mask is not supported") 20b

1183 if stream_ptr is None: 2Ybv | Ib} ~ 4

1184 raise BufferError("stream=None is ambiguous with view()") 2Yb

1185  

1186 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2v | Ib} ~ 4

1187 buf.exporting_obj = obj 2v | Ib} ~ 4

1188 buf.metadata = cai_data 2v | Ib} ~ 4

1189 buf.dl_tensor = NULL 2v | Ib} ~ 4

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

1191 buf.get_layout() 2v | Ib} ~ 4

1192 buf.ptr, buf.readonly = cai_data["data"] 1v|}~4

1193 buf.is_device_accessible = True 1v|}~4

1194 if buf.ptr != 0: 1v|}~4

1195 buf.device_id = handle_return( 1v4

1196 driver.cuPointerGetAttribute( 1v4

1197 driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL, 1v4

1198 buf.ptr)) 1v4

1199 else: 

1200 buf.device_id = handle_return(driver.cuCtxGetDevice()) 1|}~

1201  

1202 cdef intptr_t producer_s, consumer_s 

1203 cdef EventHandle h_event 

1204 stream_ptr = int(stream_ptr) 1v|}~4

1205 if stream_ptr != -1: 1v|}~4

1206 stream = cai_data.get("stream") 14

1207 if stream is not None: 14

1208 producer_s = <intptr_t>(stream) 14

1209 consumer_s = <intptr_t>(stream_ptr) 14

1210 assert producer_s > 0 14

1211 # establish stream order 

1212 if producer_s != consumer_s: 14

1213 with nogil: 14

1214 h_event = create_event_handle_noctx(cydriver.CUevent_flags.CU_EVENT_DISABLE_TIMING) 14

1215 HANDLE_RETURN(cydriver.cuEventRecord( 14

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

1217 HANDLE_RETURN(cydriver.cuStreamWaitEvent( 14

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

1219 elif _is_torch_tensor(obj): 

1220 # PyTorch's __cuda_array_interface__ reports version 2 and 

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

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

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

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

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

1226 # event-based stream ordering. 

1227 _get_tensor_bridge().sync_torch_stream( 

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

1229  

1230 return buf 1v|}~4

1231  

1232  

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

1234 cdef dict data = obj.__array_interface__ 21b4b! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

1235 if data["version"] < 3: 21b4b! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

1236 raise BufferError("only NumPy Array Interface v3 or above is supported") 24b

1237 if data.get("mask") is not None: 21b! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

1238 raise BufferError("mask is not supported") 21b

1239  

1240 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

1241 buf.exporting_obj = obj 2! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

1242 buf.metadata = data 2! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

1243 buf.dl_tensor = NULL 2! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

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

1245 buf.get_layout() 2! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb

1246 buf.ptr, buf.readonly = data["data"] 1!#-$.%'()*/:;=?@[]^+_`{,

1247 buf.is_device_accessible = False 1!#-$.%'()*/:;=?@[]^+_`{,

1248 buf.device_id = handle_return(driver.cuCtxGetDevice()) 1!#-$.%'()*/:;=?@[]^+_`{,

1249 return buf 1!#-$.%'()*/:;=?@[]^+_`{,

1250  

1251  

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

1253 """ 

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

1255 specified positional arguments. 

1256  

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

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

1259 desired). 

1260  

1261 Inside the decorated function, the specified arguments become instances 

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

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

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

1265 example: 

1266  

1267 .. code-block:: python 

1268  

1269 @args_viewable_as_strided_memory((1,)) 

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

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

1272 view = arg1.view(stream.handle) 

1273 assert isinstance(view, StridedMemoryView) 

1274 ... 

1275  

1276 Parameters 

1277 ---------- 

1278 arg_indices : tuple 

1279 The indices of the target positional arguments. 

1280 """ 

1281 def wrapped_func_with_indices(func: "Callable") -> "Callable": 1JKLMN

1282 @functools.wraps(func) 1JKLMN

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

1284 args = list(args) 1JKLMN

1285 cdef int idx 

1286 for idx in arg_indices: 1JKLMN

1287 args[idx] = _StridedMemoryViewProxy(args[idx]) 1JKLMN

1288 return func(*args, **kwargs) 1JKLMN

1289 return wrapped_func 1JKLMN

1290 return wrapped_func_with_indices 1JKLMN

1291  

1292  

1293cdef inline _StridedLayout layout_from_dlpack(DLTensor* dl_tensor): 

1294 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 1VJKLMNQRSTUWXYZ0xywgIHBCDEFGAbsdehijopqrklmnfutca

1295 cdef int nbits = dl_tensor.dtype.bits * dl_tensor.dtype.lanes 1VJKLMNQRSTUWXYZ0xywgIHBCDEFGAbsdehijopqrklmnfutca

1296 cdef int itemsize = nbits >> 3 1VJKLMNQRSTUWXYZ0xywgIHBCDEFGAbsdehijopqrklmnfutca

1297 if (itemsize << 3) != nbits: 1VJKLMNQRSTUWXYZ0xywgIHBCDEFGAbsdehijopqrklmnfutca

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

1299 layout.init_from_ptr(dl_tensor.ndim, dl_tensor.shape, dl_tensor.strides, itemsize) 1VJKLMNQRSTUWXYZ0xywgIHBCDEFGAbsdehijopqrklmnfutca

1300 return layout 1VJKLMNQRSTUWXYZ0xywgIHBCDEFGAbsdehijopqrklmnfutca

1301  

1302  

1303cdef _StridedLayout layout_from_cai(object metadata): 

1304 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 2v ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} ~ 4

1305 cdef object shape = metadata["shape"] 2v ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} ~ 4

1306 cdef object strides = metadata.get("strides") 2v ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} ~ 4

1307 cdef int itemsize = _typestr2itemsize(metadata["typestr"]) 2v ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} ~ 4

1308 layout.init_from_tuple(shape, strides, itemsize, True) 2v ! # - $ . % ' ( ) * / : ; = ? @ [ ] ^ + _ ` { , Kb| Ib} ~ 4

1309 return layout 1v!#-$.%'()*/:;=?@[]^+_`{,|}~4

1310  

1311  

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

1313 return <intptr_t>(int(buffer.handle)) + layout.get_slice_offset_in_bytes() 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1314  

1315  

1316cdef inline int view_buffer_strided( 

1317 StridedMemoryView view, 

1318 object buffer, 

1319 _StridedLayout layout, 

1320 object dtype, 

1321 bint is_readonly, 

1322) except -1: 

1323 if dtype is not None: 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbabbbNbJbO 9 H B C D E F G

1324 dtype = numpy.dtype(dtype) 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbabbbNbJbH B C D E F G

1325 if dtype.itemsize != layout.itemsize: 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbabbbNbJbH B C D E F G

1326 raise ValueError( 

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

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

1329 ) 

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

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

1332 # The required_size_in_bytes fails if min_offset < 0. 

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

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

1335 # while neither is reported by the packages. 

1336 cdef bint is_allocated = buffer.memory_resource is not None 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbabbbNbJbO 9 H B C D E F G

1337 if is_allocated and buffer.size < layout.get_required_size_in_bytes(): 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbPbabbbNbJbO 9 H B C D E F G

1338 raise ValueError( 2Nb

1339 f"Buffer size is too small for the layout. " 2Nb

1340 f"Expected at least {layout.get_required_size_in_bytes()} bytes, " 2Nb

1341 f"got {buffer.size} bytes." 2Nb

1342 ) 

1343 # set the public attributes 

1344 view.ptr = get_data_ptr(buffer, layout) 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1345 view.device_id = buffer.device_id 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1346 view.is_device_accessible = buffer.is_device_accessible 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1347 view.readonly = is_readonly 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1348 view.exporting_obj = view._buffer = buffer 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1349 # no dlpack/cai metadata 

1350 view.dl_tensor = NULL 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1351 view.metadata = None 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1352 # we get the layout from the caller 

1353 view._layout = layout 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1354 view._dtype = dtype 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G

1355 return 0 2x y w cbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbabbbJbO 9 H B C D E F G