Coverage for cuda/core/_memoryview.pyx: 90.19%
724 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-10 02:27 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-10 02:27 +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._resource_handles 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 2.3 <= torch <= 2.12 (known AOTI ABI range). Memoized.
56 Lower bound: AOTI functions we use were introduced in PyTorch 2.3.
57 Upper bound: the ``pyobj_to_aten_handle`` trick relies on the
58 THPVariable struct layout (PyObject_HEAD followed by at::Tensor cdata)
59 and the identity ``AtenTensorHandle == at::Tensor*``. Both are
60 undocumented internals that could change in a future PyTorch version.
61 We cap at the latest version we have tested against; unknown versions
62 fall back to the standard DLPack/CAI paths. Bump the upper bound
63 after verifying a new PyTorch release.
64 """
65 global _torch_version_ok
66 if _torch_version_ok is not None:
67 return <bint>_torch_version_ok
68 torch = sys.modules.get("torch")
69 if torch is None:
70 _torch_version_ok = False
71 return False
72 try:
73 major, minor = int(torch.__version__.split(".")[0]), \
74 int(torch.__version__.split(".")[1])
75 _torch_version_ok = (2, 3) <= (major, minor) <= (2, 12)
76 except (ValueError, IndexError):
77 _torch_version_ok = False
78 return <bint>_torch_version_ok
81cdef inline bint _is_torch_tensor(object obj):
82 cdef type tp = type(obj) 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsb= ? s @ W / Y V - P Q R S T U : N O * g L E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
83 cdef object cached = _torch_type_cache.get(tp) 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsb= ? s @ W / Y V - P Q R S T U : N O * g L E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
84 if cached is not None: 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsb= ? s @ W / Y V - P Q R S T U : N O * g L E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
85 return <bint>cached 2. , [ 6 7 Z 0 1 2 3 8 9 5 ! # J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8b= ? s W / Y V P Q R S T U : N O * g L E o p t u v A B C D w x y z q G F l c #bb h e m i j n k f d r a
86 cdef str mod = tp.__module__ or "" 2+ 6 5 H qb4bsb@ - X 9bb h e f d r a $b
87 cdef bint result = mod.startswith("torch") and hasattr(obj, "data_ptr") \ 2+ 6 5 H qb4bsb@ - X 9bb h e f d r a $b
88 and _torch_version_check()
89 _torch_type_cache[tp] = result # setdefault not needed for bools 2+ 6 5 H qb4bsb@ - X 9bb h e f d r a $b
90 return result 2+ 6 5 H qb4bsb@ - X 9bb h e f d r a $b
93cdef object _get_tensor_bridge():
94 """Bootstrap AOTI symbols, then import _tensor_bridge on first use."""
95 global _tensor_bridge
96 if _tensor_bridge is not None:
97 return _tensor_bridge
98 torch_C = sys.modules.get("torch._C")
99 if torch_C is None:
100 raise RuntimeError(
101 "torch._C is not loaded; cannot initialise the tensor bridge. "
102 "Make sure PyTorch is imported before passing a torch.Tensor.")
103 ctypes.CDLL(torch_C.__file__, mode=ctypes.RTLD_GLOBAL)
104 from cuda.core import _tensor_bridge as tb
105 _tensor_bridge = tb
106 return _tensor_bridge
109try:
110 from ml_dtypes import bfloat16
111except ImportError:
112 bfloat16 = None
114# TODO(leofang): support NumPy structured dtypes
117cdef extern from "Python.h":
118 ctypedef struct PyTypeObject:
119 void* tp_dict
120 void PyType_Modified(PyTypeObject*)
123cdef DLPackExchangeAPI _SMV_DLPACK_EXCHANGE_API
124cdef bint _SMV_DLPACK_EXCHANGE_API_INITED = False
125_SMV_DLPACK_EXCHANGE_API_CAPSULE = cpython.PyCapsule_New(
126 <void*>&_SMV_DLPACK_EXCHANGE_API,
127 b"dlpack_exchange_api",
128 NULL,
129)
132cdef class StridedMemoryView:
133 """A class holding metadata of a strided dense array/tensor.
135 A :obj:`StridedMemoryView` instance can be created in three ways:
137 1. Using the :obj:`args_viewable_as_strided_memory` decorator (recommended)
138 2. Explicit construction relying on DLPack or CUDA Array Interface, see below.
139 3. From :obj:`~_memory.Buffer` and shape and size tuples (see
140 :meth:`from_buffer` classmethod)
142 ``StridedMemoryView(obj, stream_ptr)`` can be used to create a view from
143 objects supporting either DLPack (up to v1.0) or CUDA Array Interface
144 (CAI) v3. When wrapping an arbitrary object it will try the DLPack protocol
145 first, then the CAI protocol. A :obj:`BufferError` is raised if neither is
146 supported.
148 Since either way would take a consumer stream, for DLPack it is passed to
149 ``obj.__dlpack__()`` as-is (except for :obj:`None`, see below); for CAI, a
150 stream order will be established between the consumer stream and the
151 producer stream (from ``obj.__cuda_array_interface__()["stream"]``), as if
152 ``cudaStreamWaitEvent`` is called by this method.
154 To opt-out of the stream ordering operation in either DLPack or CAI,
155 please pass ``stream_ptr=-1``. Note that this deviates (on purpose)
156 from the semantics of ``obj.__dlpack__(stream=None, ...)`` since ``cuda.core``
157 does not encourage using the (legacy) default/null stream, but is
158 consistent with the CAI's semantics. For DLPack, ``stream=-1`` will be
159 internally passed to ``obj.__dlpack__()`` instead.
161 Parameters
162 ----------
163 obj : Any
164 Any objects that supports either DLPack (up to v1.0) or CUDA Array
165 Interface (v3).
166 stream_ptr: int
167 The pointer address (as Python `int`) to the **consumer** stream.
168 Stream ordering will be properly established unless ``-1`` is passed.
171 Attributes
172 -----------
173 ptr : int
174 Pointer to the tensor buffer (as a Python `int`).
175 device_id : int
176 The device ID for where the tensor is located. It is -1 for CPU tensors
177 (meaning those only accessible from the host).
178 is_device_accessible : bool
179 Whether the tensor data can be accessed on the GPU.
180 readonly: bool
181 Whether the tensor data can be modified in place.
182 exporting_obj : Any
183 A reference to the original tensor object that is being viewed.
184 If the view is created with :meth:`from_buffer`,
185 it will be the Buffer instance passed to the method.
187 """
188 def __init__(self, obj: object = None, stream_ptr: int | None = None) -> None:
189 cdef str clsname = self.__class__.__name__ 2$ % ' ( ) 'brb
190 if obj is not None: 2$ % ' ( ) 'brb
191 # populate self's attributes
192 if check_has_dlpack(obj): 2$ % ' ( ) rb
193 warnings.warn( 1$%'()
194 f"Constructing a {clsname} directly from a DLPack-supporting object is deprecated; " 1M$%'()
195 "Use `StridedMemoryView.from_dlpack` or `StridedMemoryView.from_any_interface` instead.",
196 DeprecationWarning, 1$%'()
197 stacklevel=2,
198 )
199 view_as_dlpack(obj, stream_ptr, self) 1$%'()
200 else:
201 warnings.warn( 2M rb
202 f"Constructing a {clsname} directly from a CUDA-array-interface-supporting object is deprecated; " 2rb
203 "Use `StridedMemoryView.from_cuda_array_interface` or `StridedMemoryView.from_any_interface` instead.",
204 DeprecationWarning, 2rb
205 stacklevel=2,
206 )
207 view_as_cai(obj, stream_ptr, self) 2rb
208 else:
209 warnings.warn( 2'b
210 f"Constructing an empty {clsname} is deprecated; " 2'b
211 "use one of the classmethods `from_dlpack`, `from_cuda_array_interface` or `from_any_interface` "
212 "to construct a StridedMemoryView from an object",
213 DeprecationWarning, 2M 'b
214 stacklevel=2,
215 )
217 @classmethod
218 def from_dlpack(cls, obj: object, stream_ptr: int | None=None) -> StridedMemoryView:
219 """Create a view from an object supporting the `DLPack <https://dmlc.github.io/dlpack/latest/>`_ protocol.
221 Parameters
222 ----------
223 obj : object
224 An object implementing the `DLPack <https://dmlc.github.io/dlpack/latest/>`_ protocol
225 (via ``__dlpack__``).
226 stream_ptr : int, optional
227 Stream pointer for synchronization. If ``None``, no synchronization is performed.
228 """
229 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
230 if _is_torch_tensor(obj): 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
231 _get_tensor_bridge().view_as_torch_tensor(obj, stream_ptr, buf)
232 return buf
233 view_as_dlpack(obj, stream_ptr, buf) 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
234 return buf 1.+,[67Z0123895!#JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
236 @classmethod
237 def from_cuda_array_interface(cls, obj: object, stream_ptr: int | None=None) -> StridedMemoryView:
238 """Create a view from an object supporting the `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_ protocol.
240 Parameters
241 ----------
242 obj : object
243 An object implementing the `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_ protocol.
244 stream_ptr : int, optional
245 Stream pointer for synchronization. If ``None``, no synchronization is performed.
246 """
247 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2H qb4bsb@ -
248 if _is_torch_tensor(obj): 2H qb4bsb@ -
249 _get_tensor_bridge().view_as_torch_tensor(obj, stream_ptr, buf)
250 return buf
251 view_as_cai(obj, stream_ptr, buf) 2M H qb4bsb@ -
252 return buf 2H qbsb@ -
254 @classmethod
255 def from_array_interface(cls, obj: object) -> StridedMemoryView:
256 """Create a view from an object supporting the `__array_interface__ <https://numpy.org/doc/stable/reference/arrays.interface.html>`_ protocol.
258 Parameters
259 ----------
260 obj : object
261 An object implementing the `__array_interface__ <https://numpy.org/doc/stable/reference/arrays.interface.html>`_ protocol (e.g., a numpy array).
262 """
263 cdef StridedMemoryView buf = StridedMemoryView.__new__(cls) 2M ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
264 if _is_torch_tensor(obj): 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
265 _get_tensor_bridge().view_as_torch_tensor(obj, None, buf)
266 return buf
267 view_as_array_interface(obj, buf) 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
268 return buf 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbL c
270 @classmethod
271 def from_any_interface(cls, obj: object, stream_ptr: int | None = None) -> StridedMemoryView:
272 """Create a view by automatically selecting the best available protocol.
274 Tries `DLPack <https://dmlc.github.io/dlpack/latest/>`_ first, then falls back to
275 `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_.
276 ``torch.Tensor`` objects are transparently handled via a fast AOTI path
277 regardless of which protocol is selected.
279 Parameters
280 ----------
281 obj : object
282 An object implementing `DLPack <https://dmlc.github.io/dlpack/latest/>`_ or
283 `__cuda_array_interface__ <https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html>`_.
284 stream_ptr : int, optional
285 Stream pointer for synchronization. If ``None``, no synchronization is performed.
286 """
287 if check_has_dlpack(obj): 2. + , [ 6 7 8 9 5 ! # /bJ K I = ? s W / Y V : N O * g E o p t u v A B C D w x y z q G F l b h e m i j n k f d r a
288 return cls.from_dlpack(obj, stream_ptr) 1.+,[67895!#JKI=?sW/YV:NO*gEoptuvABCDwxyzqGFlbhemijnkfdra
289 return cls.from_cuda_array_interface(obj, stream_ptr)
291 @classmethod
292 def from_buffer(
293 cls,
294 buffer : Buffer,
295 shape : tuple[int, ...],
296 strides : tuple[int, ...] | None = None,
297 *,
298 itemsize : int | None = None,
299 dtype : numpy.dtype | None = None,
300 is_readonly : bool = False
301 ) -> StridedMemoryView:
302 """
303 Creates a :obj:`StridedMemoryView` instance from a :obj:`~_memory.Buffer` and shape and strides tuples.
304 The Buffer can be either allocation coming from a :obj:`MemoryResource` or an external allocation
305 wrapped in a :obj:`~_memory.Buffer` object with ``Buffer.from_handle(ptr, size, owner=...)``.
307 .. caution::
308 When creating a :obj:`StridedMemoryView` from a :obj:`~_memory.Buffer`,
309 no synchronization is performed. It is the user's responsibility to ensure
310 the data in ``buffer`` is properly synchronized when consuming the view.
312 Parameters
313 ----------
314 buffer : :obj:`~_memory.Buffer`
315 The buffer to create the view from.
316 shape : :obj:`tuple`
317 The layout describing the shape, strides and itemsize of the elements in
318 the buffer.
319 strides : :obj:`tuple`
320 The layout describing the shape, strides and itemsize of the elements in
321 the buffer.
322 dtype : :obj:`numpy.dtype`
323 Optional dtype.
324 If specified, the dtype's itemsize must match the layout's itemsize.
325 is_readonly : bool, optional
326 Whether the mark the view as readonly.
327 """
328 cdef StridedMemoryView view = StridedMemoryView.__new__(cls) 25b6bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%b*b(bubvb!b7b4 ;
329 if itemsize is None and dtype is None: 25b6bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%b*b(bubvb!b7b4 ;
330 raise ValueError("Either itemsize or dtype must be specified") 2*b
331 if itemsize is not None and dtype is not None and itemsize != dtype.itemsize: 25b6bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%b(bubvb!b7b4 ;
332 raise ValueError( 2(b
333 f"itemsize ({itemsize}) does not match dtype.itemsize ({dtype.itemsize})" 2(b
334 )
335 # (itemsize is None XOR dtype is None) OR they are equal
336 view_buffer_strided( 25b6bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7b4 ;
337 view,
338 buffer,
339 _StridedLayout(shape=shape, strides=strides, itemsize=getattr(dtype, "itemsize", itemsize)), 25b6bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7b4 ;
340 dtype,
341 is_readonly,
342 )
343 return view 25b6bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ;
345 def __dealloc__(self) -> None:
346 if self.dl_tensor == NULL: 25b6b. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%b*b(bubvb!b7bqb4bsb= ? s 4 'brb@ ; W / Y V - P Q R S T U : N O * tbwbxbL E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
347 return 25b6bH J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%b*b(bubvb!b7bqb4bsb4 'brb@ ; / Y V - P Q R S T U L c X #b9b$b
349 if cpython.PyCapsule_IsValid( 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * tbwbxbE o p t u v A B C D w x y z q G F l c X b h e m i j n k f d r a
350 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME): 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * tbwbxbE o p t u v A B C D w x y z q G F l c X b h e m i j n k f d r a
351 data = cpython.PyCapsule_GetPointer( 2M . + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * tbwbxbE o p t u v A B C D w x y z q G F l c X h e m i j n k f r a
352 self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME) 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * tbwbxbE o p t u v A B C D w x y z q G F l c X h e m i j n k f r a
353 dlm_tensor_ver = <DLManagedTensorVersioned*>data 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * tbwbxbE o p t u v A B C D w x y z q G F l c X h e m i j n k f r a
354 if dlm_tensor_ver.deleter != NULL: 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * tbwbxbE o p t u v A B C D w x y z q G F l c X h e m i j n k f r a
355 dlm_tensor_ver.deleter(dlm_tensor_ver) 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*EoptuvABCDwxyzqGFlcXhemijnkfa
356 elif cpython.PyCapsule_IsValid( 1bda
357 self.metadata, DLPACK_TENSOR_USED_NAME): 1bda
358 data = cpython.PyCapsule_GetPointer( 1Mbda
359 self.metadata, DLPACK_TENSOR_USED_NAME) 1bda
360 dlm_tensor = <DLManagedTensor*>data 1bda
361 if dlm_tensor.deleter != NULL: 1bda
362 dlm_tensor.deleter(dlm_tensor) 1ba
364 def view(
365 self, layout : _StridedLayout | None = None, dtype : numpy.dtype | None = None
366 ) -> StridedMemoryView:
367 """
368 Creates a new view with adjusted layout and dtype.
369 Same as calling :meth:`from_buffer` with the current buffer.
370 """
371 cdef StridedMemoryView view = StridedMemoryView.__new__(self.__class__) 2J K I ubvb/ Y V P Q R S T U X
372 if layout is None and dtype is None: 2J K I ubvb/ Y V P Q R S T U X
373 return self 1/
374 if layout is None: 2J K I ubvbY V P Q R S T U X
375 layout = self.get_layout() 1JKIYVX
376 if dtype is None: 2J K I ubvbY V P Q R S T U X
377 dtype = self.get_dtype() 2ubvbP Q R S T U
378 view_buffer_strided(view, self.get_buffer(), layout, dtype, self.readonly) 2M J K I ubvbY V P Q R S T U X
379 return view 2J K I ubvbV P Q R S T U X
381 def as_tensor_map(
382 self,
383 box_dim: tuple[int, ...] | None = None,
384 *,
385 options: TensorMapDescriptorOptions | None = None,
386 element_strides: tuple[int, ...] | None = None,
387 data_type: object = None,
388 interleave: object = None,
389 swizzle: object = None,
390 l2_promotion: object = None,
391 oob_fill: object = None,
392 ) -> object:
393 """Create a tiled :obj:`TensorMapDescriptor` from this view.
395 This is the public entry point for creating tiled tensor map
396 descriptors in ``cuda.core``. Pass either ``box_dim`` and the
397 individual keyword arguments directly, or provide bundled tiled
398 options via ``options=``.
399 """
400 from cuda.core._tensor_map import TensorMapDescriptor 17
402 kwargs = {} 17
403 if options is not None: 17
404 kwargs["options"] = options
405 if element_strides is not None: 17
406 kwargs["element_strides"] = element_strides 17
407 if data_type is not None: 17
408 kwargs["data_type"] = data_type 17
409 if interleave is not None: 17
410 kwargs["interleave"] = interleave
411 if swizzle is not None: 17
412 kwargs["swizzle"] = swizzle 17
413 if l2_promotion is not None: 1M7
414 kwargs["l2_promotion"] = l2_promotion 17
415 if oob_fill is not None: 17
416 kwargs["oob_fill"] = oob_fill 17
417 return TensorMapDescriptor._from_tiled(self, box_dim, **kwargs) 17
419 def copy_from(
420 self,
421 other: StridedMemoryView,
422 stream: Stream,
423 allocator: object = None,
424 blocking: bool | None = None,
425 ) -> None:
426 """
427 Copies the data from the other view into this view.
429 The copy can be performed between following memory spaces:
430 host-to-device, device-to-host, device-to-device (on the same device).
432 Parameters
433 ----------
434 other : StridedMemoryView
435 The view to copy data from.
436 stream : Stream | None, optional
437 The stream to schedule the copy on.
438 allocator : MemoryResource | None, optional
439 If temporary buffers are needed, the specified memory resources
440 will be used to allocate the memory. If not specified, default
441 resources will be used.
442 blocking : bool | None, optional
443 Whether the call should block until the copy is complete.
444 * ``True``: the ``stream`` is synchronized with the host at the end of the call,
445 blocking until the copy is complete.
446 * ``False``: if possible, the call returns immediately once the copy is scheduled.
447 However, in some cases of host-to-device or device-to-host copies, the call may
448 still synchronize with the host if necessary.
449 * ``None`` (default):
450 * for device-to-device, it defaults to ``False`` (non-blocking),
451 * for host-to-device or device-to-host, it defaults to ``True`` (blocking).
452 """
453 raise NotImplementedError("Sorry, not supported: copy_from") 1=
455 def copy_to(
456 self,
457 other: StridedMemoryView,
458 stream: Stream | None = None,
459 allocator: object = None,
460 blocking: bool | None = None,
461 ) -> None:
462 """
463 Copies the data from this view into the ``other`` view.
465 For details, see :meth:`copy_from`.
466 """
467 raise NotImplementedError("Sorry, not supported: copy_to") 1?
469 def __dlpack__(
470 self,
471 *,
472 stream: int | None = None,
473 max_version: tuple[int, int] | None = None,
474 dl_device: tuple[int, int] | None = None,
475 copy: bool | None = None,
476 ) -> object:
477 # Similar to Buffer.__dlpack__: no implicit synchronization is performed.
478 if dl_device is not None: 1,HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
479 raise BufferError("Sorry, not supported: dl_device other than None") 1,
480 if copy is True: 1,HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
481 raise BufferError("Sorry, not supported: copy=True") 1M,
483 cdef bint versioned
484 if max_version is None: 1,HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
485 versioned = False 1HJKI4Fbda
486 else:
487 if not isinstance(max_version, tuple) or len(max_version) != 2: 1,sLEoptuvABCDwxyzqGlcbhemijnkfra
488 raise BufferError(f"Expected max_version tuple[int, int], got {max_version}") 1,
489 versioned = max_version >= (1, 0) 1sLEoptuvABCDwxyzqGlcbhemijnkfra
491 # NOTE: stream is accepted for protocol compatibility but not used.
492 cdef object capsule = _smv_make_py_capsule(self, versioned) 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
493 return capsule 1HsLEoptuvABCDwxyzqGFlcbhemijnkfdra
495 def __dlpack_device__(self) -> tuple[int, int]:
496 cdef _DLDeviceType device_type
497 cdef int32_t device_id
498 _smv_get_dl_device(self, &device_type, &device_id) 1.+HsLcbhemijnkfdra
499 return (<int>device_type, int(device_id)) 1.+HsLcbhemijnkfdra
501 @property
502 def _layout(self) -> _StridedLayout:
503 """
504 The layout of the tensor. For StridedMemoryView created from DLPack or CAI,
505 the layout is inferred from the tensor object's metadata.
506 """
507 return self.get_layout() 2ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb'bV P Q R S T U
509 @property
510 def size(self) -> int:
511 return self.get_layout().get_volume() 2Z 0 1 2 3 8 9 5 ! # $ % ' ( ) ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbqb
513 @property
514 def shape(self) -> tuple[int, ...]:
515 """
516 Shape of the tensor.
517 """
518 return self.get_layout().get_shape_tuple() 25b6b6 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvbqbsbrb@ ; W - P Q R S T U g b h
520 @property
521 def strides(self) -> tuple[int, ...] | None:
522 """
523 Strides of the tensor (in **counts**, not bytes).
524 """
525 return self.get_layout().get_strides_tuple() 26 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bqbsb; W
527 @property
528 def dtype(self) -> numpy.dtype | None:
529 """
530 Data type of the tensor.
532 Supports standard NumPy dtypes as well as narrow data types (e.g., ``bfloat16``)
533 when the optional `ml_dtypes <https://github.com/jax-ml/ml_dtypes>`_ package is
534 installed. If ``ml_dtypes`` is not available and such a tensor is encountered,
535 a :obj:`NotImplementedError` will be raised.
536 """
537 return self.get_dtype() 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b7b; W V P Q R S T U e m i j n k f
539 def __repr__(self) -> str:
540 return (f"StridedMemoryView(ptr={self.ptr},\n" 1;W
541 + f" shape={self.shape},\n" 1M;W
542 + f" strides={self.strides},\n" 1;W
543 + f" itemsize={self._layout.itemsize},\n" 1;W
544 + f" dtype={get_simple_repr(self.dtype)},\n" 1;W
545 + f" device_id={self.device_id},\n" 1;W
546 + f" is_device_accessible={self.is_device_accessible},\n" 1;W
547 + f" readonly={self.readonly},\n" 1;W
548 + f" exporting_obj={get_simple_repr(self.exporting_obj)})") 1M;W
550 @cython.critical_section
551 cdef inline _StridedLayout get_layout(self):
552 cdef _StridedLayout layout
553 if self._layout is None: 25b6b6 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvbqb4bsbs 4 'brb@ ; W Y V - P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c X b h e m i j n k f d r a
554 if self.dl_tensor: 26 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsbs 'brb@ W Y V - P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c X b h e m i j n k f d r a
555 layout = layout_from_dlpack(self.dl_tensor) 16Z0123895!#$%'()JKIsWYVPQRSTUNOgEoptuvABCDwxyzqGFlXbhemijnkfdra
556 elif self.metadata is not None: 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsb'brb@ - L c
557 layout = layout_from_cai(self.metadata) 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsbrb@ - L c
558 else:
559 raise ValueError("Cannot infer layout from the exporting object") 2'b
560 if self._layout is None: 26 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbqbsbs rb@ W Y V - P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c X b h e m i j n k f d r a
561 self._layout = layout 26 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbqbsbs rb@ W Y V - P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c X b h e m i j n k f d r a
562 return self._layout 25b6b6 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvbqbsbs 4 rb@ ; W Y V - P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c X b h e m i j n k f d r a
564 @cython.critical_section
565 cdef inline object get_buffer(self):
566 """
567 Returns Buffer instance with the underlying data.
568 If the SMV was created from a Buffer, it will return the same Buffer instance.
569 Otherwise, it will create a new instance with owner set to the exporting object.
570 """
571 cdef object buffer
572 if self._buffer is None: 2H J K I ubvbY V P Q R S T U X
573 if isinstance(self.exporting_obj, Buffer): 1HJKIYVPQRSTUX
574 buffer = self.exporting_obj 1X
575 else:
576 buffer = Buffer.from_handle(self.ptr, 0, owner=self.exporting_obj) 1HJKIYVPQRSTU
577 if self._buffer is None: 1HJKIYVPQRSTUX
578 self._buffer = buffer 1HJKIYVPQRSTUX
579 return self._buffer 2H J K I ubvbY V P Q R S T U X
581 @cython.critical_section
582 cdef inline object get_dtype(self):
583 cdef object dtype
584 if self._dtype is None: 2H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7bs 4 ; W V P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c b h e m i j n k f d r a
585 dtype = None 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbs 4 ; W P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c b h e m i j n k f d r a
586 if self.dl_tensor != NULL: 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbs 4 ; W P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c b h e m i j n k f d r a
587 dtype = dtype_dlpack_to_numpy(&self.dl_tensor.dtype) 1MsWPQRSTUNOgEoptuvABCDwxyzqGFlbhemijnkfdra
588 elif isinstance(self.metadata, int): 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb4 ; L c
589 # AOTI dtype code stored by the torch tensor bridge
590 dtype = _get_tensor_bridge().resolve_aoti_dtype(
591 self.metadata)
592 elif self.metadata is not None: 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb4 ; L c
593 dtype = _typestr2dtype(self.metadata["typestr"]) 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbL c
594 if self._dtype is None: 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbs 4 ; W P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c b h e m i j n k f d r a
595 self._dtype = dtype 2M H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbs 4 ; W P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c b h e m i j n k f d r a
596 return self._dtype 2H J K I ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7bs 4 ; W V P Q R S T U N O g L E o p t u v A B C D w x y z q G F l c b h e m i j n k f d r a
599cdef void _smv_pycapsule_deleter(object capsule) noexcept:
600 cdef DLManagedTensor* dlm_tensor
601 cdef DLManagedTensorVersioned* dlm_tensor_ver
602 # Do not invoke the deleter on a used capsule.
603 if cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME): 2H s tbwbxbL E o p t u v A B C D w x y z q G F l c b h e m i j n k f a
604 dlm_tensor = <DLManagedTensor*>( 1HF
605 cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME) 1HF
606 )
607 if dlm_tensor.deleter: 1HF
608 dlm_tensor.deleter(dlm_tensor) 1HF
609 elif cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 2M s tbwbxbL E o p t u v A B C D w x y z q G l c b h e m i j n k f a
610 dlm_tensor_ver = <DLManagedTensorVersioned*>( 1l
611 cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 1l
612 )
613 if dlm_tensor_ver.deleter: 1Ml
614 dlm_tensor_ver.deleter(dlm_tensor_ver) 1l
617cdef inline void _smv_release_export_resources(void* manager_ctx, int64_t* shape_ptr) noexcept with gil:
618 if shape_ptr: 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
619 stdlib.free(shape_ptr) 1HsLEoptuvABCDwxyzqFlcbhemijnkfdra
620 if manager_ctx: 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
621 cpython.Py_DECREF(<object>manager_ctx) 1MHJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
624cdef void _smv_deleter(DLManagedTensor* tensor) noexcept with gil:
625 if tensor: 1HJKI4Fbda
626 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1HJKI4Fbda
627 tensor.manager_ctx = NULL 1HJKI4Fbda
628 stdlib.free(tensor) 1HJKI4Fbda
631cdef void _smv_versioned_deleter(DLManagedTensorVersioned* tensor) noexcept with gil:
632 if tensor: 1MJKIs4LEoptuvABCDwxyzqGlcbhemijnkfra
633 _smv_release_export_resources(tensor.manager_ctx, tensor.dl_tensor.shape) 1sLEoptuvABCDwxyzqGlcbhemijnkfra
634 tensor.manager_ctx = NULL 1sLEoptuvABCDwxyzqGlcbhemijnkfra
635 stdlib.free(tensor) 1sLEoptuvABCDwxyzqGlcbhemijnkfra
638cdef inline DLManagedTensorVersioned* _smv_allocate_dlm_tensor_versioned() except? NULL:
639 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
640 dlm_tensor_ver = <DLManagedTensorVersioned*>stdlib.malloc(sizeof(DLManagedTensorVersioned)) 1MsgLEoptuvABCDwxyzqGlcbhemijnkfra
641 if dlm_tensor_ver == NULL: 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
642 raise MemoryError()
643 dlm_tensor_ver.dl_tensor.shape = NULL 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
644 dlm_tensor_ver.manager_ctx = NULL 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
645 return dlm_tensor_ver 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
648cdef inline DLManagedTensor* _smv_allocate_dlm_tensor() except? NULL:
649 cdef DLManagedTensor* dlm_tensor = NULL 1HJKI4Fbda
650 dlm_tensor = <DLManagedTensor*>stdlib.malloc(sizeof(DLManagedTensor)) 1HJKI4Fbda
651 if dlm_tensor == NULL: 1HJKI4Fbda
652 raise MemoryError()
653 dlm_tensor.dl_tensor.shape = NULL 1HJKI4Fbda
654 dlm_tensor.manager_ctx = NULL 1HJKI4Fbda
655 return dlm_tensor 1HJKI4Fbda
658cdef inline int _smv_dtype_numpy_to_dlpack(object dtype_obj, DLDataType* out_dtype) except -1:
659 cdef object np_dtype = numpy.dtype(dtype_obj) 1HJKIsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
660 if np_dtype.fields is not None: 1HJKIsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
661 raise BufferError("Structured dtypes are not supported for DLPack export") 1K
662 if not np_dtype.isnative and np_dtype.byteorder not in ("=", "|"): 1HJIsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
663 raise BufferError("Non-native-endian dtypes are not supported for DLPack export") 1J
665 cdef str kind = np_dtype.kind 1HIsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
666 cdef int bits = np_dtype.itemsize * 8 1HIsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
667 cdef uint8_t code
668 if kind == "b": 1MHIsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
669 if bits != 8: 1E
670 raise BufferError(f"Unsupported bool dtype itemsize: {np_dtype.itemsize}")
671 code = <uint8_t>kDLBool 1E
672 elif kind == "i": 1HIsNOgLoptuvABCDwxyzqGFlcbhemijnkfdra
673 if bits not in (8, 16, 32, 64): 1MsNOLABCDFlcbhemijnkfdra
674 raise BufferError(f"Unsupported signed integer dtype: {np_dtype}")
675 code = <uint8_t>kDLInt 1sNOLABCDFlcbhemijnkfdra
676 elif kind == "u": 1HIgoptuvwxyzqG
677 if bits not in (8, 16, 32, 64): 1wxyz
678 raise BufferError(f"Unsupported unsigned integer dtype: {np_dtype}")
679 code = <uint8_t>kDLUInt 1wxyz
680 elif kind == "f": 1HIgoptuvqG
681 if bits not in (16, 32, 64): 1Hgtuv
682 raise BufferError(f"Unsupported floating dtype: {np_dtype}")
683 code = <uint8_t>kDLFloat 1MHgtuv
684 elif kind == "c": 1IopqG
685 if bits not in (64, 128): 1opqG
686 raise BufferError(f"Unsupported complex dtype: {np_dtype}")
687 code = <uint8_t>kDLComplex 1opqG
688 else:
689 raise BufferError(f"Unsupported dtype for DLPack export: {np_dtype}") 1I
691 out_dtype.code = code 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
692 out_dtype.bits = <uint8_t>bits 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
693 out_dtype.lanes = <uint16_t>1 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
694 return 0 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
697cdef inline int _smv_get_dl_device(
698 StridedMemoryView view,
699 _DLDeviceType* out_device_type,
700 int32_t* out_device_id,
701) except -1:
702 cdef _DLDeviceType device_type
703 cdef int32_t device_id
704 cdef object buf
705 if view.dl_tensor != NULL: 1.+HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
706 device_type = view.dl_tensor.device.device_type 1.+sNOgEoptuvABCDwxyzqGFlbhemijnkfdra
707 if device_type == _kDLCUDA: 1.+sNOgEoptuvABCDwxyzqGFlbhemijnkfdra
708 device_id = view.dl_tensor.device.device_id
709 else:
710 # CPU, CUDAHost, and CUDAManaged use device_id=0 in DLPack.
711 device_id = 0 1.+sNOgEoptuvABCDwxyzqGFlbhemijnkfdra
712 elif view.is_device_accessible: 1HLc
713 buf = view.get_buffer() 1H
714 dev_type, dev_id = classify_dl_device(buf) 1H
715 device_type = <_DLDeviceType>dev_type 1H
716 device_id = <int32_t>dev_id 1H
717 else:
718 device_type = _kDLCPU 1Lc
719 device_id = 0 1Lc
721 out_device_type[0] = device_type 1.+HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
722 out_device_id[0] = device_id 1.+HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
723 return 0 1.+HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
726cdef inline int _smv_setup_dl_tensor_common(
727 DLTensor* dl_tensor,
728 StridedMemoryView view,
729 _StridedLayout layout,
730) except -1:
731 cdef object dtype_obj = view.get_dtype() 1HJKIs4NOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
732 if dtype_obj is None: 1HJKIs4NOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
733 raise BufferError( 14
734 "Cannot export StridedMemoryView via DLPack without dtype information; "
735 "create the view with dtype specified."
736 )
737 _smv_dtype_numpy_to_dlpack(dtype_obj, &dl_tensor.dtype) 1HJKIsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
738 _smv_get_dl_device(view, &dl_tensor.device.device_type, &dl_tensor.device.device_id) 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
740 cdef int ndim = layout.base.ndim 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
741 dl_tensor.ndim = ndim 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
742 if layout.get_volume() == 0: 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
743 dl_tensor.data = NULL 1q
744 else:
745 dl_tensor.data = <void*><intptr_t>view.ptr 1HsNOgLEoptuvABCDwxyzGFlcbhemijnkfdra
746 dl_tensor.byte_offset = 0 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
747 return 0 1HsNOgLEoptuvABCDwxyzqGFlcbhemijnkfdra
750cdef inline int _smv_setup_dl_tensor(DLTensor* dl_tensor, StridedMemoryView view) except -1:
751 cdef _StridedLayout layout = view.get_layout() 1HJKIs4gLEoptuvABCDwxyzqGFlcbhemijnkfdra
752 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1HJKIs4gLEoptuvABCDwxyzqGFlcbhemijnkfdra
754 cdef int i
755 cdef int64_t* shape_strides = NULL 1HsgLEoptuvABCDwxyzqGFlcbhemijnkfdra
756 cdef int64_t* strides_src = NULL 1HsgLEoptuvABCDwxyzqGFlcbhemijnkfdra
757 cdef int ndim = dl_tensor.ndim 1HsgLEoptuvABCDwxyzqGFlcbhemijnkfdra
758 if ndim == 0: 1HsgLEoptuvABCDwxyzqGFlcbhemijnkfdra
759 dl_tensor.shape = NULL 1G
760 dl_tensor.strides = NULL 1G
761 else:
762 # DLPack v1.2+ requires non-NULL strides for ndim != 0.
763 shape_strides = <int64_t*>stdlib.malloc(sizeof(int64_t) * 2 * ndim) 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
764 if shape_strides == NULL: 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
765 raise MemoryError()
766 try: 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
767 strides_src = get_strides_ptr(layout.base) 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
768 for i in range(ndim): 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
769 shape_strides[i] = layout.base.shape[i] 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
770 shape_strides[i + ndim] = strides_src[i] 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
771 except Exception:
772 stdlib.free(shape_strides)
773 raise
774 dl_tensor.shape = shape_strides 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
775 dl_tensor.strides = shape_strides + ndim 1HsgLEoptuvABCDwxyzqFlcbhemijnkfdra
776 return 0 1HsgLEoptuvABCDwxyzqGFlcbhemijnkfdra
779cdef inline int _smv_setup_dltensor_borrowed(DLTensor* dl_tensor, StridedMemoryView view) except -1:
780 cdef _StridedLayout layout = view.get_layout() 1NO
781 _smv_setup_dl_tensor_common(dl_tensor, view, layout) 1NO
783 if dl_tensor.ndim == 0: 1NO
784 dl_tensor.shape = NULL 1N
785 dl_tensor.strides = NULL 1N
786 else:
787 dl_tensor.shape = layout.base.shape 1O
788 # For temporary/non-owning exchange we provide explicit strides.
789 dl_tensor.strides = get_strides_ptr(layout.base) 1O
790 return 0 1NO
793cdef inline int _smv_fill_managed_tensor_versioned(
794 DLManagedTensorVersioned* dlm_tensor_ver,
795 StridedMemoryView view,
796) except -1:
797 cpython.Py_INCREF(view) 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
798 dlm_tensor_ver.manager_ctx = <void*>view 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
799 dlm_tensor_ver.deleter = _smv_versioned_deleter 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
800 dlm_tensor_ver.version.major = DLPACK_MAJOR_VERSION 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
801 dlm_tensor_ver.version.minor = DLPACK_MINOR_VERSION 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
802 dlm_tensor_ver.flags = DLPACK_FLAG_BITMASK_READ_ONLY if view.readonly else 0 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
803 _smv_setup_dl_tensor(&dlm_tensor_ver.dl_tensor, view) 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
804 return 0 1sgLEoptuvABCDwxyzqGlcbhemijnkfra
807cdef inline int _smv_fill_managed_tensor(
808 DLManagedTensor* dlm_tensor,
809 StridedMemoryView view,
810) except -1:
811 cpython.Py_INCREF(view) 1HJKI4Fbda
812 dlm_tensor.manager_ctx = <void*>view 1HJKI4Fbda
813 dlm_tensor.deleter = _smv_deleter 1HJKI4Fbda
814 _smv_setup_dl_tensor(&dlm_tensor.dl_tensor, view) 1HJKI4Fbda
815 return 0 1HFbda
818cdef object _smv_make_py_capsule(StridedMemoryView view, bint versioned):
819 cdef DLManagedTensor* dlm_tensor = NULL 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
820 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
821 cdef object capsule = None 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
822 cdef void* tensor_ptr = NULL 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
823 cdef const char* capsule_name
824 try: 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
825 if versioned: 1HJKIs4LEoptuvABCDwxyzqGFlcbhemijnkfdra
826 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1sLEoptuvABCDwxyzqGlcbhemijnkfra
827 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, view) 1sLEoptuvABCDwxyzqGlcbhemijnkfra
828 tensor_ptr = <void*>dlm_tensor_ver 1sLEoptuvABCDwxyzqGlcbhemijnkfra
829 capsule_name = DLPACK_VERSIONED_TENSOR_UNUSED_NAME 1sLEoptuvABCDwxyzqGlcbhemijnkfra
830 else:
831 dlm_tensor = _smv_allocate_dlm_tensor() 1HJKI4Fbda
832 _smv_fill_managed_tensor(dlm_tensor, view) 1HJKI4Fbda
833 tensor_ptr = <void*>dlm_tensor 1HFbda
834 capsule_name = DLPACK_TENSOR_UNUSED_NAME 1HFbda
835 capsule = cpython.PyCapsule_New(tensor_ptr, capsule_name, _smv_pycapsule_deleter) 1HsLEoptuvABCDwxyzqGFlcbhemijnkfdra
836 except Exception: 1JKI4
837 if capsule is None: 1JKI4
838 _smv_deleter(dlm_tensor) 1JKI4
839 _smv_versioned_deleter(dlm_tensor_ver) 1JKI4
840 raise 1JKI4
841 return capsule 1HsLEoptuvABCDwxyzqGFlcbhemijnkfdra
844cdef inline StridedMemoryView _smv_from_dlpack_capsule(object capsule, object exporting_obj):
845 cdef void* data = NULL 2g tbwbxb
846 cdef DLTensor* dl_tensor = NULL 2g tbwbxb
847 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 2g tbwbxb
848 cdef DLManagedTensor* dlm_tensor = NULL 2g tbwbxb
849 cdef bint is_readonly = False 2g tbwbxb
850 cdef const char* used_name = NULL 2g tbwbxb
851 if cpython.PyCapsule_IsValid(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME): 2g tbwbxb
852 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME) 2g tbwbxb
853 dlm_tensor_ver = <DLManagedTensorVersioned*>data 2g tbwbxb
854 dl_tensor = &dlm_tensor_ver.dl_tensor 2g tbwbxb
855 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 2g tbwbxb
856 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 2g tbwbxb
857 elif cpython.PyCapsule_IsValid(capsule, DLPACK_TENSOR_UNUSED_NAME):
858 data = cpython.PyCapsule_GetPointer(capsule, DLPACK_TENSOR_UNUSED_NAME)
859 dlm_tensor = <DLManagedTensor*>data
860 dl_tensor = &dlm_tensor.dl_tensor
861 is_readonly = False
862 used_name = DLPACK_TENSOR_USED_NAME
863 else:
864 raise BufferError("Invalid DLPack capsule")
866 cpython.PyCapsule_SetName(capsule, used_name) 2g tbwbxb
868 cdef StridedMemoryView view = StridedMemoryView.__new__(StridedMemoryView) 2g tbwbxb
869 view.dl_tensor = dl_tensor 2g tbwbxb
870 view.metadata = capsule 2g tbwbxb
871 view.ptr = <intptr_t>(dl_tensor.data) + <intptr_t>(dl_tensor.byte_offset) 2g tbwbxb
872 view.readonly = is_readonly 2g tbwbxb
873 view.exporting_obj = exporting_obj 2g tbwbxb
874 if dl_tensor.device.device_type == _kDLCPU: 2g tbwbxb
875 view.device_id = -1 1g
876 view.is_device_accessible = False 1g
877 elif dl_tensor.device.device_type in (_kDLCUDA, _kDLCUDAHost, _kDLCUDAManaged): 2tb
878 view.device_id = dl_tensor.device.device_id 2tbwbxb
879 view.is_device_accessible = True 2tbwbxb
880 else:
881 raise BufferError("device not supported")
882 return view 2g tbwbxb
885cdef int _smv_managed_tensor_allocator(
886 DLTensor* prototype,
887 DLManagedTensorVersioned** out,
888 void* error_ctx,
889 void (*SetError)(void* error_ctx, const char* kind, const char* message) noexcept,
890) noexcept with gil:
891 if out != NULL: 2+b
892 out[0] = NULL 2+b
893 if SetError != NULL: 2+b
894 SetError(error_ctx, b"NotImplementedError", b"managed_tensor_allocator is not supported by StridedMemoryView")
895 cpython.PyErr_SetString(NotImplementedError, b"managed_tensor_allocator is not supported by StridedMemoryView") 2+b
896 return -1 2+b
899cdef int _smv_managed_tensor_from_py_object_no_sync(
900 void* py_object,
901 DLManagedTensorVersioned** out,
902) noexcept with gil:
903 cdef DLManagedTensorVersioned* dlm_tensor_ver = NULL 1*g
904 if out == NULL: 1*g
905 cpython.PyErr_SetString(RuntimeError, b"out cannot be NULL") 1*
906 return -1 1*
907 out[0] = NULL 1*g
908 cdef object obj = <object>py_object 1*g
909 if not isinstance(obj, StridedMemoryView): 1*g
910 cpython.PyErr_SetString(TypeError, b"py_object must be a StridedMemoryView") 1*
911 return -1 1*
912 try: 1g
913 dlm_tensor_ver = _smv_allocate_dlm_tensor_versioned() 1g
914 _smv_fill_managed_tensor_versioned(dlm_tensor_ver, <StridedMemoryView>obj) 1g
915 except Exception:
916 _smv_versioned_deleter(dlm_tensor_ver)
917 return -1
918 out[0] = dlm_tensor_ver 1g
919 return 0 1g
922cdef int _smv_managed_tensor_to_py_object_no_sync(
923 DLManagedTensorVersioned* tensor,
924 void** out_py_object,
925) noexcept with gil:
926 cdef object capsule
927 cdef object py_view
928 if out_py_object == NULL: 2g tbwbxb=b,b
929 cpython.PyErr_SetString(RuntimeError, b"out_py_object cannot be NULL") 2=b
930 return -1 2=b
931 out_py_object[0] = NULL 2g tbwbxb,b
932 if tensor == NULL: 2g tbwbxb,b
933 cpython.PyErr_SetString(RuntimeError, b"tensor cannot be NULL") 2,b
934 return -1 2,b
935 try: 2g tbwbxb
936 capsule = cpython.PyCapsule_New( 2g tbwbxb
937 <void*>tensor,
938 DLPACK_VERSIONED_TENSOR_UNUSED_NAME,
939 _smv_pycapsule_deleter,
940 )
941 py_view = _smv_from_dlpack_capsule(capsule, capsule) 2g tbwbxb
942 cpython.Py_INCREF(py_view) 2g tbwbxb
943 out_py_object[0] = <void*>py_view 2g tbwbxb
944 except Exception:
945 return -1
946 return 0 2g tbwbxb
949cdef int _smv_dltensor_from_py_object_no_sync(
950 void* py_object,
951 DLTensor* out,
952) noexcept with gil:
953 if out == NULL: 2: N -bO
954 cpython.PyErr_SetString(RuntimeError, b"out cannot be NULL") 1:
955 return -1 1:
956 cdef object obj = <object>py_object 2N -bO
957 if not isinstance(obj, StridedMemoryView): 2N -bO
958 cpython.PyErr_SetString(TypeError, b"py_object must be a StridedMemoryView") 2-b
959 return -1 2-b
960 try: 1NO
961 _smv_setup_dltensor_borrowed(out, <StridedMemoryView>obj) 1NO
962 except Exception:
963 return -1
964 return 0 1NO
967cdef int _smv_current_work_stream(
968 _DLDeviceType device_type,
969 int32_t device_id,
970 void** out_current_stream,
971) noexcept with gil:
972 if out_current_stream == NULL: 2?b@b
973 cpython.PyErr_SetString(RuntimeError, b"out_current_stream cannot be NULL") 2?b
974 return -1 2?b
975 # cuda.core has no global/current stream state today.
976 out_current_stream[0] = NULL 2@b
977 return 0 2@b
980cdef void _init_smv_dlpack_exchange_api():
981 global _SMV_DLPACK_EXCHANGE_API_INITED
982 if _SMV_DLPACK_EXCHANGE_API_INITED:
983 return
984 _SMV_DLPACK_EXCHANGE_API.header.version.major = DLPACK_MAJOR_VERSION
985 _SMV_DLPACK_EXCHANGE_API.header.version.minor = DLPACK_MINOR_VERSION
986 _SMV_DLPACK_EXCHANGE_API.header.prev_api = NULL
987 _SMV_DLPACK_EXCHANGE_API.managed_tensor_allocator = _smv_managed_tensor_allocator
988 _SMV_DLPACK_EXCHANGE_API.managed_tensor_from_py_object_no_sync = _smv_managed_tensor_from_py_object_no_sync
989 _SMV_DLPACK_EXCHANGE_API.managed_tensor_to_py_object_no_sync = _smv_managed_tensor_to_py_object_no_sync
990 _SMV_DLPACK_EXCHANGE_API.dltensor_from_py_object_no_sync = _smv_dltensor_from_py_object_no_sync
991 _SMV_DLPACK_EXCHANGE_API.current_work_stream = _smv_current_work_stream
992 _SMV_DLPACK_EXCHANGE_API_INITED = True
995_init_smv_dlpack_exchange_api()
996# cdef classes are immutable types in Cython 3, so inject these attributes
997# directly into the type dict.
998(<dict>(<PyTypeObject*>StridedMemoryView).tp_dict)["__dlpack_c_exchange_api__"] = _SMV_DLPACK_EXCHANGE_API_CAPSULE
999(<dict>(<PyTypeObject*>StridedMemoryView).tp_dict)["__c_dlpack_exchange_api__"] = _SMV_DLPACK_EXCHANGE_API_CAPSULE
1000PyType_Modified(<PyTypeObject*>StridedMemoryView)
1003cdef str get_simple_repr(obj):
1004 # TODO: better handling in np.dtype objects
1005 cdef object obj_class
1006 cdef str obj_repr
1007 if isinstance(obj, type): 1;W
1008 obj_class = obj
1009 else:
1010 obj_class = obj.__class__ 1;W
1011 if obj_class.__module__ in (None, "builtins"): 1;W
1012 obj_repr = obj_class.__name__ 1;
1013 else:
1014 obj_repr = f"{obj_class.__module__}.{obj_class.__name__}" 1;W
1015 return obj_repr 1;W
1019cdef bint check_has_dlpack(obj) except*:
1020 cdef bint has_dlpack
1021 if hasattr(obj, "__dlpack__") and hasattr(obj, "__dlpack_device__"): 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) /bJ K I = ? s rb)b@ W / Y V : N O * g E o p t u v A B C D w x y z q G F l b h e m i j n k f d r a
1022 has_dlpack = True 1.+,[67Z0123895!#$%'()JKI=?sW/YV:NO*gEoptuvABCDwxyzqGFlbhemijnkfdra
1023 elif hasattr(obj, "__cuda_array_interface__"): 2/brb)b@
1024 has_dlpack = False 2rb)b@
1025 else:
1026 raise BufferError( 2/b
1027 "the input object does not support any data exchange protocol")
1028 return has_dlpack 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s rb)b@ W / Y V : N O * g E o p t u v A B C D w x y z q G F l b h e m i j n k f d r a
1031cdef class _StridedMemoryViewProxy:
1032 cdef readonly:
1033 object obj
1034 bint has_dlpack
1036 def __init__(self, obj: object) -> None:
1037 self.obj = obj 2Z 0 1 2 3 )b@
1038 self.has_dlpack = check_has_dlpack(obj) 2Z 0 1 2 3 )b@
1040 cpdef StridedMemoryView view(self, stream_ptr=None):
1041 if self.has_dlpack: 1Z0123@
1042 return StridedMemoryView.from_dlpack(self.obj, stream_ptr) 1Z0123
1043 else:
1044 return StridedMemoryView.from_cuda_array_interface(self.obj, stream_ptr) 1@
1047cdef StridedMemoryView view_as_dlpack(obj, stream_ptr, view=None):
1048 cdef int dldevice, device_id
1049 cdef bint is_device_accessible, is_readonly
1050 is_device_accessible = False 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
1051 dldevice, device_id = obj.__dlpack_device__() 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
1052 if dldevice == _kDLCPU: 2. + , [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c X #b9bb h e m i j n k f d r a $b
1053 assert device_id == 0 2, [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c #bb h e m i j n k f d r a
1054 device_id = -1 2, [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c #bb h e m i j n k f d r a
1055 if stream_ptr is None: 2, [ 6 7 Z 0 1 2 3 8 9 5 ! # $ % ' ( ) J K I = ? s W / Y V P Q R S T U : N O * g E o p t u v A B C D w x y z q G F l c #bb h e m i j n k f d r a
1056 raise BufferError("stream=None is ambiguous with view()") 2#b
1057 elif stream_ptr == -1: 1,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcbhemijnkfdra
1058 stream_ptr = None 1,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcbhemijnkfdra
1059 elif dldevice == _kDLCUDA:
1060 assert device_id >= 0 2X 9b
1061 is_device_accessible = True 2X 9b
1062 # no need to check other stream values, it's a pass-through
1063 if stream_ptr is None: 2X 9b
1064 raise BufferError("stream=None is ambiguous with view()") 29b
1065 elif dldevice in (_kDLCUDAHost, _kDLCUDAManaged):
1066 is_device_accessible = True 1.+
1067 # just do a pass-through without any checks, as pinned/managed memory can be
1068 # accessed on both host and device
1069 else:
1070 raise BufferError("device not supported") 2$b
1072 cdef object capsule
1073 try: 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1074 capsule = obj.__dlpack__( 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1075 stream=int(stream_ptr) if stream_ptr else None, 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1076 max_version=(DLPACK_MAJOR_VERSION, DLPACK_MINOR_VERSION)) 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1077 except TypeError: 1bda
1078 capsule = obj.__dlpack__( 1bda
1079 stream=int(stream_ptr) if stream_ptr else None) 1bda
1081 cdef void* data = NULL 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1082 cdef DLTensor* dl_tensor
1083 cdef DLManagedTensorVersioned* dlm_tensor_ver
1084 cdef DLManagedTensor* dlm_tensor
1085 cdef const char *used_name
1086 if cpython.PyCapsule_IsValid( 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1087 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME):
1088 data = cpython.PyCapsule_GetPointer( 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1089 capsule, DLPACK_VERSIONED_TENSOR_UNUSED_NAME)
1090 dlm_tensor_ver = <DLManagedTensorVersioned*>data 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1091 dl_tensor = &dlm_tensor_ver.dl_tensor 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1092 is_readonly = bool((dlm_tensor_ver.flags & DLPACK_FLAG_BITMASK_READ_ONLY) != 0) 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1093 used_name = DLPACK_VERSIONED_TENSOR_USED_NAME 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1094 elif cpython.PyCapsule_IsValid( 1bda
1095 capsule, DLPACK_TENSOR_UNUSED_NAME):
1096 data = cpython.PyCapsule_GetPointer( 1bda
1097 capsule, DLPACK_TENSOR_UNUSED_NAME)
1098 dlm_tensor = <DLManagedTensor*>data 1bda
1099 dl_tensor = &dlm_tensor.dl_tensor 1bda
1100 is_readonly = False 1bda
1101 used_name = DLPACK_TENSOR_USED_NAME 1bda
1102 else:
1103 assert False
1105 cpython.PyCapsule_SetName(capsule, used_name) 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1107 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1108 buf.dl_tensor = dl_tensor 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1109 buf.metadata = capsule 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1110 buf.ptr = <intptr_t>(dl_tensor.data) + <intptr_t>(dl_tensor.byte_offset) 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1111 buf.device_id = device_id 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1112 buf.is_device_accessible = is_device_accessible 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1113 buf.readonly = is_readonly 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1114 buf.exporting_obj = obj 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1116 return buf 1.+,[67Z0123895!#$%'()JKI=?sW/YVPQRSTU:NO*gEoptuvABCDwxyzqGFlcXbhemijnkfdra
1119@functools.lru_cache
1120def _typestr2dtype(str typestr) -> numpy.dtype:
1121 return numpy.dtype(typestr) 2H ] ^ _ ` { | } ~ abbb4brbc
1124@functools.lru_cache
1125def _typestr2itemsize(str typestr) -> int:
1126 return _typestr2dtype(typestr).itemsize 2H ] ^ _ ` { | } ~ abbb4brbc
1129cdef object dtype_dlpack_to_numpy(DLDataType* dtype):
1130 cdef int bits = dtype.bits 1sWPQRSTUNOgEoptuvABCDwxyzqGFlbhemijnkfdra
1131 if dtype.lanes != 1: 1sWPQRSTUNOgEoptuvABCDwxyzqGFlbhemijnkfdra
1132 # TODO: return a NumPy structured dtype?
1133 raise NotImplementedError( 1k
1134 f'vector dtypes (lanes={dtype.lanes}) is not supported') 1k
1135 if dtype.code == kDLUInt: 1sWPQRSTUNOgEoptuvABCDwxyzqGFlbhemijnkfdra
1136 if bits == 8: 1wxyzf
1137 np_dtype = numpy.uint8 1w
1138 elif bits == 16:
1139 np_dtype = numpy.uint16 1x
1140 elif bits == 32:
1141 np_dtype = numpy.uint32 1y
1142 elif bits == 64:
1143 np_dtype = numpy.uint64 1z
1144 else:
1145 raise TypeError('uint{} is not supported.'.format(bits)) 1f
1146 elif dtype.code == kDLInt:
1147 if bits == 8: 1sWPQRSTUNOABCDFlbhemijnkfdra
1148 np_dtype = numpy.int8 1A
1149 elif bits == 16:
1150 np_dtype = numpy.int16 1NB
1151 elif bits == 32:
1152 np_dtype = numpy.int32 1sWPQRSTUOCFlbhemijnkfdra
1153 elif bits == 64:
1154 np_dtype = numpy.int64 1D
1155 else:
1156 raise TypeError('int{} is not supported.'.format(bits)) 1n
1157 elif dtype.code == kDLFloat:
1158 if bits == 16: 1gtuvj
1159 np_dtype = numpy.float16 1t
1160 elif bits == 32:
1161 np_dtype = numpy.float32 1u
1162 elif bits == 64:
1163 np_dtype = numpy.float64 1gv
1164 else:
1165 raise TypeError('float{} is not supported.'.format(bits)) 1j
1166 elif dtype.code == kDLComplex:
1167 # TODO(leofang): support complex32
1168 if bits == 64: 1opqGi
1169 np_dtype = numpy.complex64 1o
1170 elif bits == 128:
1171 np_dtype = numpy.complex128 1pqG
1172 else:
1173 raise TypeError('complex{} is not supported.'.format(bits)) 1i
1174 elif dtype.code == kDLBool:
1175 if bits == 8: 1Ee
1176 np_dtype = numpy.bool_ 1E
1177 else:
1178 raise TypeError(f'{bits}-bit bool is not supported') 1e
1179 elif dtype.code == kDLBfloat:
1180 if bfloat16 is not None:
1181 np_dtype = numpy.dtype("bfloat16")
1182 else:
1183 raise NotImplementedError(
1184 'Support for bfloat16 within cuda-core requires `ml_dtypes`'
1185 'to be installed.'
1186 )
1187 else:
1188 raise TypeError('Unsupported dtype. dtype code: {}'.format(dtype.code)) 1m
1190 # We want the dtype object not just the type object
1191 return numpy.dtype(np_dtype) 1sWPQRSTUNOgEoptuvABCDwxyzqGFlbhemijnkfdra
1194cpdef StridedMemoryView view_as_cai(obj, stream_ptr, view=None):
1195 cdef dict cai_data = obj.__cuda_array_interface__ 2:b.b[b]bH qb4bsbrb@ -
1196 if cai_data.get("version", 0) < 3: 2:b.b[b]bH qb4bsbrb@ -
1197 raise BufferError("only CUDA Array Interface v3 or above is supported") 2[b]b
1198 if cai_data.get("mask") is not None: 2:b.bH qb4bsbrb@ -
1199 raise BufferError("mask is not supported") 2:b
1200 if stream_ptr is None: 2.bH qb4bsbrb@ -
1201 raise BufferError("stream=None is ambiguous with view()") 2.b
1203 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2H qb4bsbrb@ -
1204 buf.exporting_obj = obj 2H qb4bsbrb@ -
1205 buf.metadata = cai_data 2H qb4bsbrb@ -
1206 buf.dl_tensor = NULL 2H qb4bsbrb@ -
1207 # Validate shape/strides/typestr eagerly so constructor paths fail fast.
1208 buf.get_layout() 2H qb4bsbrb@ -
1209 buf.ptr, buf.readonly = cai_data["data"] 2H qbsbrb@ -
1210 buf.is_device_accessible = True 2H qbsbrb@ -
1211 if buf.ptr != 0: 2H qbsbrb@ -
1212 buf.device_id = handle_return( 1H-
1213 driver.cuPointerGetAttribute( 1H-
1214 driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL, 1H-
1215 buf.ptr)) 1H-
1216 else:
1217 buf.device_id = handle_return(driver.cuCtxGetDevice()) 2qbsbrb@
1219 cdef intptr_t producer_s, consumer_s
1220 cdef EventHandle h_event
1221 stream_ptr = int(stream_ptr) 2H qbsbrb@ -
1222 if stream_ptr != -1: 2H qbsbrb@ -
1223 stream = cai_data.get("stream") 1-
1224 if stream is not None: 1-
1225 producer_s = <intptr_t>(stream) 1-
1226 consumer_s = <intptr_t>(stream_ptr) 1-
1227 assert producer_s > 0 1-
1228 # establish stream order
1229 if producer_s != consumer_s: 1-
1230 with nogil: 1-
1231 # The event must belong to the producer stream's context to
1232 # be recorded on it, whatever context is current here.
1233 h_event = create_event_handle_for_stream( 1-
1234 <cydriver.CUstream>producer_s, cydriver.CUevent_flags.CU_EVENT_DISABLE_TIMING)
1235 if not h_event: 1-
1236 HANDLE_RETURN(get_last_error())
1237 HANDLE_RETURN(cydriver.cuEventRecord( 1-
1238 as_cu(h_event), <cydriver.CUstream>producer_s))
1239 HANDLE_RETURN(cydriver.cuStreamWaitEvent( 1-
1240 <cydriver.CUstream>consumer_s, as_cu(h_event), 0))
1241 elif _is_torch_tensor(obj):
1242 # PyTorch's __cuda_array_interface__ reports version 2 and
1243 # omits the "stream" field, so the standard CAI sync path
1244 # above is a no-op for torch tensors. This is unsafe: the
1245 # consumer has no guarantee that the producer's work is
1246 # visible. We fix this by querying PyTorch's current CUDA
1247 # stream via the AOTI stable C ABI and performing the same
1248 # event-based stream ordering.
1249 _get_tensor_bridge().sync_torch_stream(
1250 buf.device_id, <intptr_t>(stream_ptr))
1252 return buf 2H qbsbrb@ -
1255cpdef StridedMemoryView view_as_array_interface(obj, view=None):
1256 cdef dict data = obj.__array_interface__ 2;b^b_b] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
1257 if data.get("version", 0) < 3: 2;b^b_b] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
1258 raise BufferError("only NumPy Array Interface v3 or above is supported") 2^b_b
1259 if data.get("mask") is not None: 2;b] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
1260 raise BufferError("mask is not supported") 2;b
1262 cdef StridedMemoryView buf = StridedMemoryView() if view is None else view 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
1263 buf.exporting_obj = obj 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
1264 buf.metadata = data 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
1265 buf.dl_tensor = NULL 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
1266 # Validate shape/strides/typestr eagerly so constructor paths fail fast.
1267 buf.get_layout() 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bL c
1268 buf.ptr, buf.readonly = data["data"] 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbL c
1269 buf.is_device_accessible = False 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbL c
1270 buf.device_id = -1 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbL c
1271 return buf 2] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbL c
1274def args_viewable_as_strided_memory(arg_indices: tuple[int, ...]) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
1275 """
1276 Decorator to create proxy objects to :obj:`StridedMemoryView` for the
1277 specified positional arguments.
1279 This allows array/tensor attributes to be accessed inside the function
1280 implementation, while keeping the function body array-library-agnostic (if
1281 desired).
1283 Inside the decorated function, the specified arguments become instances
1284 of an (undocumented) proxy type, regardless of its original source. A
1285 :obj:`StridedMemoryView` instance can be obtained by passing the (consumer)
1286 stream pointer (as a Python `int`) to the proxies's ``view()`` method. For
1287 example:
1289 .. code-block:: python
1291 @args_viewable_as_strided_memory((1,))
1292 def my_func(arg0, arg1, arg2, stream: Stream):
1293 # arg1 can be any object supporting DLPack or CUDA Array Interface
1294 view = arg1.view(stream.handle)
1295 assert isinstance(view, StridedMemoryView)
1296 ...
1298 Parameters
1299 ----------
1300 arg_indices : tuple
1301 The indices of the target positional arguments.
1302 """
1303 def wrapped_func_with_indices(func: "Callable") -> "Callable": 1Z0123
1304 @functools.wraps(func) 1Z0123
1305 def wrapped_func(*args, **kwargs) -> object:
1306 args = list(args) 1Z0123
1307 cdef int idx
1308 for idx in arg_indices: 1Z0123
1309 args[idx] = _StridedMemoryViewProxy(args[idx]) 1Z0123
1310 return func(*args, **kwargs) 1Z0123
1311 return wrapped_func 1Z0123
1312 return wrapped_func_with_indices 1Z0123
1315cdef inline _StridedLayout layout_from_dlpack(DLTensor* dl_tensor):
1316 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 16Z0123895!#$%'()JKIsWYVPQRSTUNOgEoptuvABCDwxyzqGFlXbhemijnkfdra
1317 cdef int nbits = dl_tensor.dtype.bits * dl_tensor.dtype.lanes 16Z0123895!#$%'()JKIsWYVPQRSTUNOgEoptuvABCDwxyzqGFlXbhemijnkfdra
1318 cdef int itemsize = nbits >> 3 16Z0123895!#$%'()JKIsWYVPQRSTUNOgEoptuvABCDwxyzqGFlXbhemijnkfdra
1319 if (itemsize << 3) != nbits: 16Z0123895!#$%'()JKIsWYVPQRSTUNOgEoptuvABCDwxyzqGFlXbhemijnkfdra
1320 raise ValueError("dl_tensor.dtype.bits must be a multiple of 8")
1321 layout.init_from_ptr(dl_tensor.ndim, dl_tensor.shape, dl_tensor.strides, itemsize) 16Z0123895!#$%'()JKIsWYVPQRSTUNOgEoptuvABCDwxyzqGFlXbhemijnkfdra
1322 return layout 16Z0123895!#$%'()JKIsWYVPQRSTUNOgEoptuvABCDwxyzqGFlXbhemijnkfdra
1325cdef _StridedLayout layout_from_cai(object metadata):
1326 cdef _StridedLayout layout = _StridedLayout.__new__(_StridedLayout) 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsbrb@ - L c
1327 cdef object shape = metadata["shape"] 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsbrb@ - L c
1328 cdef object strides = metadata.get("strides") 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsbrb@ - L c
1329 cdef int itemsize = _typestr2itemsize(metadata["typestr"]) 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsbrb@ - L c
1330 layout.init_from_tuple(shape, strides, itemsize, True) 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbb8bqb4bsbrb@ - L c
1331 return layout 2H ] ^ cb_ db` eb{ | } fbgbhb~ ibjbabkblbmbnbobpbbbqbsbrb@ - L c
1334cdef inline intptr_t get_data_ptr(object buffer, _StridedLayout layout) except? 0:
1335 return <intptr_t>(int(buffer.handle)) + layout.get_slice_offset_in_bytes() 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1338cdef inline int view_buffer_strided(
1339 StridedMemoryView view,
1340 object buffer,
1341 _StridedLayout layout,
1342 object dtype,
1343 bint is_readonly,
1344) except -1:
1345 if isinstance(buffer, Buffer): 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7b4 ; Y V P Q R S T U X
1346 Buffer_check_open(<cyBuffer>buffer) 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7b4 ; Y V P Q R S T U X
1347 if dtype is not None: 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7b4 ; Y V P Q R S T U X
1348 dtype = numpy.dtype(dtype) 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7bY V P Q R S T U X
1349 if dtype.itemsize != layout.itemsize: 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7bY V P Q R S T U X
1350 raise ValueError( 1Y
1351 f"The dtype's itemsize ({dtype.itemsize}) does not match the layout's " 1Y
1352 f"itemsize ({layout.itemsize})." 1Y
1353 )
1354 # Check the layout's offset range [min_offset, max_offset] fits
1355 # within the [0, buffer.size - 1] range.
1356 # The required_size_in_bytes fails if min_offset < 0.
1357 # NB. For external memory, both positive and negative offsets can be valid,
1358 # but for a proper check we'd need to know both size and data offset,
1359 # while neither is reported by the packages.
1360 cdef bint is_allocated = buffer.memory_resource is not None 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7b4 ; V P Q R S T U X
1361 if is_allocated and buffer.size < layout.get_required_size_in_bytes(): 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b%bubvb!b7b4 ; V P Q R S T U X
1362 raise ValueError( 2!b
1363 f"Buffer size is too small for the layout. " 2!b
1364 f"Expected at least {layout.get_required_size_in_bytes()} bytes, " 2!b
1365 f"got {buffer.size} bytes." 2!b
1366 )
1367 # set the public attributes
1368 view.ptr = get_data_ptr(buffer, layout) 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1369 view.device_id = buffer.device_id 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1370 view.is_device_accessible = buffer.is_device_accessible 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1371 view.readonly = is_readonly 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1372 view.exporting_obj = view._buffer = buffer 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1373 # no dlpack/cai metadata
1374 view.dl_tensor = NULL 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1375 view.metadata = None 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1376 # we get the layout from the caller
1377 view._layout = layout 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1378 view._dtype = dtype 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X
1379 return 0 25b6bJ K I ybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3bubvb7b4 ; V P Q R S T U X