Coverage for cuda/core/_memoryview.pyx: 77.84%
722 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-05 01:11 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-05 01:11 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from __future__ import annotations
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
14import ctypes
15import functools
16import sys
17import warnings
18from collections.abc import Callable # no-cython-lint # used in string annotations below
19from typing import TYPE_CHECKING, Any # no-cython-lint # used in string annotations below
21if TYPE_CHECKING:
22 from cuda.core._tensor_map import TensorMapDescriptorOptions
24import numpy
26from cuda.bindings cimport cydriver
27from cuda.core._rt cimport (
28 EventHandle,
29 create_event_handle_for_stream,
30 as_cu,
31 get_last_error,
32)
34from cuda.core._utils.cuda_utils import handle_return, driver
35from cuda.core._utils.cuda_utils cimport HANDLE_RETURN
38from cuda.core._memory import Buffer
39from cuda.core._memory._buffer cimport Buffer as cyBuffer, Buffer_check_open
42# ---------------------------------------------------------------------------
43# Lazy tensor bridge (avoids loading _tensor_bridge.so until torch is used)
44# ---------------------------------------------------------------------------
46cdef object _tensor_bridge = None
47# Cache: type(obj) -> True/False for the torch tensor check.
48# Once a type is seen, we never re-check.
49cdef dict _torch_type_cache = {}
50# Tri-state: None = not checked, True/False = result of version check
51cdef object _torch_version_ok = None
53cdef inline bint _torch_version_check():
54 """Return True if torch >= 2.3. Memoized.
56 Lower bound: AOTI functions we use were introduced in PyTorch 2.3.
58 No upper bound. The dispatch in ``_tensor_bridge.view_as_torch_tensor``
59 selects between two safe paths per torch version:
61 * torch >= 2.14 -- stable PyObject->Tensor C ABI shim
62 (``torch_tensor_from_pyobject`` + ``aoti_torch_delete_tensor_object``);
63 part of torch's stable contract, so any 2.14+ release is covered.
64 * torch 2.3-2.13 -- ``pyobj_to_aten_handle`` pointer-arithmetic trick,
65 validated against the two known THPVariable layouts
66 (``c10::MaybeOwned<at::Tensor>`` for 2.3-2.9; ``at::Tensor`` directly
67 for 2.10-2.13; see ``_get_cdata_extra_offset`` in ``_tensor_bridge.pyx``).
68 """
69 global _torch_version_ok
70 if _torch_version_ok is not None:
71 return <bint>_torch_version_ok
72 torch = sys.modules.get("torch")
73 if torch is None:
74 _torch_version_ok = False
75 return False
76 try:
77 major, minor = int(torch.__version__.split(".")[0]), \
78 int(torch.__version__.split(".")[1])
79 _torch_version_ok = (major, minor) >= (2, 3)
80 except (ValueError, IndexError):
81 _torch_version_ok = False
82 return <bint>_torch_version_ok
85cdef inline bint _is_torch_tensor(object obj):
86 cdef type tp = type(obj) 2bb{ } jb: ( 6 3 % 7 | 8 9 ! # $ + , - . / L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbgbhbw mb1 cb5 Z dbLbS T U V W X ; ) = ~ ebfbQ R 4 abj P Y 0 I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
87 cdef object cached = _torch_type_cache.get(tp) 2bb{ } jb: ( 6 3 % 7 | 8 9 ! # $ + , - . / L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbgbhbw mb1 cb5 Z dbLbS T U V W X ; ) = ~ ebfbQ R 4 abj P Y 0 I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
88 if cached is not None: 2bb{ } jb: ( 6 3 % 7 | 8 9 ! # $ + , - . / L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbgbhbw mb1 cb5 Z dbLbS T U V W X ; ) = ~ ebfbQ R 4 abj P Y 0 I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
89 return <bint>cached 2bb} jb: ( 6 3 % 7 8 9 ! # $ + , - . / N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bgbhbw 1 cb5 Z S T U V W X ; ) = ~ ebfbQ R 4 abj P Y 0 I s t x y z E F G H A B C D u K J p f 2 cce d b k h q l m r n o g v c i a
90 cdef str mod = tp.__module__ or "" 2{ ( 3 | L Mb]bNbmbdbLb) = 4 2 e d |bb k h g v ~b}b[bi a ac
91 cdef bint result = mod.startswith("torch") and hasattr(obj, "data_ptr") \ 2{ ( 3 | L Mb]bNbmbdbLb) = 4 2 e d |bb k h g v ~b}b[bi a ac
92 and _torch_version_check()
93 _torch_type_cache[tp] = result # setdefault not needed for bools 2{ ( 3 | L Mb]bNbmbdbLb) = 4 2 e d |bb k h g v ~b}b[bi a ac
94 return result 2{ ( 3 | L Mb]bNbmbdbLb) = 4 2 e d |bb k h g v ~b}b[bi a ac
97cdef object _get_tensor_bridge():
98 """Bootstrap AOTI symbols, then import _tensor_bridge on first use."""
99 global _tensor_bridge
100 if _tensor_bridge is not None:
101 return _tensor_bridge
102 torch_C = sys.modules.get("torch._C")
103 if torch_C is None:
104 raise RuntimeError(
105 "torch._C is not loaded; cannot initialise the tensor bridge. "
106 "Make sure PyTorch is imported before passing a torch.Tensor.")
107 ctypes.CDLL(torch_C.__file__, mode=ctypes.RTLD_GLOBAL)
108 from cuda.core import _tensor_bridge as tb
109 _tensor_bridge = tb
110 return _tensor_bridge
113try:
114 from ml_dtypes import bfloat16
115except ImportError:
116 bfloat16 = None
118# TODO(leofang): support NumPy structured dtypes
121cdef extern from "Python.h":
122 ctypedef struct PyTypeObject:
123 void* tp_dict
124 void PyType_Modified(PyTypeObject*)
127cdef DLPackExchangeAPI _SMV_DLPACK_EXCHANGE_API
128cdef bint _SMV_DLPACK_EXCHANGE_API_INITED = False
129_SMV_DLPACK_EXCHANGE_API_CAPSULE = cpython.PyCapsule_New(
130 <void*>&_SMV_DLPACK_EXCHANGE_API,
131 b"dlpack_exchange_api",
132 NULL,
133)
136cdef class StridedMemoryView:
137 """A class holding metadata of a strided dense array/tensor.
139 A :obj:`StridedMemoryView` instance can be created in three ways:
141 1. Using the :obj:`args_viewable_as_strided_memory` decorator (recommended)
142 2. Explicit construction relying on DLPack or CUDA Array Interface, see below.
143 3. From :obj:`~_memory.Buffer` and shape and size tuples (see
144 :meth:`from_buffer` classmethod)
146 ``StridedMemoryView(obj, stream_ptr)`` can be used to create a view from
147 objects supporting either DLPack (up to v1.0) or CUDA Array Interface
148 (CAI) v3. When wrapping an arbitrary object it will try the DLPack protocol
149 first, then the CAI protocol. A :obj:`BufferError` is raised if neither is
150 supported.
152 Since either way would take a consumer stream, for DLPack it is passed to
153 ``obj.__dlpack__()`` as-is (except for :obj:`None`, see below); for CAI, a
154 stream order will be established between the consumer stream and the
155 producer stream (from ``obj.__cuda_array_interface__()["stream"]``), as if
156 ``cudaStreamWaitEvent`` is called by this method.
158 To opt-out of the stream ordering operation in either DLPack or CAI,
159 please pass ``stream_ptr=-1``. Note that this deviates (on purpose)
160 from the semantics of ``obj.__dlpack__(stream=None, ...)`` since ``cuda.core``
161 does not encourage using the (legacy) default/null stream, but is
162 consistent with the CAI's semantics. For DLPack, ``stream=-1`` will be
163 internally passed to ``obj.__dlpack__()`` instead.
165 Parameters
166 ----------
167 obj : Any
168 Any objects that supports either DLPack (up to v1.0) or CUDA Array
169 Interface (v3).
170 stream_ptr: int
171 The pointer address (as Python `int`) to the **consumer** stream.
172 Stream ordering will be properly established unless ``-1`` is passed.
175 Attributes
176 -----------
177 ptr : int
178 Pointer to the tensor buffer (as a Python `int`).
179 device_id : int
180 The device ID for where the tensor is located. It is -1 for CPU tensors
181 (meaning those only accessible from the host).
182 is_device_accessible : bool
183 Whether the tensor data can be accessed on the GPU.
184 readonly: bool
185 Whether the tensor data can be modified in place.
186 exporting_obj : Any
187 A reference to the original tensor object that is being viewed.
188 If the view is created with :meth:`from_buffer`,
189 it will be the Buffer instance passed to the method.
191 """
192 def __init__(self, obj: object = None, stream_ptr: int | None = None) -> None:
193 cdef str clsname = self.__class__.__name__ 2? @ [ ] ^ ecPb_ `
194 if obj is not None: 2? @ [ ] ^ ecPb_ `
195 # populate self's attributes
196 if check_has_dlpack(obj): 2? @ [ ] ^ Pb_ `
197 warnings.warn( 1?@[]^_`
198 f"Constructing a {clsname} directly from a DLPack-supporting object is deprecated; " 1?@[]^_`
199 "Use `StridedMemoryView.from_dlpack` or `StridedMemoryView.from_any_interface` instead.",
200 DeprecationWarning, 1?@[]^_`
201 stacklevel=2,
202 )
203 view_as_dlpack(obj, stream_ptr, self) 1?@[]^_`
204 else:
205 warnings.warn( 2Pb
206 f"Constructing a {clsname} directly from a CUDA-array-interface-supporting object is deprecated; " 2Pb
207 "Use `StridedMemoryView.from_cuda_array_interface` or `StridedMemoryView.from_any_interface` instead.",
208 DeprecationWarning, 2Pb
209 stacklevel=2,
210 )
211 view_as_cai(obj, stream_ptr, self) 2Pb
212 else:
213 warnings.warn( 2ec
214 f"Constructing an empty {clsname} is deprecated; " 2ec
215 "use one of the classmethods `from_dlpack`, `from_cuda_array_interface` or `from_any_interface` "
216 "to construct a StridedMemoryView from an object",
217 DeprecationWarning, 2ec
218 stacklevel=2,
219 )
221 @classmethod
222 def from_dlpack(cls, obj: object, stream_ptr: int | None=None) -> StridedMemoryView:
223 """Create a view from an object supporting the `DLPack <https://dmlc.github.io/dlpack/latest/>`_ protocol.
225 Parameters
226 ----------
227 obj : object
228 An object implementing the `DLPack <https://dmlc.github.io/dlpack/latest/>`_ protocol
229 (via ``__dlpack__``).
230 stream_ptr : int, optional
231 Stream pointer for synchronization. If ``None``, no synchronization is performed.
232 """
233 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / N O M gbhbw 1 cb5 Z S T U V W X ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
234 if _is_torch_tensor(obj): 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / N O M gbhbw 1 cb5 Z S T U V W X ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
235 _get_tensor_bridge().view_as_torch_tensor(obj, stream_ptr, buf)
236 return buf
237 view_as_dlpack(obj, stream_ptr, buf) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / N O M gbhbw 1 cb5 Z S T U V W X ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
238 return buf 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / N O M gbhbw 1 cb5 Z S T U V W X ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
240 @classmethod
241 def from_cuda_array_interface(cls, obj: object, stream_ptr: int | None=None) -> StridedMemoryView:
242 """Create a view from an object supporting the `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_ protocol.
244 Parameters
245 ----------
246 obj : object
247 An object implementing the `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_ protocol.
248 stream_ptr : int, optional
249 Stream pointer for synchronization. If ``None``, no synchronization is performed.
250 """
251 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2% 7 | L Mb]bNbmbdbLb
252 if _is_torch_tensor(obj): 2% 7 | L Mb]bNbmbdbLb
253 _get_tensor_bridge().view_as_torch_tensor(obj, stream_ptr, buf)
254 return buf
255 view_as_cai(obj, stream_ptr, buf) 2% 7 | L Mb]bNbmbdbLb
256 return buf 2% 7 | L MbNbmbdb
258 @classmethod
259 def from_array_interface(cls, obj: object) -> StridedMemoryView:
260 """Create a view from an object supporting the `__array_interface__ <https://numpy.org/doc/stable/reference/arrays.interface.html>`_ protocol.
262 Parameters
263 ----------
264 obj : object
265 An object implementing the `__array_interface__ <https://numpy.org/doc/stable/reference/arrays.interface.html>`_ protocol (e.g., a numpy array).
266 """
267 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
268 if _is_torch_tensor(obj): 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
269 _get_tensor_bridge().view_as_torch_tensor(obj, None, buf)
270 return buf
271 view_as_array_interface(obj, buf) 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
272 return buf 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbeb4 P Y 0 f e d
274 @classmethod
275 def from_any_interface(cls, obj: object, stream_ptr: int | None = None) -> StridedMemoryView:
276 """Create a view by automatically selecting the best available protocol.
278 Tries `DLPack <https://dmlc.github.io/dlpack/latest/>`_ first, then falls back to
279 `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_.
280 ``torch.Tensor`` objects are transparently handled via a fast AOTI path
281 regardless of which protocol is selected.
283 Parameters
284 ----------
285 obj : object
286 An object implementing `DLPack <https://dmlc.github.io/dlpack/latest/>`_ or
287 `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_.
288 stream_ptr : int, optional
289 Stream pointer for synchronization. If ``None``, no synchronization is performed.
290 """
291 if check_has_dlpack(obj): 2bb{ } jb: ( 6 3 % 7 | + , - . / kcN O M gbhbw 1 cb5 Z ; ) fbQ R abj I s t x y z E F G H A B C D u K J p b k h q l m r n o g v c i a
292 return cls.from_dlpack(obj, stream_ptr) 2bb{ } jb: ( 6 3 + , - . / N O M gbhbw 1 cb5 Z ; ) fbQ R abj I s t x y z E F G H A B C D u K J p b k h q l m r n o g v c i a
293 return cls.from_cuda_array_interface(obj, stream_ptr) 1%7|
295 @classmethod
296 def from_buffer(
297 cls,
298 cyBuffer buffer not None : Buffer,
299 shape : tuple[int, ...],
300 strides : tuple[int, ...] | None = None,
301 *,
302 itemsize : int | None = None,
303 dtype : numpy.dtype | None = None,
304 is_readonly : bool = False
305 ) -> StridedMemoryView:
306 """
307 Creates a :obj:`StridedMemoryView` instance from a :obj:`~_memory.Buffer` and shape and strides tuples.
308 The Buffer can be either allocation coming from a :obj:`MemoryResource` or an external allocation
309 wrapped in a :obj:`~_memory.Buffer` object with ``Buffer.from_handle(ptr, size, owner=...)``.
311 .. caution::
312 When creating a :obj:`StridedMemoryView` from a :obj:`~_memory.Buffer`,
313 no synchronization is performed. It is the user's responsibility to ensure
314 the data in ``buffer`` is properly synchronized when consuming the view.
316 Parameters
317 ----------
318 buffer : :obj:`~_memory.Buffer`
319 The buffer to create the view from.
320 shape : :obj:`tuple`
321 The layout describing the shape, strides and itemsize of the elements in
322 the buffer.
323 strides : :obj:`tuple`
324 The layout describing the shape, strides and itemsize of the elements in
325 the buffer.
326 dtype : :obj:`numpy.dtype`
327 Optional dtype.
328 If specified, the dtype's itemsize must match the layout's itemsize.
329 is_readonly : bool, optional
330 Whether the mark the view as readonly.
331 """
332 cdef StridedMemoryView view = StridedMemoryView.__new__(cls) 2^b_bibkbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdchcfcQbRbbc`b' lbOb*
333 if itemsize is None and dtype is None: 2^b_bibkbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdchcfcQbRbbc`b' lbOb*
334 raise ValueError("Either itemsize or dtype must be specified") 2hc
335 if itemsize is not None and dtype is not None and itemsize != dtype.itemsize: 2^b_bibkbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcfcQbRbbc`b' lbOb*
336 raise ValueError( 2fc
337 f"itemsize ({itemsize}) does not match dtype.itemsize ({dtype.itemsize})" 2fc
338 )
339 # (itemsize is None XOR dtype is None) OR they are equal
340 view_buffer_strided( 2^b_bibkbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b' lbOb*
341 view,
342 buffer,
343 _StridedLayout(shape=shape, strides=strides, itemsize=getattr(dtype, "itemsize", itemsize)), 2^b_bibkbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b' lbOb*
344 dtype,
345 is_readonly, 2^b_bibkbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b' lbOb*
346 )
347 return view 2^b_bibkbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbOb*
349 def __dealloc__(self) -> None:
350 if self.dl_tensor == NULL: 2^b_bbb{ } jb: ( ib6 3 % 7 | kb8 9 ! # $ + , - . / ? @ [ ] ^ L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdchcfcQbRbbc`bMb]bNbgbhbw ' ecPbmblb1 cb5 Z dbLbS T U V W X _ ` ; ) = ~ ebfbQ R Ob* @b4 abSbTbUbP Y 0 I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
351 return 2^b_bib% 7 | kbL N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdchcfcQbRbbc`bMb]bNb' ecPbmblbcb5 Z dbLbS T U V W X ebOb* 4 P Y 0 f 2 cce d |b~b}b[bc ac
353 if cpython.PyCapsule_IsValid( 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R @babSbTbUbI s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
354 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME): 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R @babSbTbUbI s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
355 data = cpython.PyCapsule_GetPointer( 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R @babSbTbUbI s t x y z E F G H A B C D u K J p f 2 e d k h q l m r n o v c i a
356 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R @babSbTbUbI s t x y z E F G H A B C D u K J p f 2 e d k h q l m r n o v c i a
357 dlm_tensor_ver = <DLManagedTensorVersioned*>data 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R @babSbTbUbI s t x y z E F G H A B C D u K J p f 2 e d k h q l m r n o v c i a
358 if dlm_tensor_ver.deleter != NULL: 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R @babSbTbUbI s t x y z E F G H A B C D u K J p f 2 e d k h q l m r n o v c i a
359 dlm_tensor_ver.deleter(dlm_tensor_ver) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abI s t x y z E F G H A B C D u K J p f 2 e d k h q l m r n o c i a
360 elif cpython.PyCapsule_IsValid( 1bga
361 self.metadata, DLPACK_TENSOR_USED_NAME): 1bga
362 data = cpython.PyCapsule_GetPointer( 1bga
363 self.metadata, DLPACK_TENSOR_USED_NAME) 1bga
364 dlm_tensor = <DLManagedTensor*>data 1bga
365 if dlm_tensor.deleter != NULL: 1bga
366 dlm_tensor.deleter(dlm_tensor) 1ba
368 def view(
369 self, layout : _StridedLayout | None = None, dtype : numpy.dtype | None = None
370 ) -> StridedMemoryView:
371 """
372 Creates a new view with adjusted layout and dtype.
373 Same as calling :meth:`from_buffer` with the current buffer.
374 """
375 cdef StridedMemoryView view = StridedMemoryView.__new__(self.__class__) 2N O M QbRbcb5 Z S T U V W X 2 c
376 if layout is None and dtype is None: 2N O M QbRbcb5 Z S T U V W X 2 c
377 return self 2cb
378 if layout is None: 2N O M QbRb5 Z S T U V W X 2 c
379 layout = self.get_layout() 1NOM5Z2c
380 if dtype is None: 2N O M QbRb5 Z S T U V W X 2 c
381 dtype = self.get_dtype() 2QbRbS T U V W X
382 view_buffer_strided(view, self.get_buffer(), layout, dtype, self.readonly) 2N O M QbRb5 Z S T U V W X 2 c
383 return view 2N O M QbRbZ S T U V W X 2 c
385 def as_tensor_map(
386 self,
387 box_dim: tuple[int, ...] | None = None,
388 *,
389 options: TensorMapDescriptorOptions | None = None,
390 element_strides: tuple[int, ...] | None = None,
391 data_type: object = None,
392 interleave: object = None,
393 swizzle: object = None,
394 l2_promotion: object = None,
395 oob_fill: object = None,
396 ) -> object:
397 """Create a tiled :obj:`TensorMapDescriptor` from this view.
399 This is the public entry point for creating tiled tensor map
400 descriptors in ``cuda.core``. Pass either ``box_dim`` and the
401 individual keyword arguments directly, or provide bundled tiled
402 options via ``options=``.
403 """
404 from cuda.core._tensor_map import TensorMapDescriptor 2( ib6 3 % 7 | kb
406 kwargs = {} 2( ib6 3 % 7 | kb
407 if options is not None: 2( ib6 3 % 7 | kb
408 kwargs["options"] = options
409 if element_strides is not None: 2( ib6 3 % 7 | kb
410 kwargs["element_strides"] = element_strides 1(63
411 if data_type is not None: 2( ib6 3 % 7 | kb
412 kwargs["data_type"] = data_type 1(63%
413 if interleave is not None: 2( ib6 3 % 7 | kb
414 kwargs["interleave"] = interleave 1(
415 if swizzle is not None: 2( ib6 3 % 7 | kb
416 kwargs["swizzle"] = swizzle 1(
417 if l2_promotion is not None: 2( ib6 3 % 7 | kb
418 kwargs["l2_promotion"] = l2_promotion 1(
419 if oob_fill is not None: 2( ib6 3 % 7 | kb
420 kwargs["oob_fill"] = oob_fill 1(
421 return TensorMapDescriptor._from_tiled(self, box_dim, **kwargs) 2( ib6 3 % 7 | kb
423 def copy_from(
424 self,
425 StridedMemoryView other not None: StridedMemoryView,
426 stream: Stream | None,
427 allocator: object = None,
428 blocking: bool | None = None,
429 ) -> None:
430 """
431 Copies the data from the other view into this view.
433 The copy can be performed between following memory spaces:
434 host-to-device, device-to-host, device-to-device (on the same device).
436 Parameters
437 ----------
438 other : StridedMemoryView
439 The view to copy data from.
440 stream : Stream | None, optional
441 The stream to schedule the copy on.
442 allocator : MemoryResource | None, optional
443 If temporary buffers are needed, the specified memory resources
444 will be used to allocate the memory. If not specified, default
445 resources will be used.
446 blocking : bool | None, optional
447 Whether the call should block until the copy is complete.
448 * ``True``: the ``stream`` is synchronized with the host at the end of the call,
449 blocking until the copy is complete.
450 * ``False``: if possible, the call returns immediately once the copy is scheduled.
451 However, in some cases of host-to-device or device-to-host copies, the call may
452 still synchronize with the host if necessary.
453 * ``None`` (default):
454 * for device-to-device, it defaults to ``False`` (non-blocking),
455 * for host-to-device or device-to-host, it defaults to ``True`` (blocking).
456 """
457 raise NotImplementedError("Sorry, not supported: copy_from") 2gb
459 def copy_to(
460 self,
461 StridedMemoryView other not None: StridedMemoryView,
462 stream: Stream | None = None,
463 allocator: object = None,
464 blocking: bool | None = None,
465 ) -> None:
466 """
467 Copies the data from this view into the ``other`` view.
469 For details, see :meth:`copy_from`.
470 """
471 raise NotImplementedError("Sorry, not supported: copy_to") 2hb
473 def __dlpack__(
474 self,
475 *,
476 stream: int | None = None,
477 max_version: tuple[int, int] | None = None,
478 dl_device: tuple[int, int] | None = None,
479 copy: bool | None = None,
480 ) -> object:
481 # Similar to Buffer.__dlpack__: no implicit synchronization is performed.
482 if dl_device is not None: 1}LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
483 raise BufferError("Sorry, not supported: dl_device other than None") 1}
484 if copy is True: 1}LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
485 raise BufferError("Sorry, not supported: copy=True") 1}
487 cdef bint versioned
488 if max_version is None: 1}LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
489 versioned = False 1LNOM'Jbga
490 else:
491 if not isinstance(max_version, tuple) or len(max_version) != 2: 1}wPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
492 raise BufferError(f"Expected max_version tuple[int, int], got {max_version}") 1}
493 versioned = max_version >= (1, 0) 1wPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
495 # NOTE: stream is accepted for protocol compatibility but not used.
496 cdef object capsule = _smv_make_py_capsule(self, versioned) 1LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
497 return capsule 1LwPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
499 def __dlpack_device__(self) -> tuple[int, int]:
500 cdef _DLDeviceType device_type
501 cdef int32_t device_id
502 _smv_get_dl_device(self, &device_type, &device_id) 2bb{ ib6 3 % 7 kbL w P f e d b k h q l m r n o g v c i a
503 return (<int>device_type, int(device_id)) 2bb{ ib6 3 % 7 kbL w P f e d b k h q l m r n o g v c i a
505 @property
506 def _layout(self) -> _StridedLayout:
507 """
508 The layout of the tensor. For StridedMemoryView created from DLPack or CAI,
509 the layout is inferred from the tensor object's metadata.
510 """
511 return self.get_layout() 2VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRbecZ S T U V W X
513 @property
514 def size(self) -> int:
515 return self.get_layout().get_volume() 28 9 ! # $ + , - . / ? @ [ ] ^ nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbMb
517 @property
518 def shape(self) -> tuple[int, ...]:
519 """
520 Shape of the tensor.
521 """
522 return self.get_layout().get_shape_tuple() 2^b_b: 8 9 ! # $ + , - . / ? @ [ ] ^ nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRbMbNbPbmblb1 dbS T U V W X _ ` ; ) = ~ j b k c i
524 @property
525 def strides(self) -> tuple[int, ...] | None:
526 """
527 Strides of the tensor (in **counts**, not bytes).
528 """
529 return self.get_layout().get_strides_tuple() 2: 8 9 ! # $ + , - . / ? @ [ ] ^ nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bMbNblb1
531 @property
532 def dtype(self) -> numpy.dtype | None:
533 """
534 Data type of the tensor.
536 Supports standard NumPy dtypes as well as narrow data types (e.g., ``bfloat16``)
537 when the optional `ml_dtypes <https://github.com/jax-ml/ml_dtypes>`_ package is
538 installed. If ``ml_dtypes`` is not available and such a tensor is encountered,
539 a :obj:`NotImplementedError` will be raised.
540 """
541 return self.get_dtype() 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b`blb1 Z S T U V W X Y 0 h q l m r n o
543 def __repr__(self) -> str:
544 return (f"StridedMemoryView(ptr={self.ptr},\n" 2lb1
545 + f" shape={self.shape},\n" 2lb1
546 + f" strides={self.strides},\n" 2lb1
547 + f" itemsize={self._layout.itemsize},\n" 2lb1
548 + f" dtype={get_simple_repr(self.dtype)},\n" 2lb1
549 + f" device_id={self.device_id},\n" 2lb1
550 + f" is_device_accessible={self.is_device_accessible},\n" 2lb1
551 + f" readonly={self.readonly},\n" 2lb1
552 + f" exporting_obj={get_simple_repr(self.exporting_obj)})") 2lb1
554 @cython.critical_section
555 cdef inline _StridedLayout get_layout(self):
556 cdef _StridedLayout layout
557 if self._layout is None: 2^b_b: 6 3 % 7 | kb8 9 ! # $ + , - . / ? @ [ ] ^ L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRbMb]bNbw ' ecPbmblb1 5 Z dbLbS T U V W X _ ` ; ) = ~ ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
558 if self.dl_tensor: 2: 6 3 % 7 | 8 9 ! # $ + , - . / ? @ [ ] ^ L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbw ecPbmb1 5 Z dbLbS T U V W X _ ` ; ) = ~ ebQ R 4 j P Y 0 I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
559 layout = layout_from_dlpack(self.dl_tensor) 1:6389!#$+,-./?@[]^NOMw15ZSTUVWX_`;)=~QRjIstxyzEFGHABCDuKJp2edbkhqlmrnogvcia
560 elif self.metadata is not None: 2% 7 | L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbecPbmbdbLbeb4 P Y 0 f e d
561 layout = layout_from_cai(self.metadata) 2% 7 | L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbPbmbdbLbeb4 P Y 0 f e d
562 else:
563 raise ValueError("Cannot infer layout from the exporting object") 2ec
564 if self._layout is None: 2: 6 3 % 7 | 8 9 ! # $ + , - . / ? @ [ ] ^ L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbMbNbw Pbmb1 5 Z dbLbS T U V W X _ ` ; ) = ~ ebQ R 4 j P Y 0 I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
565 self._layout = layout 2: 6 3 % 7 | 8 9 ! # $ + , - . / ? @ [ ] ^ L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbMbNbw Pbmb1 5 Z dbLbS T U V W X _ ` ; ) = ~ ebQ R 4 j P Y 0 I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
566 return self._layout 2^b_b: 6 3 % 7 | kb8 9 ! # $ + , - . / ? @ [ ] ^ L N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRbMbNbw ' Pbmblb1 5 Z dbLbS T U V W X _ ` ; ) = ~ ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
568 @cython.critical_section
569 cdef inline object get_buffer(self):
570 """
571 Returns Buffer instance with the underlying data.
572 If the SMV was created from a Buffer, it will return the same Buffer instance.
573 Otherwise, it will create a new instance with owner set to the exporting object.
574 """
575 cdef object buffer
576 if self._buffer is None: 2ib% 7 kbL N O M QbRb5 Z S T U V W X 2 c
577 if isinstance(self.exporting_obj, Buffer): 1%7LNOM5ZSTUVWX2c
578 buffer = self.exporting_obj 12
579 else:
580 buffer = Buffer.from_handle(self.ptr, 0, owner=self.exporting_obj) 1%7LNOM5ZSTUVWXc
581 if self._buffer is None: 1%7LNOM5ZSTUVWX2c
582 self._buffer = buffer 1%7LNOM5ZSTUVWX2c
583 return self._buffer 2ib% 7 kbL N O M QbRb5 Z S T U V W X 2 c
585 @cython.critical_section
586 cdef inline object get_dtype(self):
587 cdef object dtype
588 if self._dtype is None: 2ib7 kbL N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`bw ' lb1 Z S T U V W X ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
589 dtype = None 2ib7 L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbw ' lb1 S T U V W X ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
590 if self.dl_tensor != NULL: 2ib7 L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbw ' lb1 S T U V W X ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
591 dtype = dtype_dlpack_to_numpy(&self.dl_tensor.dtype) 1w1STUVWXQRjIstxyzEFGHABCDuKJpedbkhqlmrnogvcia
592 elif isinstance(self.metadata, int): 2ib7 L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb' lbebOb* 4 P Y 0 f e d
593 # AOTI dtype code stored by the torch tensor bridge
594 dtype = _get_tensor_bridge().resolve_aoti_dtype(
595 self.metadata)
596 elif self.metadata is not None: 2ib7 L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb' lbebOb* 4 P Y 0 f e d
597 dtype = _typestr2dtype(self.metadata["typestr"]) 27 L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbeb4 P Y 0 f e d
598 if self._dtype is None: 2ib7 L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbw ' lb1 S T U V W X ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
599 self._dtype = dtype 2ib7 L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbw ' lb1 S T U V W X ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
600 return self._dtype 2ib7 kbL N O M nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`bw ' lb1 Z S T U V W X ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
603cdef void _smv_pycapsule_deleter(object capsule) noexcept:
604 cdef DLManagedTensor* dlm_tensor
605 cdef DLManagedTensorVersioned* dlm_tensor_ver
606 # Do not invoke the deleter on a used capsule.
607 if cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME): 2L w @bSbTbUbP I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o c i a
608 dlm_tensor = <DLManagedTensor*>( 1LJ
609 cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME) 1LJ
610 )
611 if dlm_tensor.deleter: 1LJ
612 dlm_tensor.deleter(dlm_tensor) 1LJ
613 elif cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 2w @bSbTbUbP I s t x y z E F G H A B C D u K p f e d b k h q l m r n o c i a
614 dlm_tensor_ver = <DLManagedTensorVersioned*>( 1p
615 cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 1p
616 )
617 if dlm_tensor_ver.deleter: 1p
618 dlm_tensor_ver.deleter(dlm_tensor_ver) 1p
621cdef inline void _smv_release_export_resources(void* manager_ctx, int64_t* shape_ptr) noexcept with gil:
622 if shape_ptr: 1LNOMw'*4PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
623 stdlib.free(shape_ptr) 1LwPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
624 if manager_ctx: 1LNOMw'*4PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
625 cpython.Py_DECREF(<object>manager_ctx) 1LNOMw'*4PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
628cdef void _smv_deleter(DLManagedTensor* tensor) noexcept with gil:
629 if tensor: 1LNOM'Y0Jbga
630 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1LNOM'Jbga
631 tensor.manager_ctx = NULL 1LNOM'Jbga
632 stdlib.free(tensor) 1LNOM'Jbga
635cdef void _smv_versioned_deleter(DLManagedTensorVersioned* tensor) noexcept with gil:
636 if tensor: 1NOMw'*4PY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
637 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1w*4PY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
638 tensor.manager_ctx = NULL 1w*4PY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
639 stdlib.free(tensor) 1w*4PY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
642cdef inline DLManagedTensorVersioned* _smv_allocate_dlm_tensor_versioned() except? NULL:
643 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
644 dlm_tensor_ver = <DLManagedTensorVersioned*>stdlib.malloc(sizeof(DLManagedTensorVersioned)) 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
645 if dlm_tensor_ver == NULL: 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
646 raise MemoryError()
647 dlm_tensor_ver.dl_tensor.shape = NULL 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
648 dlm_tensor_ver.manager_ctx = NULL 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
649 return dlm_tensor_ver 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
652cdef inline DLManagedTensor* _smv_allocate_dlm_tensor() except? NULL:
653 cdef DLManagedTensor* dlm_tensor = NULL 1LNOM'Jbga
654 dlm_tensor = <DLManagedTensor*>stdlib.malloc(sizeof(DLManagedTensor)) 1LNOM'Jbga
655 if dlm_tensor == NULL: 1LNOM'Jbga
656 raise MemoryError()
657 dlm_tensor.dl_tensor.shape = NULL 1LNOM'Jbga
658 dlm_tensor.manager_ctx = NULL 1LNOM'Jbga
659 return dlm_tensor 1LNOM'Jbga
662cdef inline int _smv_dtype_numpy_to_dlpack(object dtype_obj, DLDataType* out_dtype) except -1:
663 cdef object np_dtype = numpy.dtype(dtype_obj) 2L N O M w ebQ R 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
664 if np_dtype.fields is not None: 2L N O M w ebQ R 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
665 raise BufferError("Structured dtypes are not supported for DLPack export") 1O
666 if not np_dtype.isnative and np_dtype.byteorder not in ("=", "|"): 2L N M w ebQ R 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
667 raise BufferError("Non-native-endian dtypes are not supported for DLPack export") 2N eb4
669 cdef str kind = np_dtype.kind 1LMwQRjPY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
670 cdef int bits = np_dtype.itemsize * 8 1LMwQRjPY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
671 cdef uint8_t code
672 if kind == "b": 1LMwQRjPY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
673 if bits != 8: 1I
674 raise BufferError(f"Unsupported bool dtype itemsize: {np_dtype.itemsize}")
675 code = <uint8_t>kDLBool 1I
676 elif kind == "i": 1LMwQRjPY0stxyzEFGHABCDuKJpfedbkhqlmrnogvcia
677 if bits not in (8, 16, 32, 64): 1wQRPEFGHJpfbkhqlmrnogvcia
678 raise BufferError(f"Unsupported signed integer dtype: {np_dtype}")
679 code = <uint8_t>kDLInt 1wQRPEFGHJpfbkhqlmrnogvcia
680 elif kind == "u": 1LMjY0stxyzABCDuKed
681 if bits not in (8, 16, 32, 64): 1ABCD
682 raise BufferError(f"Unsupported unsigned integer dtype: {np_dtype}")
683 code = <uint8_t>kDLUInt 1ABCD
684 elif kind == "f": 1LMjY0stxyzuKed
685 if bits not in (16, 32, 64): 1Lj0xyzed
686 raise BufferError(f"Unsupported floating dtype: {np_dtype}") 10
687 code = <uint8_t>kDLFloat 1Ljxyzed
688 elif kind == "c": 1MYstuK
689 if bits not in (64, 128): 1YstuK
690 raise BufferError(f"Unsupported complex dtype: {np_dtype}") 1Y
691 code = <uint8_t>kDLComplex 1stuK
692 else:
693 raise BufferError(f"Unsupported dtype for DLPack export: {np_dtype}") 1M
695 out_dtype.code = code 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
696 out_dtype.bits = <uint8_t>bits 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
697 out_dtype.lanes = <uint16_t>1 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
698 return 0 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
701cdef inline int _smv_get_dl_device(
702 StridedMemoryView view,
703 _DLDeviceType* out_device_type,
704 int32_t* out_device_id,
705) except -1:
706 cdef _DLDeviceType device_type
707 cdef int32_t device_id
708 cdef object buf
709 if view.dl_tensor != NULL: 2bb{ ib6 3 % 7 kbL w Q R j P I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
710 device_type = view.dl_tensor.device.device_type 2bb{ 6 3 w Q R j I s t x y z E F G H A B C D u K J p e d b k h q l m r n o g v c i a
711 if device_type == _kDLCUDA: 2bb{ 6 3 w Q R j I s t x y z E F G H A B C D u K J p e d b k h q l m r n o g v c i a
712 device_id = view.dl_tensor.device.device_id 163
713 else:
714 # CPU, CUDAHost, and CUDAManaged use device_id=0 in DLPack.
715 device_id = 0 2bb{ w Q R j I s t x y z E F G H A B C D u K J p e d b k h q l m r n o g v c i a
716 elif view.is_device_accessible: 2ib% 7 kbL P f e d
717 buf = view.get_buffer() 2ib% 7 kbL
718 dev_type, dev_id = classify_dl_device(buf) 2ib% 7 kbL
719 device_type = <_DLDeviceType>dev_type 2ib% 7 kbL
720 device_id = <int32_t>dev_id 2ib% 7 kbL
721 else:
722 device_type = _kDLCPU 1Pfed
723 device_id = 0 1Pfed
725 out_device_type[0] = device_type 2bb{ ib6 3 % 7 kbL w Q R j P I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
726 out_device_id[0] = device_id 2bb{ ib6 3 % 7 kbL w Q R j P I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
727 return 0 2bb{ ib6 3 % 7 kbL w Q R j P I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
730cdef inline int _smv_setup_dl_tensor_common(
731 DLTensor* dl_tensor,
732 StridedMemoryView view,
733 _StridedLayout layout,
734) except -1:
735 cdef object dtype_obj = view.get_dtype() 2L N O M w ' ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
736 if dtype_obj is None: 2L N O M w ' ebQ R Ob* 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
737 raise BufferError( 2' Ob*
738 "Cannot export StridedMemoryView via DLPack without dtype information; "
739 "create the view with dtype specified."
740 )
741 _smv_dtype_numpy_to_dlpack(dtype_obj, &dl_tensor.dtype) 2L N O M w ebQ R 4 j P Y 0 I s t x y z E F G H A B C D u K J p f e d b k h q l m r n o g v c i a
742 _smv_get_dl_device(view, &dl_tensor.device.device_type, &dl_tensor.device.device_id) 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
744 cdef int ndim = layout.base.ndim 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
745 dl_tensor.ndim = ndim 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
746 if layout.get_volume() == 0: 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
747 dl_tensor.data = NULL 1u
748 else:
749 dl_tensor.data = <void*><intptr_t>view.ptr 1LwQRjPIstxyzEFGHABCDKJpfedbkhqlmrnogvcia
750 dl_tensor.byte_offset = 0 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
751 return 0 1LwQRjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
754cdef inline int _smv_setup_dl_tensor(DLTensor* dl_tensor, StridedMemoryView view) except -1:
755 cdef _StridedLayout layout = view.get_layout() 1LNOMw'*4jPY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
756 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1LNOMw'*4jPY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
758 cdef int i
759 cdef int64_t* shape_strides = NULL 1LwjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
760 cdef int64_t* strides_src = NULL 1LwjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
761 cdef int ndim = dl_tensor.ndim 1LwjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
762 if ndim == 0: 1LwjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
763 dl_tensor.shape = NULL 1K
764 dl_tensor.strides = NULL 1K
765 else:
766 # DLPack v1.2+ requires non-NULL strides for ndim != 0.
767 shape_strides = <int64_t*>stdlib.malloc(sizeof(int64_t) * 2 * ndim) 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
768 if shape_strides == NULL: 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
769 raise MemoryError()
770 try: 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
771 strides_src = get_strides_ptr(layout.base) 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
772 for i in range(ndim): 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
773 shape_strides[i] = layout.base.shape[i] 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
774 shape_strides[i + ndim] = strides_src[i] 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
775 except Exception:
776 stdlib.free(shape_strides)
777 raise
778 dl_tensor.shape = shape_strides 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
779 dl_tensor.strides = shape_strides + ndim 1LwjPIstxyzEFGHABCDuJpfedbkhqlmrnogvcia
780 return 0 1LwjPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
783cdef inline int _smv_setup_dltensor_borrowed(DLTensor* dl_tensor, StridedMemoryView view) except -1:
784 cdef _StridedLayout layout = view.get_layout() 2ebQ R Ob
785 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 2ebQ R Ob
787 if dl_tensor.ndim == 0: 1QR
788 dl_tensor.shape = NULL 1Q
789 dl_tensor.strides = NULL 1Q
790 else:
791 dl_tensor.shape = layout.base.shape 1R
792 # For temporary/non-owning exchange we provide explicit strides.
793 dl_tensor.strides = get_strides_ptr(layout.base) 1R
794 return 0 1QR
797cdef inline int _smv_fill_managed_tensor_versioned(
798 DLManagedTensorVersioned* dlm_tensor_ver,
799 StridedMemoryView view,
800) except -1:
801 cpython.Py_INCREF(view) 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
802 dlm_tensor_ver.manager_ctx = <void*>view 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
803 dlm_tensor_ver.deleter = _smv_versioned_deleter 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
804 dlm_tensor_ver.version.major = DLPACK_MAJOR_VERSION 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
805 dlm_tensor_ver.version.minor = DLPACK_MINOR_VERSION 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
806 dlm_tensor_ver.flags = DLPACK_FLAG_BITMASK_READ_ONLY if view.readonly else 0 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
807 _smv_setup_dl_tensor(&dlm_tensor_ver.dl_tensor, view) 1w*4jPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
808 return 0 1wjPIstxyzEFGHABCDuKpfedbkhqlmrnovcia
811cdef inline int _smv_fill_managed_tensor(
812 DLManagedTensor* dlm_tensor,
813 StridedMemoryView view,
814) except -1:
815 cpython.Py_INCREF(view) 1LNOM'Jbga
816 dlm_tensor.manager_ctx = <void*>view 1LNOM'Jbga
817 dlm_tensor.deleter = _smv_deleter 1LNOM'Jbga
818 _smv_setup_dl_tensor(&dlm_tensor.dl_tensor, view) 1LNOM'Jbga
819 return 0 1LJbga
822cdef object _smv_make_py_capsule(StridedMemoryView view, bint versioned):
823 cdef DLManagedTensor* dlm_tensor = NULL 1LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
824 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
825 cdef object capsule = None 1LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
826 cdef void* tensor_ptr = NULL 1LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
827 cdef const char* capsule_name
828 try: 1LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
829 if versioned: 1LNOMw'PY0IstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
830 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1wPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
831 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, view) 1wPY0IstxyzEFGHABCDuKpfedbkhqlmrnovcia
832 tensor_ptr = <void*>dlm_tensor_ver 1wPIstxyzEFGHABCDuKpfedbkhqlmrnovcia
833 capsule_name = DLPACK_VERSIONED_TENSOR_UNUSED_NAME 1wPIstxyzEFGHABCDuKpfedbkhqlmrnovcia
834 else:
835 dlm_tensor = _smv_allocate_dlm_tensor() 1LNOM'Jbga
836 _smv_fill_managed_tensor(dlm_tensor, view) 1LNOM'Jbga
837 tensor_ptr = <void*>dlm_tensor 1LJbga
838 capsule_name = DLPACK_TENSOR_UNUSED_NAME 1LJbga
839 capsule = cpython.PyCapsule_New(tensor_ptr, capsule_name, _smv_pycapsule_deleter) 1LwPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
840 except Exception: 1NOM'Y0
841 if capsule is None: 1NOM'Y0
842 _smv_deleter(dlm_tensor) 1NOM'Y0
843 _smv_versioned_deleter(dlm_tensor_ver) 1NOM'Y0
844 raise 1NOM'Y0
845 return capsule 1LwPIstxyzEFGHABCDuKJpfedbkhqlmrnogvcia
848cdef inline StridedMemoryView _smv_from_dlpack_capsule(object capsule, object exporting_obj):
849 cdef void* data = NULL 2@bj SbTbUb
850 cdef DLTensor* dl_tensor = NULL 2@bj SbTbUb
851 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 2@bj SbTbUb
852 cdef DLManagedTensor* dlm_tensor = NULL 2@bj SbTbUb
853 cdef bint is_readonly = False 2@bj SbTbUb
854 cdef const char* used_name = NULL 2@bj SbTbUb
855 if cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 2@bj SbTbUb
856 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 2@bj SbTbUb
857 dlm_tensor_ver = <DLManagedTensorVersioned*>data 2@bj SbTbUb
858 dl_tensor = &dlm_tensor_ver.dl_tensor 2@bj SbTbUb
859 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 2@bj SbTbUb
860 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 2@bj SbTbUb
861 elif cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME):
862 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME)
863 dlm_tensor = <DLManagedTensor*>data
864 dl_tensor = &dlm_tensor.dl_tensor
865 is_readonly = False
866 used_name = DLPACK_TENSOR_USED_NAME
867 else:
868 raise BufferError("Invalid DLPack capsule")
870 cpython.PyCapsule_SetName(capsule, used_name) 2@bj SbTbUb
872 cdef StridedMemoryView view = StridedMemoryView.__new__(StridedMemoryView) 2@bj SbTbUb
873 view.dl_tensor = dl_tensor 2@bj SbTbUb
874 view.metadata = capsule 2@bj SbTbUb
875 view.ptr = <intptr_t>(dl_tensor.data) + <intptr_t>(dl_tensor.byte_offset) 2@bj SbTbUb
876 view.readonly = is_readonly 2@bj SbTbUb
877 view.exporting_obj = exporting_obj 2@bj SbTbUb
878 if dl_tensor.device.device_type == _kDLCPU: 2@bj SbTbUb
879 view.device_id = -1 1j
880 view.is_device_accessible = False 1j
881 elif dl_tensor.device.device_type in (_kDLCUDA, _kDLCUDAHost, _kDLCUDAManaged): 2Sb
882 view.device_id = dl_tensor.device.device_id 2SbTbUb
883 view.is_device_accessible = True 2SbTbUb
884 else:
885 raise BufferError("device not supported") 2@b
886 return view 2j SbTbUb
889cdef int _smv_managed_tensor_allocator(
890 DLTensor* prototype,
891 DLManagedTensorVersioned** out,
892 void* error_ctx,
893 void (*SetError)(void* error_ctx, const char* kind, const char* message) noexcept,
894) noexcept with gil:
895 if out != NULL: 2ic
896 out[0] = NULL 2ic
897 if SetError != NULL: 2ic
898 SetError(error_ctx, b"NotImplementedError", b"managed_tensor_allocator is not supported by StridedMemoryView")
899 cpython.PyErr_SetString(NotImplementedError, b"managed_tensor_allocator is not supported by StridedMemoryView") 2ic
900 return -1 2ic
903cdef int _smv_managed_tensor_from_py_object_no_sync(
904 void* py_object,
905 DLManagedTensorVersioned** out,
906) except -1 with gil:
907 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 2* 4 abj
908 if out == NULL: 2* 4 abj
909 raise RuntimeError("out cannot be NULL") 2ab
910 out[0] = NULL 2* 4 abj
911 cdef object obj = <object>py_object 2* 4 abj
912 if not isinstance(obj, StridedMemoryView): 2* 4 abj
913 raise TypeError("py_object must be a StridedMemoryView") 2ab
914 try: 1*4j
915 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1*4j
916 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, <StridedMemoryView>obj) 1*4j
917 except BaseException: 1*4
918 # Rollback must also run for KeyboardInterrupt.
919 _smv_versioned_deleter(dlm_tensor_ver) 1*4
920 raise 1*4
921 out[0] = dlm_tensor_ver 1j
922 return 0 1j
925cdef int _smv_managed_tensor_to_py_object_no_sync(
926 DLManagedTensorVersioned* tensor,
927 void** out_py_object,
928) except -1 with gil:
929 if out_py_object == NULL: 2@bj SbTbUbuclc
930 raise RuntimeError("out_py_object cannot be NULL") 2uc
931 out_py_object[0] = NULL 2@bj SbTbUblc
932 if tensor == NULL: 2@bj SbTbUblc
933 raise RuntimeError("tensor cannot be NULL") 2lc
934 cdef object capsule = cpython.PyCapsule_New( 2@bj SbTbUb
935 <void*>tensor,
936 DLPACK_VERSIONED_TENSOR_UNUSED_NAME,
937 _smv_pycapsule_deleter,
938 )
939 cdef object py_view = _smv_from_dlpack_capsule(capsule, capsule) 2@bj SbTbUb
940 cpython.Py_INCREF(py_view) 2j SbTbUb
941 out_py_object[0] = <void*>py_view 2j SbTbUb
942 return 0 2j SbTbUb
945cdef int _smv_dltensor_from_py_object_no_sync(
946 void* py_object,
947 DLTensor* out,
948) except -1 with gil:
949 if out == NULL: 2ebfbQ mcR Ob
950 raise RuntimeError("out cannot be NULL") 2fb
951 cdef object obj = <object>py_object 2ebQ mcR Ob
952 if not isinstance(obj, StridedMemoryView): 2ebQ mcR Ob
953 raise TypeError("py_object must be a StridedMemoryView") 2mc
954 _smv_setup_dltensor_borrowed(out, <StridedMemoryView>obj) 2ebQ R Ob
955 return 0 1QR
958cdef int _smv_current_work_stream(
959 _DLDeviceType device_type,
960 int32_t device_id,
961 void** out_current_stream,
962) except -1 with gil:
963 if out_current_stream == NULL: 2vcpc
964 raise RuntimeError("out_current_stream cannot be NULL") 2vc
965 # cuda.core has no global/current stream state today.
966 out_current_stream[0] = NULL 2pc
967 return 0 2pc
970cdef void _init_smv_dlpack_exchange_api():
971 global _SMV_DLPACK_EXCHANGE_API_INITED
972 if _SMV_DLPACK_EXCHANGE_API_INITED:
973 return
974 _SMV_DLPACK_EXCHANGE_API.header.version.major = DLPACK_MAJOR_VERSION
975 _SMV_DLPACK_EXCHANGE_API.header.version.minor = DLPACK_MINOR_VERSION
976 _SMV_DLPACK_EXCHANGE_API.header.prev_api = NULL
977 _SMV_DLPACK_EXCHANGE_API.managed_tensor_allocator = _smv_managed_tensor_allocator
978 _SMV_DLPACK_EXCHANGE_API.managed_tensor_from_py_object_no_sync = _smv_managed_tensor_from_py_object_no_sync
979 _SMV_DLPACK_EXCHANGE_API.managed_tensor_to_py_object_no_sync = _smv_managed_tensor_to_py_object_no_sync
980 _SMV_DLPACK_EXCHANGE_API.dltensor_from_py_object_no_sync = _smv_dltensor_from_py_object_no_sync
981 _SMV_DLPACK_EXCHANGE_API.current_work_stream = _smv_current_work_stream
982 _SMV_DLPACK_EXCHANGE_API_INITED = True
985_init_smv_dlpack_exchange_api()
986# cdef classes are immutable types in Cython 3, so inject these attributes
987# directly into the type dict.
988(<dict>(<PyTypeObject*>StridedMemoryView).tp_dict)["__dlpack_c_exchange_api__"] = _SMV_DLPACK_EXCHANGE_API_CAPSULE
989(<dict>(<PyTypeObject*>StridedMemoryView).tp_dict)["__c_dlpack_exchange_api__"] = _SMV_DLPACK_EXCHANGE_API_CAPSULE
990PyType_Modified(<PyTypeObject*>StridedMemoryView)
993cdef str get_simple_repr(obj):
994 # TODO: better handling in np.dtype objects
995 cdef object obj_class
996 cdef str obj_repr
997 if isinstance(obj, type): 2lb1
998 obj_class = obj
999 else:
1000 obj_class = obj.__class__ 2lb1
1001 if obj_class.__module__ in (None, "builtins"): 2lb1
1002 obj_repr = obj_class.__name__ 2lb
1003 else:
1004 obj_repr = f"{obj_class.__module__}.{obj_class.__name__}" 2lb1
1005 return obj_repr 2lb1
1009cdef bint check_has_dlpack(obj) except*:
1010 cdef bint has_dlpack
1011 if hasattr(obj, "__dlpack__") and hasattr(obj, "__dlpack_device__"): 2bb{ } jb: ( 6 3 % 7 | 8 9 ! # $ + , - . / ? @ [ ] ^ kcN O M gbhbw Pbgcmb1 cb5 Z _ ` ; ) fbQ R abj I s t x y z E F G H A B C D u K J p b k h q l m r n o g v c i a
1012 has_dlpack = True 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z _ ` ; ) fbQ R abj I s t x y z E F G H A B C D u K J p b k h q l m r n o g v c i a
1013 elif hasattr(obj, "__cuda_array_interface__"): 2% 7 | kcPbgcmb
1014 has_dlpack = False 2% 7 | Pbgcmb
1015 else:
1016 raise BufferError( 2kc
1017 "the input object does not support any data exchange protocol")
1018 return has_dlpack 2bb{ } jb: ( 6 3 % 7 | 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw Pbgcmb1 cb5 Z _ ` ; ) fbQ R abj I s t x y z E F G H A B C D u K J p b k h q l m r n o g v c i a
1021cdef class _StridedMemoryViewProxy:
1022 cdef readonly:
1023 object obj
1024 bint has_dlpack
1026 def __init__(self, obj: object) -> None:
1027 self.obj = obj 28 9 ! # $ gcmb
1028 self.has_dlpack = check_has_dlpack(obj) 28 9 ! # $ gcmb
1030 cpdef StridedMemoryView view(self, stream_ptr=None):
1031 if self.has_dlpack: 28 9 ! # $ mb
1032 return StridedMemoryView.from_dlpack(self.obj, stream_ptr) 189!#$
1033 else:
1034 return StridedMemoryView.from_cuda_array_interface(self.obj, stream_ptr) 2mb
1037cdef StridedMemoryView view_as_dlpack(obj, stream_ptr, view=None):
1038 cdef int dldevice, device_id
1039 cdef bint is_device_accessible, is_readonly = False 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
1040 is_device_accessible = False 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
1041 # Callers may pass an int-convertible stream wrapper (e.g. numba-cuda's
1042 # CUstream). Normalize it so the -1 and truthiness checks below see an int.
1043 if stream_ptr is not None: 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
1044 stream_ptr = int(stream_ptr) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 b k h q l m r n o g v ~b}b[bc i a ac
1045 dldevice, device_id = obj.__dlpack_device__() 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
1046 if dldevice == _kDLCPU: 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 cce d |bb k h q l m r n o g v ~b}b[bc i a ac
1047 if device_id != 0: 2} jb: ( 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f ccb k h q l m r n o g v ~b[bc i a
1048 raise ValueError(f"__dlpack_device__() reported device_id {device_id} for a kDLCPU tensor; expected 0") 2~b
1049 device_id = -1 2} jb: ( 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f ccb k h q l m r n o g v [bc i a
1050 if stream_ptr is None: 2} jb: ( 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f ccb k h q l m r n o g v [bc i a
1051 raise BufferError("stream=None is ambiguous with view()") 2cc
1052 elif stream_ptr == -1: 2} jb: ( 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f b k h q l m r n o g v [bc i a
1053 stream_ptr = None 2} jb: ( 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ; = fbQ R abj I s t x y z E F G H A B C D u K J p f b k h q l m r n o g v [bc i a
1054 elif dldevice == _kDLCUDA:
1055 if device_id < 0: 26 3 2 |b}b
1056 raise ValueError( 2}b
1057 f"__dlpack_device__() reported device_id {device_id} for a kDLCUDA tensor; expected 0 or more") 2}b
1058 is_device_accessible = True 26 3 2 |b
1059 # no need to check other stream values, it's a pass-through
1060 if stream_ptr is None: 26 3 2 |b
1061 raise BufferError("stream=None is ambiguous with view()") 2|b
1062 elif dldevice in (_kDLCUDAHost, _kDLCUDAManaged): 1e
1063 is_device_accessible = True 2bb{ e d
1064 # just do a pass-through without any checks, as pinned/managed memory can be
1065 # accessed on both host and device
1066 else:
1067 raise BufferError("device not supported") 2ac
1069 cdef object capsule
1070 try: 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v [bc i a
1071 capsule = obj.__dlpack__( 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v [bc i a
1072 stream=int(stream_ptr) if stream_ptr else None, 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v [bc i a
1073 max_version=(DLPACK_MAJOR_VERSION, DLPACK_MINOR_VERSION)) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v [bc i a
1074 except TypeError: 1bga
1075 capsule = obj.__dlpack__( 1bga
1076 stream=int(stream_ptr) if stream_ptr else None) 1bga
1078 cdef void* data = NULL 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v [bc i a
1079 cdef DLTensor* dl_tensor = NULL 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v [bc i a
1080 cdef DLManagedTensorVersioned* dlm_tensor_ver
1081 cdef DLManagedTensor* dlm_tensor
1082 cdef const char *used_name = NULL 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v [bc i a
1083 if cpython.PyCapsule_IsValid( 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v [bc i a
1084 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME):
1085 data = cpython.PyCapsule_GetPointer( 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1086 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME)
1087 dlm_tensor_ver = <DLManagedTensorVersioned*>data 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1088 dl_tensor = &dlm_tensor_ver.dl_tensor 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1089 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1090 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1091 elif cpython.PyCapsule_IsValid( 2b g [ba
1092 capsule, DLPACK_TENSOR_UNUSED_NAME):
1093 data = cpython.PyCapsule_GetPointer( 1bga
1094 capsule, DLPACK_TENSOR_UNUSED_NAME)
1095 dlm_tensor = <DLManagedTensor*>data 1bga
1096 dl_tensor = &dlm_tensor.dl_tensor 1bga
1097 is_readonly = False 1bga
1098 used_name = DLPACK_TENSOR_USED_NAME 1bga
1099 else:
1100 raise ValueError(f"__dlpack__() returned {capsule!r}, not an unconsumed DLPack capsule") 2[b
1102 cpython.PyCapsule_SetName(capsule, used_name) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1104 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1105 buf.dl_tensor = dl_tensor 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1106 buf.metadata = capsule 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1107 buf.ptr = <intptr_t>(dl_tensor.data) + <intptr_t>(dl_tensor.byte_offset) 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1108 buf.device_id = device_id 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1109 buf.is_device_accessible = is_device_accessible 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1110 buf.readonly = is_readonly 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1111 buf.exporting_obj = obj 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1113 return buf 2bb{ } jb: ( 6 3 8 9 ! # $ + , - . / ? @ [ ] ^ N O M gbhbw 1 cb5 Z S T U V W X _ ` ; ) = ~ fbQ R abj I s t x y z E F G H A B C D u K J p f 2 e d b k h q l m r n o g v c i a
1116@functools.lru_cache
1117def _typestr2dtype(str typestr) -> numpy.dtype:
1118 return numpy.dtype(typestr) 27 | nbobpbqbrbsbtbubvbwb4 P Y 0 d
1121@functools.lru_cache
1122def _typestr2itemsize(str typestr) -> int:
1123 return _typestr2dtype(typestr).itemsize 27 | nbobpbqbrbsbtbubvbwb4 P Y 0 d
1126cdef object dtype_dlpack_to_numpy(DLDataType* dtype):
1127 cdef int bits = dtype.bits 1w1STUVWXQRjIstxyzEFGHABCDuKJpedbkhqlmrnogvcia
1128 if dtype.lanes != 1: 1w1STUVWXQRjIstxyzEFGHABCDuKJpedbkhqlmrnogvcia
1129 # TODO: return a NumPy structured dtype?
1130 raise NotImplementedError( 1n
1131 f'vector dtypes (lanes={dtype.lanes}) is not supported') 1n
1132 if dtype.code == kDLUInt: 1w1STUVWXQRjIstxyzEFGHABCDuKJpedbkhqlmrnogvcia
1133 if bits == 8: 1ABCDo
1134 np_dtype = numpy.uint8 1A
1135 elif bits == 16:
1136 np_dtype = numpy.uint16 1B
1137 elif bits == 32:
1138 np_dtype = numpy.uint32 1C
1139 elif bits == 64:
1140 np_dtype = numpy.uint64 1D
1141 else:
1142 raise TypeError('uint{} is not supported.'.format(bits)) 1o
1143 elif dtype.code == kDLInt:
1144 if bits == 8: 1w1STUVWXQREFGHJpbkhqlmrnogvcia
1145 np_dtype = numpy.int8 1E
1146 elif bits == 16:
1147 np_dtype = numpy.int16 1QF
1148 elif bits == 32:
1149 np_dtype = numpy.int32 1w1STUVWXRGJpbkhqlmrnogvcia
1150 elif bits == 64:
1151 np_dtype = numpy.int64 1H
1152 else:
1153 raise TypeError('int{} is not supported.'.format(bits)) 1r
1154 elif dtype.code == kDLFloat:
1155 if bits == 16: 1jxyzedm
1156 np_dtype = numpy.float16 1x
1157 elif bits == 32:
1158 np_dtype = numpy.float32 1yed
1159 elif bits == 64:
1160 np_dtype = numpy.float64 1jz
1161 else:
1162 raise TypeError('float{} is not supported.'.format(bits)) 1m
1163 elif dtype.code == kDLComplex:
1164 # TODO(leofang): support complex32
1165 if bits == 64: 1stuKl
1166 np_dtype = numpy.complex64 1s
1167 elif bits == 128:
1168 np_dtype = numpy.complex128 1tuK
1169 else:
1170 raise TypeError('complex{} is not supported.'.format(bits)) 1l
1171 elif dtype.code == kDLBool:
1172 if bits == 8: 1Ih
1173 np_dtype = numpy.bool_ 1I
1174 else:
1175 raise TypeError(f'{bits}-bit bool is not supported') 1h
1176 elif dtype.code == kDLBfloat:
1177 if bfloat16 is not None:
1178 np_dtype = numpy.dtype("bfloat16")
1179 else:
1180 raise NotImplementedError(
1181 'Support for bfloat16 within cuda-core requires `ml_dtypes`'
1182 'to be installed.'
1183 )
1184 else:
1185 raise TypeError('Unsupported dtype. dtype code: {}'.format(dtype.code)) 1q
1187 # We want the dtype object not just the type object
1188 return numpy.dtype(np_dtype) 1w1STUVWXQRjIstxyzEFGHABCDuKJpedbkhqlmrnogvcia
1191cpdef StridedMemoryView view_as_cai(obj, stream_ptr, view=None):
1192 cdef dict cai_data = obj.__cuda_array_interface__ 2% 7 | ncjcqcrcL Mb]bNbPbmbdbLb
1193 if cai_data.get("version", 0) < 3: 2% 7 | ncjcqcrcL Mb]bNbPbmbdbLb
1194 raise BufferError("only CUDA Array Interface v3 or above is supported") 2qcrc
1195 if cai_data.get("mask") is not None: 2% 7 | ncjcL Mb]bNbPbmbdbLb
1196 raise BufferError("mask is not supported") 2nc
1197 if stream_ptr is None: 2% 7 | jcL Mb]bNbPbmbdbLb
1198 raise BufferError("stream=None is ambiguous with view()") 2jc
1200 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2% 7 | L Mb]bNbPbmbdbLb
1201 buf.exporting_obj = obj 2% 7 | L Mb]bNbPbmbdbLb
1202 buf.metadata = cai_data 2% 7 | L Mb]bNbPbmbdbLb
1203 buf.dl_tensor = NULL 2% 7 | L Mb]bNbPbmbdbLb
1204 # Validate shape/strides/typestr eagerly so constructor paths fail fast.
1205 buf.get_layout() 2% 7 | L Mb]bNbPbmbdbLb
1206 buf.ptr, buf.readonly = cai_data["data"] 2% 7 | L MbNbPbmbdbLb
1207 buf.is_device_accessible = True 2% 7 | L MbNbPbmbdbLb
1208 if buf.ptr != 0: 2% 7 | L MbNbPbmbdbLb
1209 buf.device_id = handle_return( 2% 7 | L db
1210 driver.cuPointerGetAttribute( 2% 7 | L db
1211 driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL, 2% 7 | L db
1212 buf.ptr)) 2% 7 | L db
1213 else:
1214 buf.device_id = handle_return(driver.cuCtxGetDevice()) 2MbNbPbmbLb
1216 cdef intptr_t producer_s, consumer_s
1217 cdef EventHandle h_event
1218 stream_ptr = int(stream_ptr) 2% 7 | L MbNbPbmbdbLb
1219 if stream_ptr != -1: 2% 7 | L MbNbPbmbdbLb
1220 stream = cai_data.get("stream") 2dbLb
1221 if stream is not None: 2dbLb
1222 producer_s = <intptr_t>(stream) 2dbLb
1223 consumer_s = <intptr_t>(stream_ptr) 2dbLb
1224 if producer_s <= 0: 2dbLb
1225 raise ValueError( 2Lb
1226 f"__cuda_array_interface__ reported stream {stream}; expected None or a positive stream handle") 2Lb
1227 # establish stream order
1228 if producer_s != consumer_s: 2db
1229 with nogil: 2db
1230 # The event must belong to the producer stream's context to
1231 # be recorded on it, whatever context is current here.
1232 h_event = create_event_handle_for_stream( 2db
1233 <cydriver.CUstream>producer_s, cydriver.CUevent_flags.CU_EVENT_DISABLE_TIMING)
1234 if not h_event: 2db
1235 HANDLE_RETURN(get_last_error())
1236 HANDLE_RETURN(cydriver.cuEventRecord( 2db
1237 as_cu(h_event), <cydriver.CUstream>producer_s))
1238 HANDLE_RETURN(cydriver.cuStreamWaitEvent( 2db
1239 <cydriver.CUstream>consumer_s, as_cu(h_event), 0))
1240 elif _is_torch_tensor(obj):
1241 # PyTorch's __cuda_array_interface__ reports version 2 and
1242 # omits the "stream" field, so the standard CAI sync path
1243 # above is a no-op for torch tensors. This is unsafe: the
1244 # consumer has no guarantee that the producer's work is
1245 # visible. We fix this by querying PyTorch's current CUDA
1246 # stream via the AOTI stable C ABI and performing the same
1247 # event-based stream ordering.
1248 _get_tensor_bridge().sync_torch_stream(
1249 buf.device_id, <intptr_t>(stream_ptr))
1251 return buf 2% 7 | L MbNbPbmbdb
1254cpdef StridedMemoryView view_as_array_interface(obj, view=None):
1255 cdef dict data = obj.__array_interface__ 2ocsctcnbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
1256 if data.get("version", 0) < 3: 2ocsctcnbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
1257 raise BufferError("only NumPy Array Interface v3 or above is supported") 2sctc
1258 if data.get("mask") is not None: 2ocnbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
1259 raise BufferError("mask is not supported") 2oc
1261 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
1262 buf.exporting_obj = obj 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
1263 buf.metadata = data 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
1264 buf.dl_tensor = NULL 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
1265 # Validate shape/strides/typestr eagerly so constructor paths fail fast.
1266 buf.get_layout() 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{beb4 P Y 0 f e d
1267 buf.ptr, buf.readonly = data["data"] 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbeb4 P Y 0 f e d
1268 buf.is_device_accessible = False 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbeb4 P Y 0 f e d
1269 buf.device_id = -1 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbeb4 P Y 0 f e d
1270 return buf 2nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbeb4 P Y 0 f e d
1273def args_viewable_as_strided_memory(arg_indices: tuple[int, ...]) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
1274 """
1275 Decorator to create proxy objects to :obj:`StridedMemoryView` for the
1276 specified positional arguments.
1278 This allows array/tensor attributes to be accessed inside the function
1279 implementation, while keeping the function body array-library-agnostic (if
1280 desired).
1282 Inside the decorated function, the specified arguments become instances
1283 of an (undocumented) proxy type, regardless of its original source. A
1284 :obj:`StridedMemoryView` instance can be obtained by passing the (consumer)
1285 stream pointer (as a Python `int`) to the proxies's ``view()`` method. For
1286 example:
1288 .. code-block:: python
1290 @args_viewable_as_strided_memory((1,))
1291 def my_func(arg0, arg1, arg2, stream: Stream):
1292 # arg1 can be any object supporting DLPack or CUDA Array Interface
1293 view = arg1.view(stream.handle)
1294 assert isinstance(view, StridedMemoryView)
1295 ...
1297 Parameters
1298 ----------
1299 arg_indices : tuple
1300 The indices of the target positional arguments.
1301 """
1302 def wrapped_func_with_indices(func: "Callable") -> "Callable": 189!#$
1303 @functools.wraps(func) 189!#$
1304 def wrapped_func(*args, **kwargs) -> object:
1305 args = list(args) 189!#$
1306 cdef int idx
1307 for idx in arg_indices: 189!#$
1308 args[idx] = _StridedMemoryViewProxy(args[idx]) 189!#$
1309 return func(*args, **kwargs) 189!#$
1310 return wrapped_func 189!#$
1311 return wrapped_func_with_indices 189!#$
1314cdef inline _StridedLayout layout_from_dlpack(DLTensor* dl_tensor):
1315 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 1:6389!#$+,-./?@[]^NOMw15ZSTUVWX_`;)=~QRjIstxyzEFGHABCDuKJp2edbkhqlmrnogvcia
1316 cdef int nbits = dl_tensor.dtype.bits * dl_tensor.dtype.lanes 1:6389!#$+,-./?@[]^NOMw15ZSTUVWX_`;)=~QRjIstxyzEFGHABCDuKJp2edbkhqlmrnogvcia
1317 cdef int itemsize = nbits >> 3 1:6389!#$+,-./?@[]^NOMw15ZSTUVWX_`;)=~QRjIstxyzEFGHABCDuKJp2edbkhqlmrnogvcia
1318 if (itemsize << 3) != nbits: 1:6389!#$+,-./?@[]^NOMw15ZSTUVWX_`;)=~QRjIstxyzEFGHABCDuKJp2edbkhqlmrnogvcia
1319 raise ValueError("dl_tensor.dtype.bits must be a multiple of 8") 1i
1320 layout.init_from_ptr(dl_tensor.ndim, dl_tensor.shape, dl_tensor.strides, itemsize) 1:6389!#$+,-./?@[]^NOMw15ZSTUVWX_`;)=~QRjIstxyzEFGHABCDuKJp2edbkhqlmrnogvcia
1321 return layout 1:6389!#$+,-./?@[]^NOMw15ZSTUVWX_`;)=~QRjIstxyzEFGHABCDuKJp2edbkhqlmrnogvcia
1324cdef _StridedLayout layout_from_cai(object metadata):
1325 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 2% 7 | L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbPbmbdbLbeb4 P Y 0 f e d
1326 cdef object shape = metadata["shape"] 2% 7 | L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbPbmbdbLbeb4 P Y 0 f e d
1327 cdef object strides = metadata.get("strides") 2% 7 | L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbPbmbdbLbeb4 P Y 0 f e d
1328 cdef int itemsize = _typestr2itemsize(metadata["typestr"]) 2% 7 | L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbPbmbdbLbeb4 P Y 0 f e d
1329 layout.init_from_tuple(shape, strides, itemsize, True) 2% 7 | L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwb{bMb]bNbPbmbdbLbeb4 P Y 0 f e d
1330 return layout 2% 7 | L nbobxbpbybqbzbrbsbtbAbBbCbDbEbFbubGbHbIbvbJbKbwbMbNbPbmbdbLbeb4 P Y 0 f e d
1333cdef inline intptr_t get_data_ptr(object buffer, _StridedLayout layout) except? 0:
1334 return <intptr_t>(int(buffer.handle)) + layout.get_slice_offset_in_bytes() 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1337cdef inline int view_buffer_strided(
1338 StridedMemoryView view,
1339 object buffer,
1340 _StridedLayout layout,
1341 object dtype,
1342 bint is_readonly,
1343) except -1:
1344 if isinstance(buffer, Buffer): 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b' lb5 Z S T U V W X Ob* 2 c
1345 Buffer_check_open(<cyBuffer>buffer) 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b' lb5 Z S T U V W X Ob* 2 c
1346 if dtype is not None: 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b' lb5 Z S T U V W X Ob* 2 c
1347 dtype = numpy.dtype(dtype) 2^b_bkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b5 Z S T U V W X 2 c
1348 if dtype.itemsize != layout.itemsize: 2^b_bkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b5 Z S T U V W X 2 c
1349 raise ValueError( 15
1350 f"The dtype's itemsize ({dtype.itemsize}) does not match the layout's " 15
1351 f"itemsize ({layout.itemsize})." 15
1352 )
1353 # Check the layout's offset range [min_offset, max_offset] fits
1354 # within the [0, buffer.size - 1] range.
1355 # The required_size_in_bytes fails if min_offset < 0.
1356 # NB. For external memory, both positive and negative offsets can be valid,
1357 # but for a proper check we'd need to know both size and data offset,
1358 # while neither is reported by the packages.
1359 cdef bint is_allocated = buffer.memory_resource is not None 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b' lbZ S T U V W X Ob* 2 c
1360 if is_allocated and buffer.size < layout.get_required_size_in_bytes(): 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bdcQbRbbc`b' lbZ S T U V W X Ob* 2 c
1361 raise ValueError( 2bc
1362 f"Buffer size is too small for the layout. " 2bc
1363 f"Expected at least {layout.get_required_size_in_bytes()} bytes, " 2bc
1364 f"got {buffer.size} bytes." 2bc
1365 )
1366 # set the public attributes
1367 view.ptr = get_data_ptr(buffer, layout) 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1368 view.device_id = buffer.device_id 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1369 view.is_device_accessible = buffer.is_device_accessible 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1370 view.readonly = is_readonly 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1371 view.exporting_obj = view._buffer = buffer 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1372 # no dlpack/cai metadata
1373 view.dl_tensor = NULL 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1374 view.metadata = None 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1375 # we get the layout from the caller
1376 view._layout = layout 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1377 view._dtype = dtype 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c
1378 return 0 2^b_bibkbN O M VbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?bQbRb`b' lbZ S T U V W X Ob* 2 c