Coverage for cuda / core / _memory / _buffer.pyx: 89.73%
224 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-25 01:07 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-25 01:07 +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 libc.stdint cimport uintptr_t
10from cuda.bindings cimport cydriver
11from cuda.core._memory._device_memory_resource import DeviceMemoryResource
12from cuda.core._memory._pinned_memory_resource import PinnedMemoryResource
13from cuda.core._memory._ipc cimport IPCBufferDescriptor, IPCDataForBuffer
14from cuda.core._memory cimport _ipc
15from cuda.core._resource_handles cimport (
16 DevicePtrHandle,
17 StreamHandle,
18 deviceptr_create_with_owner,
19 deviceptr_create_with_mr,
20 register_mr_dealloc_callback,
21 as_intptr,
22 as_cu,
23 set_deallocation_stream,
24)
26from cuda.core._stream cimport Stream, Stream_accept
27from cuda.core._utils.cuda_utils cimport HANDLE_RETURN, _parse_fill_value
29import sys
30from typing import TypeVar
32if sys.version_info >= (3, 12):
33 from collections.abc import Buffer as BufferProtocol
34else:
35 BufferProtocol = object
37from cuda.core._dlpack import DLDeviceType, make_py_capsule
38from cuda.core._utils.cuda_utils import driver
39from cuda.core._device import Device
42# =============================================================================
43# MR deallocation callback (invoked from C++ shared_ptr deleter)
44# =============================================================================
46cdef void _mr_dealloc_callback(
47 object mr,
48 cydriver.CUdeviceptr ptr,
49 size_t size,
50 const StreamHandle& h_stream,
51) noexcept:
52 """Called by the C++ deleter to deallocate via MemoryResource.deallocate."""
53 try: 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 Yel m p q n o .cZePcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNcibc d lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfcbccc6bdcr
54 stream = None 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 Yel m p q n o .cZePcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNcibc d lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfcbccc6bdcr
55 if h_stream: 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 Yel m p q n o .cZePcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNcibc d lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfcbccc6bdcr
56 stream = Stream._from_handle(Stream, h_stream) 2fc
57 mr.deallocate(int(ptr), size, stream) 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 Yel m p q n o .cZePcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNcibc d lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfcbccc6bdcr
58 except Exception as exc: 26b
59 print(f"Warning: mr.deallocate() failed during Buffer destruction: {exc}", 26b
60 file=sys.stderr) 26b
62register_mr_dealloc_callback(_mr_dealloc_callback)
65__all__ = ['Buffer', 'MemoryResource']
68DevicePointerT = driver.CUdeviceptr | int | None
69"""
70A type union of :obj:`~driver.CUdeviceptr`, `int` and `None` for hinting
71:attr:`Buffer.handle`.
72"""
74cdef class Buffer:
75 """Represent a handle to allocated memory.
77 This generic object provides a unified representation for how
78 different memory resources are to give access to their memory
79 allocations.
81 Support for data interchange mechanisms are provided by DLPack.
82 """
83 def __cinit__(self):
84 self._clear() 2H I J :c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d.c^cTe,c_cVc4cWc-cXcYcZc0c5cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cSc/cfc2cTc9bOc3cbccc6bdcr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRdB C D E F G
86 def _clear(self):
87 self._h_ptr.reset() # Release the handle 2H I J :c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d.c^cTe,c_cVc4cWc-cXcYcZc0c5cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cSc/cfc2cTc9bOc3cbccc6bdcr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRdB C D E F G
88 self._size = 0 2H I J :c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d.c^cTe,c_cVc4cWc-cXcYcZc0c5cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cSc/cfc2cTc9bOc3cbccc6bdcr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRdB C D E F G
89 self._memory_resource = None 2H I J :c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d.c^cTe,c_cVc4cWc-cXcYcZc0c5cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cSc/cfc2cTc9bOc3cbccc6bdcr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRdB C D E F G
90 self._ipc_data = None 2H I J :c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d.c^cTe,c_cVc4cWc-cXcYcZc0c5cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cSc/cfc2cTc9bOc3cbccc6bdcr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRdB C D E F G
91 self._owner = None 2H I J :c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d.c^cTe,c_cVc4cWc-cXcYcZc0c5cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cSc/cfc2cTc9bOc3cbccc6bdcr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRdB C D E F G
92 self._mem_attrs_inited = False 2H I J :c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d.c^cTe,c_cVc4cWc-cXcYcZc0c5cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cSc/cfc2cTc9bOc3cbccc6bdcr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRdB C D E F G
94 def __init__(self, *args, **kwargs):
95 raise RuntimeError("Buffer objects cannot be instantiated directly. "
96 "Please use MemoryResource APIs.")
98 @classmethod
99 def _init(
100 cls, ptr: DevicePointerT, size_t size, mr: MemoryResource | None = None,
101 ipc_descriptor: IPCBufferDescriptor | None = None,
102 owner : object | None = None
103 ):
104 """Create a Buffer from a raw pointer.
106 When ``mr`` is provided, the buffer takes ownership: ``mr.deallocate()``
107 is called when the buffer is closed or garbage collected. When ``owner``
108 is provided, the owner is kept alive but no deallocation is performed.
109 """
110 if mr is not None and owner is not None: 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb0eSc/cfc2cbccc6bdcr gcB C D E F G
111 raise ValueError("owner and memory resource cannot be both specified together") 20e
112 cdef Buffer self = Buffer.__new__(cls) 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
113 cdef uintptr_t c_ptr = <uintptr_t>(int(ptr)) 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
114 if mr is not None: 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
115 self._h_ptr = deviceptr_create_with_mr(c_ptr, size, mr) 2hbH I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNcibc d lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfcbccc6bdcr
116 else:
117 self._h_ptr = deviceptr_create_with_owner(c_ptr, owner) 2a b k s t c d e f 2cgcB C D E F G
118 self._size = size 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
119 self._memory_resource = mr 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
120 self._ipc_data = IPCDataForBuffer(ipc_descriptor, True) if ipc_descriptor is not None else None 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
121 self._owner = owner 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
122 self._mem_attrs_inited = False 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
123 return self 2H I J g h i j u v w x y z A K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o .cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSbSc/cfc2cbccc6bdcr gcB C D E F G
125 @staticmethod
126 def _reduce_helper(mr, ipc_descriptor):
127 return Buffer.from_ipc_descriptor(mr, ipc_descriptor)
129 def __reduce__(self):
130 # Must not serialize the parent's stream!
131 return Buffer._reduce_helper, (self.memory_resource, self.get_ipc_descriptor()) 2SdTdUdVd| } WdXdYdZd0d1d#c$c%c'c~ abbbcbdbebfbgb(c)c*c+cl m n o
133 @staticmethod
134 def from_handle(
135 ptr: DevicePointerT, size_t size, mr: MemoryResource | None = None,
136 owner: object | None = None,
137 ) -> Buffer:
138 """Create a new :class:`Buffer` object from a pointer.
140 Parameters
141 ----------
142 ptr : :obj:`~_memory.DevicePointerT`
143 Allocated buffer handle object
144 size : int
145 Memory size of the buffer
146 mr : :obj:`~_memory.MemoryResource`, optional
147 Memory resource associated with the buffer. When provided,
148 :meth:`MemoryResource.deallocate` is called when the buffer is
149 closed or garbage collected.
150 owner : object, optional
151 An object holding external allocation that the ``ptr`` points to.
152 The reference is kept as long as the buffer is alive.
153 The ``owner`` and ``mr`` cannot be specified together.
155 Note
156 ----
157 When neither ``mr`` nor ``owner`` is specified, this creates a
158 non-owning reference. The pointer will NOT be freed when the
159 :class:`Buffer` is closed or garbage collected.
160 """
161 return Buffer._init(ptr, size, mr=mr, owner=owner) 2g h i j u v w x y z A | } ~ abbbcbdbebfbgbl m p q n o PcQcRchc5bRbecicjckcMcNciba b k s t c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb0eSc/cfc2cbccc6bdcgcB C D E F G
163 @classmethod
164 def from_ipc_descriptor(
165 cls, mr: DeviceMemoryResource | PinnedMemoryResource, ipc_descriptor: IPCBufferDescriptor,
166 stream: Stream = None
167 ) -> Buffer:
168 """Import a buffer that was exported from another process."""
169 return _ipc.Buffer_from_ipc_descriptor(cls, mr, ipc_descriptor, stream) 21c3c
171 def get_ipc_descriptor(self) -> IPCBufferDescriptor:
172 """Export a buffer allocated for sharing between processes."""
173 if self._ipc_data is None: 2SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o 1cOc3c#d$d
174 self._ipc_data = IPCDataForBuffer(_ipc.Buffer_get_ipc_descriptor(self), False) 2SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o 1cOc3c#d$d
175 return self._ipc_data.ipc_descriptor 2SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o Oc#d$d
177 def close(self, stream: Stream | GraphBuilder | None = None):
178 """Deallocate this buffer asynchronously on the given stream.
180 This buffer is released back to their memory resource
181 asynchronously on the given stream.
183 Parameters
184 ----------
185 stream : :obj:`~_stream.Stream` | :obj:`~_graph.GraphBuilder`, optional
186 The stream object to use for asynchronous deallocation. If None,
187 the deallocation stream stored in the handle is used.
188 """
189 Buffer_close(self, stream) 2H I J :c;c=cg h i j u v w x y z A 8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 l m p q n o ^c,c_cVc4cWc-cXcYcZc0c5chc5bRba b k c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b`c{c|c}c~cadbdcdddedfdgdhd1cScfc2cTc9bOc3cbccc6bdc
191 def __enter__(self):
192 return self 2Vc4cWcYcZc0c5c
194 def __exit__(self, exc_type, exc_val, exc_tb):
195 self.close() 2Vc4cWcYcZc0c5c
196 return False 2Vc4cWcYcZc0c5c
198 def copy_to(self, dst: Buffer = None, *, stream: Stream | GraphBuilder) -> Buffer:
199 """Copy from this buffer to the dst buffer asynchronously on the given stream.
201 Copies the data from this buffer to the provided dst buffer.
202 If the dst buffer is not provided, then a new buffer is first
203 allocated using the associated memory resource before the copy.
205 Parameters
206 ----------
207 dst : :obj:`~_memory.Buffer`
208 Source buffer to copy data from
209 stream : :obj:`~_stream.Stream` | :obj:`~_graph.GraphBuilder`
210 Keyword argument specifying the stream for the
211 asynchronous copy
213 """
214 cdef Stream s = Stream_accept(stream) 2Rb7b8b9br
215 cdef size_t src_size = self._size 2Rb7b8b9br
217 if dst is None: 2Rb7b8b9br
218 if self._memory_resource is None:
219 raise ValueError("a destination buffer must be provided (this "
220 "buffer does not have a memory_resource)")
221 dst = self._memory_resource.allocate(src_size, s)
223 cdef size_t dst_size = dst._size 2Rb7b8b9br
224 if dst_size != src_size: 2Rb7b8b9br
225 raise ValueError( "buffer sizes mismatch between src and dst (sizes "
226 f"are: src={src_size}, dst={dst_size})"
227 )
228 with nogil: 2Rb7b8b9br
229 HANDLE_RETURN(cydriver.cuMemcpyAsync( 2Rb7b8b9br
230 as_cu(dst._h_ptr), as_cu(self._h_ptr), src_size, as_cu(s._h_stream)))
231 return dst 2Rb7b8b9br
233 def copy_from(self, src: Buffer, *, stream: Stream | GraphBuilder):
234 """Copy from the src buffer to this buffer asynchronously on the given stream.
236 Parameters
237 ----------
238 src : :obj:`~_memory.Buffer`
239 Source buffer to copy data from
240 stream : :obj:`~_stream.Stream` | :obj:`~_graph.GraphBuilder`
241 Keyword argument specifying the stream for the
242 asynchronous copy
244 """
245 cdef Stream s = Stream_accept(stream) 2g h i j u v w x y z A | } ~ abbbcbdbebfbgbl m p q n o PcQcRc5b
246 cdef size_t dst_size = self._size 2g h i j u v w x y z A | } ~ abbbcbdbebfbgbl m p q n o PcQcRc5b
247 cdef size_t src_size = src._size 2g h i j u v w x y z A | } ~ abbbcbdbebfbgbl m p q n o PcQcRc5b
249 if src_size != dst_size: 2g h i j u v w x y z A | } ~ abbbcbdbebfbgbl m p q n o PcQcRc5b
250 raise ValueError( "buffer sizes mismatch between src and dst (sizes "
251 f"are: src={src_size}, dst={dst_size})"
252 )
253 with nogil: 2g h i j u v w x y z A | } ~ abbbcbdbebfbgbl m p q n o PcQcRc5b
254 HANDLE_RETURN(cydriver.cuMemcpyAsync( 2g h i j u v w x y z A | } ~ abbbcbdbebfbgbl m p q n o PcQcRc5b
255 as_cu(self._h_ptr), as_cu(src._h_ptr), dst_size, as_cu(s._h_stream)))
257 def fill(self, value: int | BufferProtocol, *, stream: Stream | GraphBuilder):
258 """Fill this buffer with a repeating byte pattern.
260 Parameters
261 ----------
262 value : int | :obj:`collections.abc.Buffer`
263 - int: Must be in range [0, 256). Converted to 1 byte.
264 - :obj:`collections.abc.Buffer`: Must be 1, 2, or 4 bytes.
265 stream : :obj:`~_stream.Stream` | :obj:`~_graph.GraphBuilder`
266 Stream for the asynchronous fill operation.
268 Raises
269 ------
270 TypeError
271 If value is not an int and does not support the buffer protocol.
272 ValueError
273 If value byte length is not 1, 2, or 4.
274 If buffer size is not divisible by value byte length.
275 OverflowError
276 If int value is outside [0, 256).
278 """
279 cdef Stream s_stream = Stream_accept(stream) 2g h i j lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLc
280 cdef unsigned int val
281 cdef unsigned int elem_size
282 val, elem_size = _parse_fill_value(value) 2g h i j lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLc
284 cdef size_t buffer_size = self._size 2g h i j KbTbjbUbkbLblbMbNbObmbnbobpbqbrbPbQbsbtbVbubvbWbwbXb8 Yb9 xb! ybzbAb# $ % ' ( ) BbCb* + Zb, - 0bDb1b. 2b/ Eb: FbGbHb; = ? @ [ ] IbJb^ _ 3b` { 4b
285 cdef cydriver.CUdeviceptr dst = as_cu(self._h_ptr) 2g h i j KbTbjbUbkbLblbMbNbObmbnbobpbqbrbPbQbsbtbVbubvbWbwbXb8 Yb9 xb! ybzbAb# $ % ' ( ) BbCb* + Zb, - 0bDb1b. 2b/ Eb: FbGbHb; = ? @ [ ] IbJb^ _ 3b` { 4b
286 cdef cydriver.CUstream s = as_cu(s_stream._h_stream) 2g h i j KbTbjbUbkbLblbMbNbObmbnbobpbqbrbPbQbsbtbVbubvbWbwbXb8 Yb9 xb! ybzbAb# $ % ' ( ) BbCb* + Zb, - 0bDb1b. 2b/ Eb: FbGbHb; = ? @ [ ] IbJb^ _ 3b` { 4b
288 if elem_size == 1: 2g h i j KbTbjbUbkbLblbMbNbObmbnbobpbqbrbPbQbsbtbVbubvbWbwbXb8 Yb9 xb! ybzbAb# $ % ' ( ) BbCb* + Zb, - 0bDb1b. 2b/ Eb: FbGbHb; = ? @ [ ] IbJb^ _ 3b` { 4b
289 with nogil: 2g h i j KbLbMbNbObPbQbwbxbybzbAbBbCbDbEbFbGbHbIbJb
290 HANDLE_RETURN(cydriver.cuMemsetD8Async(dst, val, buffer_size, s)) 2g h i j KbLbMbNbObPbQbwbxbybzbAbBbCbDbEbFbGbHbIbJb
291 elif elem_size == 2:
292 if buffer_size & 0x1: 2TbjbmbnbobsbtbVbXb8 # $ % * + Zb1b. ; = ? ^ _ 3b
293 raise ValueError(f"buffer size ({buffer_size}) must be divisible by 2") 2TbVbXbZb1b3b
294 with nogil: 2jbmbnbobsbtb8 # $ % * + . ; = ? ^ _
295 HANDLE_RETURN(cydriver.cuMemsetD16Async(dst, val, buffer_size // 2, s)) 2jbmbnbobsbtb8 # $ % * + . ; = ? ^ _
296 elif elem_size == 4:
297 if buffer_size & 0x3: 2UbkblbpbqbrbubvbWbYb9 ! ' ( ) , - 0b2b/ : @ [ ] ` { 4b
298 raise ValueError(f"buffer size ({buffer_size}) must be divisible by 4") 2UbWbYb0b2b4b
299 with nogil: 2kblbpbqbrbubvb9 ! ' ( ) , - / : @ [ ] ` {
300 HANDLE_RETURN(cydriver.cuMemsetD32Async(dst, val, buffer_size // 4, s)) 2kblbpbqbrbubvb9 ! ' ( ) , - / : @ [ ] ` {
302 def __dlpack__(
303 self,
304 *,
305 stream: int | None = None,
306 max_version: tuple[int, int] | None = None,
307 dl_device: tuple[int, int] | None = None,
308 copy: bool | None = None,
309 ) -> TypeVar("PyCapsule"):
310 # Note: we ignore the stream argument entirely (as if it is -1).
311 # It is the user's responsibility to maintain stream order.
312 if dl_device is not None: 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecibr
313 raise BufferError("Sorry, not supported: dl_device other than None") 2ib
314 if copy is True: 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecibr
315 raise BufferError("Sorry, not supported: copy=True") 2ib
316 if max_version is None: 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecibr
317 versioned = False 2ecib
318 else:
319 if not isinstance(max_version, tuple) or len(max_version) != 2: 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacibr
320 raise BufferError(f"Expected max_version tuple[int, int], got {max_version}") 2ib
321 versioned = max_version >= (1, 0) 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacibr
322 capsule = make_py_capsule(self, versioned) 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecibr
323 return capsule 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacibr
325 def __dlpack_device__(self) -> tuple[int, int]:
326 cdef bint d = self.is_device_accessible 2icjckcMcNc
327 cdef bint h = self.is_host_accessible 2icjckcMcNc
328 if d and (not h): 2icjckcMcNc
329 return (DLDeviceType.kDLCUDA, self.device_id) 2jc
330 if d and h: 2ickcMcNc
331 # TODO: this can also be kDLCUDAManaged, we need more fine-grained checks
332 return (DLDeviceType.kDLCUDAHost, 0) 2McNc
333 if (not d) and h: 2ickc
334 return (DLDeviceType.kDLCPU, 0) 2kc
335 raise BufferError("buffer is neither device-accessible nor host-accessible") 2ic
337 def __buffer__(self, flags: int, /) -> memoryview:
338 # Support for Python-level buffer protocol as per PEP 688.
339 # This raises a BufferError unless:
340 # 1. Python is 3.12+
341 # 2. This Buffer object is host accessible
342 raise NotImplementedError("WIP: Buffer.__buffer__ hasn't been implemented yet.")
344 def __release_buffer__(self, buffer: memoryview, /):
345 # Supporting method paired with __buffer__.
346 raise NotImplementedError("WIP: Buffer.__release_buffer__ hasn't been implemented yet.")
348 @property
349 def device_id(self) -> int:
350 """Return the device ordinal of this buffer."""
351 if self._memory_resource is not None: 2(d)d*d+d,djciba b k s t c d e f 6c7c-d.d/dTcbcccdcidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdB C D E F G
352 return self._memory_resource.device_id 2(d)d*d+d,djcib6c7c-d.d/dTcbcccdcidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRd
353 _init_mem_attrs(self) 1abkstcdefBCDEFG
354 return self._mem_attrs.device_id 1abkstcdefBCDEFG
356 @property
357 def handle(self) -> DevicePointerT:
358 """Return the buffer handle object.
360 .. caution::
362 This handle is a Python object. To get the memory address of the underlying C
363 handle, call ``int(Buffer.handle)``.
364 """
365 # Return raw integer for compatibility with ctypes and other tools
366 # that expect a raw pointer value
367 return as_intptr(self._h_ptr) 2H I J g h i j u v w x y z A (d)d*dK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 | } ~ abbbcbdbebfbgbl m p q n o +d,d.c,cVcWcXc0cPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bachc5bRbeciba b c d wb8 9 xb! ybzbAb# $ % ' ( ) BbCb* + , - Db. / Eb: FbGbHb; = ? @ [ ] IbJb^ _ ` { Sb7b8b-d.d/d9b6bdcr 2dgcidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdB C D E F G
369 def __eq__(self, other) -> bool:
370 if not isinstance(other, Buffer): 22dgc=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele;d%d'd
371 return NotImplemented 22d=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele
372 cdef Buffer other_buf = <Buffer>other 22dgc;d%d'd
373 return (as_intptr(self._h_ptr) == as_intptr(other_buf._h_ptr) and 22dgc;d%d'd
374 self._size == other_buf._size) 22dgc%d'd
376 def __hash__(self) -> int:
377 return hash((as_intptr(self._h_ptr), self._size)) 2gcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNeOePe%d'd
379 def __repr__(self) -> str:
380 maybe_is_mapped = " is_mapped=True" if self.is_mapped else "" 2| } ?c@c#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+c:d
381 return f"<Buffer ptr={as_intptr(self._h_ptr):#x} size={self._size}{maybe_is_mapped}>" 2| } ?c@c#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+c:d
383 @property
384 def is_device_accessible(self) -> bool:
385 """Return True if this buffer can be accessed by the GPU, otherwise False."""
386 if self._memory_resource is not None: 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecicjckcMcNciba b k s t c d e f SbUcTcOcr idjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdB C D E F G
387 return self._memory_resource.is_device_accessible 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecicjckcMcNcibSbUcTcOcr idjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRd
388 _init_mem_attrs(self) 1abkstcdefBCDEFG
389 return self._mem_attrs.is_device_accessible 1abkstcdefBCDEFG
391 @property
392 def is_host_accessible(self) -> bool:
393 """Return True if this buffer can be accessed by the CPU, otherwise False."""
394 if self._memory_resource is not None: 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecicjckcMcNciba b k s t c d e f KbjbkbLblbMbNbObmbnbobpbqbrbPbQbsbtbubvbwb8 9 xb! ybzbAb# $ % ' ( ) BbCb* + , - Db. / Eb: FbGbHb; = ? @ [ ] IbJb^ _ ` { SbUcTcOcr
395 return self._memory_resource.is_host_accessible 2H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 !b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecicjckcMcNcibKbjbkbLblbMbNbObmbnbobpbqbrbPbQbsbtbubvbwb8 9 xb! ybzbAb# $ % ' ( ) BbCb* + , - Db. / Eb: FbGbHb; = ? @ [ ] IbJb^ _ ` { SbUcTcOcr
396 _init_mem_attrs(self) 1abkstcdef
397 return self._mem_attrs.is_host_accessible 1abkstcdef
399 @property
400 def is_mapped(self) -> bool:
401 """Return True if this buffer is mapped into the process via IPC."""
402 return getattr(self._ipc_data, "is_mapped", False) 2| } ?c@c#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cSb:d
405 @property
406 def memory_resource(self) -> MemoryResource:
407 """Return the memory resource associated with this buffer."""
408 return self._memory_resource 2g h i j u v w x y z A SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o hcSb7bUc8b1cTc9bOc3cbccc#d$didjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeOdPdneQdRdB C D E F G
410 @property
411 def size(self) -> int:
412 """Return the memory size of this buffer."""
413 return self._size 2H I J g h i j u v w x y z A (d)d*dK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 SdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,dVcWc-cXcYcZcPcQcRc!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacecibSb6c7c7bUc8b-d.d/dTc9bOcbccc6bdcr gc#d$didjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeOdPdneQdRd
415 @property
416 def owner(self) -> object:
417 """Return the object holding external allocation."""
418 return self._owner
421# Memory Attribute Query Helpers
422# ------------------------------
423cdef inline void _init_mem_attrs(Buffer self):
424 """Initialize memory attributes by querying the pointer."""
425 if not self._mem_attrs_inited: 1abkstcdefBCDEFG
426 _query_memory_attrs(self._mem_attrs, as_cu(self._h_ptr)) 1abkstcdefBCDEFG
427 self._mem_attrs_inited = True 1abkstcdefBCDEFG
430cdef inline int _query_memory_attrs(
431 _MemAttrs& out,
432 cydriver.CUdeviceptr ptr
433) except -1 nogil:
434 """Query memory attributes for a device pointer."""
435 cdef unsigned int memory_type = 0 1abkstcdefBCDEFG
436 cdef int is_managed = 0 1abkstcdefBCDEFG
437 cdef int device_id = 0 1abkstcdefBCDEFG
438 cdef cydriver.CUpointer_attribute attrs[3]
439 cdef uintptr_t vals[3]
441 attrs[0] = cydriver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_MEMORY_TYPE 1abkstcdefBCDEFG
442 attrs[1] = cydriver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_IS_MANAGED 1abkstcdefBCDEFG
443 attrs[2] = cydriver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL 1abkstcdefBCDEFG
444 vals[0] = <uintptr_t><void*>&memory_type 1abkstcdefBCDEFG
445 vals[1] = <uintptr_t><void*>&is_managed 1abkstcdefBCDEFG
446 vals[2] = <uintptr_t><void*>&device_id 1abkstcdefBCDEFG
448 cdef cydriver.CUresult ret
449 ret = cydriver.cuPointerGetAttributes(3, attrs, <void**>vals, ptr) 1abkstcdefBCDEFG
450 if ret == cydriver.CUresult.CUDA_ERROR_NOT_INITIALIZED: 1abkstcdefBCDEFG
451 with cython.gil:
452 # Device class handles the cuInit call internally
453 Device()
454 ret = cydriver.cuPointerGetAttributes(3, attrs, <void**>vals, ptr)
455 HANDLE_RETURN(ret) 1abkstcdefBCDEFG
457 if memory_type == 0: 1abkstcdefBCDEFG
458 # unregistered host pointer
459 out.is_host_accessible = True 1kefBCDEFG
460 out.is_device_accessible = False 1kefBCDEFG
461 out.device_id = -1 1kefBCDEFG
462 elif ( 1abstcdef
463 is_managed 1abstcdef
464 or memory_type == cydriver.CUmemorytype.CU_MEMORYTYPE_HOST 1abcdef
465 ):
466 # Managed memory or pinned host memory
467 out.is_host_accessible = True 1stcdef
468 out.is_device_accessible = True 1stcdef
469 out.device_id = device_id 1stcdef
470 elif memory_type == cydriver.CUmemorytype.CU_MEMORYTYPE_DEVICE: 1ab
471 out.is_host_accessible = False 1ab
472 out.is_device_accessible = True 1ab
473 out.device_id = device_id 1ab
474 else:
475 with cython.gil:
476 raise ValueError(f"Unsupported memory type: {memory_type}")
477 return 0 1abkstcdefBCDEFG
480cdef class MemoryResource:
481 """Abstract base class for memory resources that manage allocation and
482 deallocation of buffers.
484 Subclasses must implement methods for allocating and deallocation, as well
485 as properties associated with this memory resource from which all allocated
486 buffers will inherit. (Since all :class:`Buffer` instances allocated and
487 returned by the :meth:`allocate` method would hold a reference to self, the
488 buffer properties are retrieved simply by looking up the underlying memory
489 resource's respective property.)
490 """
492 def allocate(self, size_t size, stream: Stream | GraphBuilder | None = None) -> Buffer:
493 """Allocate a buffer of the requested size.
495 Parameters
496 ----------
497 size : int
498 The size of the buffer to allocate, in bytes.
499 stream : :obj:`~_stream.Stream` | :obj:`~_graph.GraphBuilder`, optional
500 The stream on which to perform the allocation asynchronously.
501 If None, it is up to each memory resource implementation to decide
502 and document the behavior.
504 Returns
505 -------
506 Buffer
507 The allocated buffer object, which can be used for device or host operations
508 depending on the resource's properties.
509 """
510 raise TypeError("MemoryResource.allocate must be implemented by subclasses.") 2Sb
512 def deallocate(self, ptr: DevicePointerT, size_t size, stream: Stream | GraphBuilder | None = None):
513 """Deallocate a buffer previously allocated by this resource.
515 Parameters
516 ----------
517 ptr : :obj:`~_memory.DevicePointerT`
518 The pointer or handle to the buffer to deallocate.
519 size : int
520 The size of the buffer to deallocate, in bytes.
521 stream : :obj:`~_stream.Stream` | :obj:`~_graph.GraphBuilder`, optional
522 The stream on which to perform the deallocation asynchronously.
523 If None, it is up to each memory resource implementation to decide
524 and document the behavior.
525 """
526 raise TypeError("MemoryResource.deallocate must be implemented by subclasses.")
528 @property
529 def is_device_accessible(self) -> bool:
530 """Whether buffers allocated by this resource are device-accessible."""
531 raise TypeError("MemoryResource.is_device_accessible must be implemented by subclasses.")
533 @property
534 def is_host_accessible(self) -> bool:
535 """Whether buffers allocated by this resource are host-accessible."""
536 raise TypeError("MemoryResource.is_host_accessible must be implemented by subclasses.")
538 @property
539 def device_id(self) -> int:
540 """Device ID associated with this memory resource, or -1 if not applicable."""
541 raise TypeError("MemoryResource.device_id must be implemented by subclasses.")
544# Buffer Implementation Helpers
545# -----------------------------
546cdef inline Buffer Buffer_from_deviceptr_handle(
547 DevicePtrHandle h_ptr,
548 size_t size,
549 MemoryResource mr,
550 object ipc_descriptor = None
551):
552 """Create a Buffer from an existing DevicePtrHandle."""
553 cdef Buffer buf = Buffer.__new__(Buffer) 2:c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cSdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d^cTe,c_cVc4cWc-cXcYcZc0c5ca b 6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cTc9bOc3cr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRd
554 buf._h_ptr = h_ptr 2:c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cSdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d^cTe,c_cVc4cWc-cXcYcZc0c5ca b 6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cTc9bOc3cr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRd
555 buf._size = size 2:c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cSdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d^cTe,c_cVc4cWc-cXcYcZc0c5ca b 6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cTc9bOc3cr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRd
556 buf._memory_resource = mr 2:c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cSdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d^cTe,c_cVc4cWc-cXcYcZc0c5ca b 6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cTc9bOc3cr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRd
557 buf._ipc_data = IPCDataForBuffer(ipc_descriptor, True) if ipc_descriptor is not None else None 2:c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cSdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d^cTe,c_cVc4cWc-cXcYcZc0c5ca b 6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cTc9bOc3cr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRd
558 buf._owner = None 2:c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cSdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d^cTe,c_cVc4cWc-cXcYcZc0c5ca b 6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cTc9bOc3cr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRd
559 buf._mem_attrs_inited = False 2:c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cSdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d^cTe,c_cVc4cWc-cXcYcZc0c5ca b 6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cTc9bOc3cr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRd
560 return buf 2:c;c=cQeReSeg h i j u v w x y z A (d)d*d8c9c!cSdTdUdVd3d4d| } ?c@cWd5dXd6dYd7dZd8d0d9d1d!d#c$c[c]c%c'c~ abbbcbdbebfbgb(c)c*c+cl m p q n o +d,d^cTe,c_cVc4cWc-cXcYcZc0c5ca b 6c7c7bUc8b-d.d/d`c{c|c}c~cadbdcdddedfdgdhd1cTc9bOc3cr 2dgcoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNe=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekele#d$d:d;dOePe%d'dUeVeidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdmeWeXeOdPdneQdRd
563cdef inline void Buffer_close(Buffer self, object stream):
564 """Close a buffer, freeing its memory."""
565 cdef Stream s
566 if not self._h_ptr: 2H I J :c;c=cg h i j u v w x y z A 8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 l m p q n o ^c,c_cVc4cWc-cXcYcZc0c5chc5bRba b k c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b`c{c|c}c~cadbdcdddedfdgdhd1cScfc2cTc9bOc3cbccc6bdc
567 return
568 # Update deallocation stream if provided
569 if stream is not None: 2H I J :c;c=cg h i j u v w x y z A 8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 l m p q n o ^c,c_cVc4cWc-cXcYcZc0c5chc5bRba b k c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b`c{c|c}c~cadbdcdddedfdgdhd1cScfc2cTc9bOc3cbccc6bdc
570 s = Stream_accept(stream) 28c9c!cXc7b8bfc9b
571 set_deallocation_stream(self._h_ptr, s._h_stream) 28c9c!cXc7b8bfc9b
572 # Reset handle - RAII deleter will free the memory (and release owner ref in C++)
573 self._h_ptr.reset() 2H I J :c;c=cg h i j u v w x y z A 8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 l m p q n o ^c,c_cVc4cWc-cXcYcZc0c5chc5bRba b k c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b`c{c|c}c~cadbdcdddedfdgdhd1cScfc2cTc9bOc3cbccc6bdc
574 self._size = 0 2H I J :c;c=cg h i j u v w x y z A 8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 l m p q n o ^c,c_cVc4cWc-cXcYcZc0c5chc5bRba b k c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b`c{c|c}c~cadbdcdddedfdgdhd1cScfc2cTc9bOc3cbccc6bdc
575 self._memory_resource = None 2H I J :c;c=cg h i j u v w x y z A 8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 l m p q n o ^c,c_cVc4cWc-cXcYcZc0c5chc5bRba b k c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b`c{c|c}c~cadbdcdddedfdgdhd1cScfc2cTc9bOc3cbccc6bdc
576 self._ipc_data = None 2H I J :c;c=cg h i j u v w x y z A 8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 l m p q n o ^c,c_cVc4cWc-cXcYcZc0c5chc5bRba b k c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b`c{c|c}c~cadbdcdddedfdgdhd1cScfc2cTc9bOc3cbccc6bdc
577 self._owner = None 2H I J :c;c=cg h i j u v w x y z A 8c9c!cK L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 l m p q n o ^c,c_cVc4cWc-cXcYcZc0c5chc5bRba b k c d e f lcmcKbTbjbncUbkbLbocpcqclbrcMbNbObmbnbobpbqbrbscPbQbsbtbVbubvbWbtcucvcwbXb8 wcYb9 xbxcyczc! AcybzbAb# $ % ' ( ) BcBbCb* + Zb, - 0bCcDcEcDb1b. Fc2b/ EbGcHcIc: JcFbGbHb; = ? @ [ ] KcIbJb^ _ 3b` { 4bLcSb6c7c7bUc8b`c{c|c}c~cadbdcdddedfdgdhd1cScfc2cTc9bOc3cbccc6bdc