Coverage for cuda / core / _module.pyx: 88.96%
317 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-08 01:07 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-08 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
7from libc.stddef cimport size_t
9import functools
10import threading
11from collections import namedtuple
13from cuda.core._device import Device
14from cuda.core._launch_config cimport LaunchConfig
15from cuda.core._launch_config import LaunchConfig
16from cuda.core._stream cimport Stream
17from cuda.core._resource_handles cimport (
18 LibraryHandle,
19 KernelHandle,
20 create_library_handle_from_file,
21 create_library_handle_from_data,
22 create_library_handle_ref,
23 create_kernel_handle,
24 create_kernel_handle_ref,
25 get_last_error,
26 as_cu,
27 as_py,
28 as_intptr,
29)
30from cuda.core._stream import Stream
31from cuda.core._utils.clear_error_support import (
32 assert_type_str_or_bytes_like,
33 raise_code_path_meant_to_be_unreachable,
34)
35from cuda.core._utils.cuda_utils cimport HANDLE_RETURN
36from cuda.core._utils.cuda_utils import driver, get_binding_version
37from cuda.bindings cimport cydriver
39__all__ = ["Kernel", "ObjectCode"]
41# Lazy initialization state and synchronization
42# For Python 3.13t (free-threaded builds), we use a lock to ensure thread-safe initialization.
43# For regular Python builds with GIL, the lock overhead is minimal and the code remains safe.
44cdef object _init_lock = threading.Lock()
45cdef bint _inited = False
46cdef int _py_major_ver = 0
47cdef int _py_minor_ver = 0
48cdef int _driver_ver = 0
49cdef tuple _kernel_ctypes = None
50cdef bint _paraminfo_supported = False
53cdef int _lazy_init() except -1:
54 """
55 Initialize module-level state in a thread-safe manner.
57 This function is thread-safe and suitable for both:
58 - Regular Python builds (with GIL)
59 - Python 3.13t free-threaded builds (without GIL)
61 Uses double-checked locking pattern for performance:
62 - Fast path: check without lock if already initialized
63 - Slow path: acquire lock and initialize if needed
64 """
65 global _inited
66 # Fast path: already initialized (no lock needed for read)
67 if _inited: 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObPbQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!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~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxc1cycUczc2cAcVcBc3cCc4cDc5cEc6cFcWcGc7cHc8cIc9cJc!cKc#cLc$cMc%cNcXcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
68 return 0 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObPbQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!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~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxc1cycUczc2cAcVcBc3cCc4cDc5cEc6cFcWcGc7cHc8cIc9cJc!cKc#cLc$cMc%cNcXcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
70 cdef int drv_ver
71 # Slow path: acquire lock and initialize
72 with _init_lock: 2q :c
73 # Double-check: another thread might have initialized while we waited
74 if _inited: 2q :c
75 return 0
77 global _py_major_ver, _py_minor_ver, _driver_ver, _kernel_ctypes, _paraminfo_supported
78 # binding availability depends on cuda-python version
79 _py_major_ver, _py_minor_ver = get_binding_version() 2q :c
80 _kernel_ctypes = (driver.CUkernel,) 2q :c
81 with nogil: 2q :c
82 HANDLE_RETURN(cydriver.cuDriverGetVersion(&drv_ver)) 2q :c
83 _driver_ver = drv_ver 2q :c
84 _paraminfo_supported = _driver_ver >= 12040 2q :c
86 # Mark as initialized (must be last to ensure all state is set)
87 _inited = True 2q :c
89 return 0 2q :c
92# Auto-initializing accessors (cdef for internal use)
93cdef inline int _get_py_major_ver() except -1:
94 """Get the Python binding major version, initializing if needed."""
95 _lazy_init() 1cb
96 return _py_major_ver 1cb
99cdef inline int _get_py_minor_ver() except -1:
100 """Get the Python binding minor version, initializing if needed."""
101 _lazy_init() 1cb
102 return _py_minor_ver 1cb
105cdef inline int _get_driver_ver() except -1:
106 """Get the CUDA driver version, initializing if needed."""
107 _lazy_init() 1cb
108 return _driver_ver 1cb
111cdef inline tuple _get_kernel_ctypes():
112 """Get the kernel ctypes tuple, initializing if needed."""
113 _lazy_init()
114 return _kernel_ctypes
117cdef inline bint _is_paraminfo_supported() except -1:
118 """Return True if cuKernelGetParamInfo is available (driver >= 12.4)."""
119 _lazy_init() 2d p m e f g h n i j k l Xc
120 return _paraminfo_supported 2d p m e f g h n i j k l Xc
123@functools.cache
124def _is_cukernel_get_library_supported() -> bool:
125 """Return True when cuKernelGetLibrary is available for inverse kernel-to-library lookup.
127 Requires cuda-python bindings >= 12.5 and driver >= 12.5.
128 """
129 return ( 1cb
130 (_get_py_major_ver(), _get_py_minor_ver()) >= (12, 5) 1cb
131 and _get_driver_ver() >= 12050 1cb
132 and hasattr(driver, "cuKernelGetLibrary") 1cb
133 )
136cdef inline LibraryHandle _make_empty_library_handle():
137 """Create an empty LibraryHandle to indicate no library loaded."""
138 return LibraryHandle() # Empty shared_ptr
141cdef class KernelAttributes:
142 """Provides access to kernel attributes."""
144 def __init__(self, *args, **kwargs):
145 raise RuntimeError("KernelAttributes cannot be instantiated directly. Please use Kernel APIs.") 2_e
147 @staticmethod
148 cdef KernelAttributes _init(KernelHandle h_kernel):
149 cdef KernelAttributes self = KernelAttributes.__new__(KernelAttributes) 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
150 self._h_kernel = h_kernel 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
151 self._cache = {} 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
152 _lazy_init() 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
153 return self 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
155 cdef int _get_cached_attribute(self, int device_id, cydriver.CUfunction_attribute attribute) except? -1:
156 """Helper function to get a cached attribute or fetch and cache it if not present."""
157 cdef tuple cache_key = (device_id, <int>attribute) 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
158 cached = self._cache.get(cache_key, cache_key) 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
159 if cached is not cache_key: 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
160 return cached 21cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
161 cdef int result
162 with nogil: 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
163 HANDLE_RETURN(cydriver.cuKernelGetAttribute(&result, attribute, as_cu(self._h_kernel), device_id)) 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
164 self._cache[cache_key] = result 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
165 return result 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
167 cdef inline int _resolve_device_id(self, device_id) except? -1:
168 """Convert Device or int to device_id int."""
169 return Device(device_id).device_id 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
171 def max_threads_per_block(self, device_id: Device | int = None) -> int:
172 """int : The maximum number of threads per block.
173 This attribute is read-only."""
174 return self._get_cached_attribute( 2c Pb6c
175 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK 2c Pb6c
176 )
178 def shared_size_bytes(self, device_id: Device | int = None) -> int:
179 """int : The size in bytes of statically-allocated shared memory required by this function.
180 This attribute is read-only."""
181 return self._get_cached_attribute( 2%c
182 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_SHARED_SIZE_BYTES 2%c
183 )
185 def const_size_bytes(self, device_id: Device | int = None) -> int:
186 """int : The size in bytes of user-allocated constant memory required by this function.
187 This attribute is read-only."""
188 return self._get_cached_attribute( 23c
189 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_CONST_SIZE_BYTES 23c
190 )
192 def local_size_bytes(self, device_id: Device | int = None) -> int:
193 """int : The size in bytes of local memory used by each thread of this function.
194 This attribute is read-only."""
195 return self._get_cached_attribute( 24c
196 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_LOCAL_SIZE_BYTES 24c
197 )
199 def num_regs(self, device_id: Device | int = None) -> int:
200 """int : The number of registers used by each thread of this function.
201 This attribute is read-only."""
202 return self._get_cached_attribute( 21b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b7c
203 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_NUM_REGS 21b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b7c
204 )
206 def ptx_version(self, device_id: Device | int = None) -> int:
207 """int : The PTX virtual architecture version for which the function was compiled.
208 This attribute is read-only."""
209 return self._get_cached_attribute( 29c
210 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_PTX_VERSION 29c
211 )
213 def binary_version(self, device_id: Device | int = None) -> int:
214 """int : The binary architecture version for which the function was compiled.
215 This attribute is read-only."""
216 return self._get_cached_attribute( 21c
217 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_BINARY_VERSION 21c
218 )
220 def cache_mode_ca(self, device_id: Device | int = None) -> bool:
221 """bool : Whether the function has been compiled with user specified option "-Xptxas --dlcm=ca" set.
222 This attribute is read-only."""
223 return bool( 2Uc
224 self._get_cached_attribute( 2Uc
225 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_CACHE_MODE_CA 2Uc
226 )
227 )
229 def max_dynamic_shared_size_bytes(self, device_id: Device | int = None) -> int:
230 """int : The maximum size in bytes of dynamically-allocated shared memory that can be used
231 by this function."""
232 return self._get_cached_attribute( 25c
233 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES 25c
234 )
236 def preferred_shared_memory_carveout(self, device_id: Device | int = None) -> int:
237 """int : The shared memory carveout preference, in percent of the total shared memory."""
238 return self._get_cached_attribute( 28c
239 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT 28c
240 )
242 def cluster_size_must_be_set(self, device_id: Device | int = None) -> bool:
243 """bool : The kernel must launch with a valid cluster size specified.
244 This attribute is read-only."""
245 return bool( 2Vc
246 self._get_cached_attribute( 2Vc
247 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_CLUSTER_SIZE_MUST_BE_SET 2Vc
248 )
249 )
251 def required_cluster_width(self, device_id: Device | int = None) -> int:
252 """int : The required cluster width in blocks."""
253 return self._get_cached_attribute( 2$c
254 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_REQUIRED_CLUSTER_WIDTH 2$c
255 )
257 def required_cluster_height(self, device_id: Device | int = None) -> int:
258 """int : The required cluster height in blocks."""
259 return self._get_cached_attribute( 2#c
260 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_REQUIRED_CLUSTER_HEIGHT 2#c
261 )
263 def required_cluster_depth(self, device_id: Device | int = None) -> int:
264 """int : The required cluster depth in blocks."""
265 return self._get_cached_attribute( 2!c
266 self._resolve_device_id(device_id), cydriver.CU_FUNC_ATTRIBUTE_REQUIRED_CLUSTER_DEPTH 2!c
267 )
269 def non_portable_cluster_size_allowed(self, device_id: Device | int = None) -> bool:
270 """bool : Whether the function can be launched with non-portable cluster size."""
271 return bool( 2Wc
272 self._get_cached_attribute( 2Wc
273 self._resolve_device_id(device_id), 2Wc
274 cydriver.CU_FUNC_ATTRIBUTE_NON_PORTABLE_CLUSTER_SIZE_ALLOWED,
275 )
276 )
278 def cluster_scheduling_policy_preference(self, device_id: Device | int = None) -> int:
279 """int : The block scheduling policy of a function."""
280 return self._get_cached_attribute( 22c
281 self._resolve_device_id(device_id), 22c
282 cydriver.CU_FUNC_ATTRIBUTE_CLUSTER_SCHEDULING_POLICY_PREFERENCE,
283 )
286MaxPotentialBlockSizeOccupancyResult = namedtuple("MaxPotential", ("min_grid_size", "max_block_size"))
289cdef class KernelOccupancy:
290 """This class offers methods to query occupancy metrics that help determine optimal
291 launch parameters such as block size, grid size, and shared memory usage.
292 """
294 def __init__(self, *args, **kwargs):
295 raise RuntimeError("KernelOccupancy cannot be instantiated directly. Please use Kernel APIs.") 2`e
297 @staticmethod
298 cdef KernelOccupancy _init(KernelHandle h_kernel):
299 cdef KernelOccupancy self = KernelOccupancy.__new__(KernelOccupancy) 2o =d?d@d[d]d^d1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
300 self._h_kernel = h_kernel 2o =d?d@d[d]d^d1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
301 return self 2o =d?d@d[d]d^d1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
303 def max_active_blocks_per_multiprocessor(self, block_size: int, dynamic_shared_memory_size: int) -> int:
304 """Occupancy of the kernel.
306 Returns the maximum number of active blocks per multiprocessor for this kernel.
308 Parameters
309 ----------
310 block_size: int
311 Block size parameter used to launch this kernel.
312 dynamic_shared_memory_size: int
313 The amount of dynamic shared memory in bytes needed by block.
314 Use `0` if block does not need shared memory.
316 Returns
317 -------
318 int
319 The maximum number of active blocks per multiprocessor.
321 Note
322 ----
323 The fraction of the product of maximum number of active blocks per multiprocessor
324 and the block size to the maximum number of threads per multiprocessor is known as
325 theoretical multiprocessor utilization (occupancy).
327 """
328 cdef int num_blocks
329 cdef int c_block_size = block_size 2o 1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b
330 cdef size_t c_shmem_size = dynamic_shared_memory_size 2o 1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b
331 cdef cydriver.CUfunction func = <cydriver.CUfunction>as_cu(self._h_kernel) 2o 1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b
332 with nogil: 2o 1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b
333 HANDLE_RETURN(cydriver.cuOccupancyMaxActiveBlocksPerMultiprocessor( 2o 1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b
334 &num_blocks, func, c_block_size, c_shmem_size
335 ))
336 return num_blocks 2o 1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b
338 def max_potential_block_size(
339 self, dynamic_shared_memory_needed: int | driver.CUoccupancyB2DSize, block_size_limit: int
340 ) -> MaxPotentialBlockSizeOccupancyResult:
341 """MaxPotentialBlockSizeOccupancyResult: Suggested launch configuration for reasonable occupancy.
343 Returns the minimum grid size needed to achieve the maximum occupancy and
344 the maximum block size that can achieve the maximum occupancy.
346 Parameters
347 ----------
348 dynamic_shared_memory_needed: Union[int, driver.CUoccupancyB2DSize]
349 The amount of dynamic shared memory in bytes needed by block.
350 Use `0` if block does not need shared memory. Use C-callable
351 represented by :obj:`~driver.CUoccupancyB2DSize` to encode
352 amount of needed dynamic shared memory which varies depending
353 on tne block size.
354 block_size_limit: int
355 Known upper limit on the kernel block size. Use `0` to indicate
356 the maximum block size permitted by the device / kernel instead
358 Returns
359 -------
360 :obj:`~MaxPotentialBlockSizeOccupancyResult`
361 An object with `min_grid_size` amd `max_block_size` attributes encoding
362 the suggested launch configuration.
364 Note
365 ----
366 Please be advised that use of C-callable that requires Python Global
367 Interpreter Lock may lead to deadlocks.
369 """
370 cdef int min_grid_size, max_block_size
371 cdef cydriver.CUfunction func = <cydriver.CUfunction>as_cu(self._h_kernel) 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
372 cdef cydriver.CUoccupancyB2DSize callback
373 cdef size_t c_shmem_size
374 cdef int c_block_size_limit = block_size_limit 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
375 if isinstance(dynamic_shared_memory_needed, int): 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
376 c_shmem_size = dynamic_shared_memory_needed 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
377 with nogil: 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
378 HANDLE_RETURN(cydriver.cuOccupancyMaxPotentialBlockSize( 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
379 &min_grid_size, &max_block_size, func, NULL, c_shmem_size, c_block_size_limit
380 ))
381 elif isinstance(dynamic_shared_memory_needed, driver.CUoccupancyB2DSize): 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
382 # Callback may require GIL, so don't use nogil here
383 callback = <cydriver.CUoccupancyB2DSize><size_t>dynamic_shared_memory_needed.getPtr()
384 HANDLE_RETURN(cydriver.cuOccupancyMaxPotentialBlockSize(
385 &min_grid_size, &max_block_size, func, callback, 0, c_block_size_limit
386 ))
387 else:
388 raise TypeError( 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
389 "dynamic_shared_memory_needed expected to have type int, or CUoccupancyB2DSize, " 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
390 f"got {type(dynamic_shared_memory_needed)}" 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
391 )
392 return MaxPotentialBlockSizeOccupancyResult(min_grid_size=min_grid_size, max_block_size=max_block_size) 2;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
394 def available_dynamic_shared_memory_per_block(self, num_blocks_per_multiprocessor: int, block_size: int) -> int:
395 """Dynamic shared memory available per block for given launch configuration.
397 The amount of dynamic shared memory per block, in bytes, for given kernel launch configuration.
399 Parameters
400 ----------
401 num_blocks_per_multiprocessor: int
402 Number of blocks to be concurrently executing on a multiprocessor.
403 block_size: int
404 Block size parameter used to launch this kernel.
406 Returns
407 -------
408 int
409 Dynamic shared memory available per block for given launch configuration.
410 """
411 cdef size_t dynamic_smem_size
412 cdef int c_num_blocks = num_blocks_per_multiprocessor 2=d?d@d[d]d^d
413 cdef int c_block_size = block_size 2=d?d@d[d]d^d
414 cdef cydriver.CUfunction func = <cydriver.CUfunction>as_cu(self._h_kernel) 2=d?d@d[d]d^d
415 with nogil: 2=d?d@d[d]d^d
416 HANDLE_RETURN(cydriver.cuOccupancyAvailableDynamicSMemPerBlock( 2=d?d@d[d]d^d
417 &dynamic_smem_size, func, c_num_blocks, c_block_size
418 ))
419 return dynamic_smem_size 2=d?d@d[d]d^d
421 def max_potential_cluster_size(self, config: LaunchConfig, stream: Stream | None = None) -> int:
422 """Maximum potential cluster size.
424 The maximum potential cluster size for this kernel and given launch configuration.
426 Parameters
427 ----------
428 config: :obj:`~_launch_config.LaunchConfig`
429 Kernel launch configuration. Cluster dimensions in the configuration are ignored.
430 stream: :obj:`~Stream`, optional
431 The stream on which this kernel is to be launched.
433 Returns
434 -------
435 int
436 The maximum cluster size that can be launched for this kernel and launch configuration.
437 """
438 cdef cydriver.CUlaunchConfig drv_cfg = (<LaunchConfig>config)._to_native_launch_config()
439 cdef Stream s
440 if stream is not None:
441 s = <Stream>stream
442 drv_cfg.hStream = as_cu(s._h_stream)
443 cdef int cluster_size
444 cdef cydriver.CUfunction func = <cydriver.CUfunction>as_cu(self._h_kernel)
445 with nogil:
446 HANDLE_RETURN(cydriver.cuOccupancyMaxPotentialClusterSize(&cluster_size, func, &drv_cfg))
447 return cluster_size
449 def max_active_clusters(self, config: LaunchConfig, stream: Stream | None = None) -> int:
450 """Maximum number of active clusters on the target device.
452 The maximum number of clusters that could concurrently execute on the target device.
454 Parameters
455 ----------
456 config: :obj:`~_launch_config.LaunchConfig`
457 Kernel launch configuration.
458 stream: :obj:`~Stream`, optional
459 The stream on which this kernel is to be launched.
461 Returns
462 -------
463 int
464 The maximum number of clusters that could co-exist on the target device.
465 """
466 cdef cydriver.CUlaunchConfig drv_cfg = (<LaunchConfig>config)._to_native_launch_config()
467 cdef Stream s
468 if stream is not None:
469 s = <Stream>stream
470 drv_cfg.hStream = as_cu(s._h_stream)
471 cdef int num_clusters
472 cdef cydriver.CUfunction func = <cydriver.CUfunction>as_cu(self._h_kernel)
473 with nogil:
474 HANDLE_RETURN(cydriver.cuOccupancyMaxActiveClusters(&num_clusters, func, &drv_cfg))
475 return num_clusters
478ParamInfo = namedtuple("ParamInfo", ["offset", "size"])
481cdef class Kernel:
482 """Represent a compiled kernel that had been loaded onto the device.
484 Kernel instances can execution when passed directly into the
485 :func:`~launch` function.
487 Directly creating a :obj:`~_module.Kernel` is not supported, and they
488 should instead be created through a :obj:`~_module.ObjectCode` object.
490 """
492 def __init__(self, *args, **kwargs):
493 raise RuntimeError("Kernel objects cannot be instantiated directly. Please use ObjectCode APIs.") 2{e
495 @staticmethod
496 cdef Kernel _from_obj(KernelHandle h_kernel):
497 cdef Kernel ker = Kernel.__new__(Kernel) 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMb_dNbc ObPbQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X
498 ker._h_kernel = h_kernel 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMb_dNbc ObPbQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X
499 ker._attributes = None 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMb_dNbc ObPbQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X
500 ker._occupancy = None 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMb_dNbc ObPbQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X
501 return ker 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMb_dNbc ObPbQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X
503 @property
504 def attributes(self) -> KernelAttributes:
505 """Get the read-only attributes of this kernel."""
506 if self._attributes is None: 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
507 self._attributes = KernelAttributes._init(self._h_kernel) 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
508 return self._attributes 2c Pb1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b1cUc2cVc3c4c5c6cWc7c8c9c!c#c$c%c
510 cdef tuple _get_arguments_info(self, bint param_info=False):
511 if not _is_paraminfo_supported(): 2d p m e f g h n i j k l Xc
512 driver_ver = _get_driver_ver()
513 raise NotImplementedError(
514 "Driver version 12.4 or newer is required for this function. "
515 f"Using driver version {driver_ver // 1000}.{(driver_ver % 1000) // 10}"
516 )
517 cdef size_t arg_pos = 0 2d p m e f g h n i j k l Xc
518 cdef list param_info_data = [] 2d p m e f g h n i j k l Xc
519 cdef cydriver.CUkernel cu_kernel = as_cu(self._h_kernel) 2d p m e f g h n i j k l Xc
520 cdef size_t param_offset, param_size
521 cdef cydriver.CUresult err
522 while True: 2d p m e f g h n i j k l Xc
523 with nogil: 2d p m e f g h n i j k l Xc
524 err = cydriver.cuKernelGetParamInfo(cu_kernel, arg_pos, ¶m_offset, ¶m_size) 2d p m e f g h n i j k l Xc
525 if err != cydriver.CUDA_SUCCESS: 2d p m e f g h n i j k l Xc
526 break 2d p m e f g h n i j k l Xc
527 if param_info: 2d e f g h i j k l Xc
528 param_info_data.append(ParamInfo(offset=param_offset, size=param_size)) 2e f g h i j k l Xc
529 arg_pos = arg_pos + 1 2d e f g h i j k l Xc
530 if err != cydriver.CUDA_ERROR_INVALID_VALUE: 2d p m e f g h n i j k l Xc
531 HANDLE_RETURN(err) 1p
532 return arg_pos, param_info_data 2d m e f g h n i j k l Xc
534 @property
535 def num_arguments(self) -> int:
536 """int : The number of arguments of this function"""
537 num_args, _ = self._get_arguments_info() 2d p m e f g h n i j k l Xc
538 return num_args 2d m e f g h n i j k l Xc
540 @property
541 def arguments_info(self) -> list[ParamInfo]:
542 """list[ParamInfo]: (offset, size) for each argument of this function"""
543 _, param_info = self._get_arguments_info(param_info=True) 2m e f g h n i j k l Xc
544 return param_info 2m e f g h n i j k l Xc
546 @property
547 def occupancy(self) -> KernelOccupancy:
548 """Get the occupancy information for launching this kernel."""
549 if self._occupancy is None: 2o =d?d@d[d]d^d1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
550 self._occupancy = KernelOccupancy._init(self._h_kernel) 2o =d?d@d[d]d^d1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
551 return self._occupancy 2o =d?d@d[d]d^d1b3b5b7b9b#b%b(b*b,b.b:b=b@b]b_b{b}b;c=c?c@c[c]c^c_c`c{c|c}c~cadbdcdddedfdgdhd
553 @property
554 def handle(self):
555 """Return the underlying kernel handle object.
557 .. caution::
559 This handle is a Python object. To get the memory address of the underlying C
560 handle, call ``int(Kernel.handle)``.
561 """
562 return as_py(self._h_kernel) 2|e_dc Pbd r b
564 @property
565 def _handle(self):
566 return self.handle
568 @staticmethod
569 def from_handle(handle, mod: ObjectCode = None) -> Kernel:
570 """Creates a new :obj:`Kernel` object from a foreign kernel handle.
572 Uses a CUkernel pointer address to create a new :obj:`Kernel` object.
574 Parameters
575 ----------
576 handle : int
577 Kernel handle representing the address of a foreign
578 kernel object (CUkernel).
579 mod : :obj:`ObjectCode`, optional
580 The ObjectCode object associated with this kernel. If not provided,
581 a placeholder ObjectCode will be created. Note that without a proper
582 ObjectCode, certain operations may be limited.
583 """
585 # Validate that handle is an integer
586 if not isinstance(handle, int): 2_dc .e/e:e;e=e?e@e[e]e^ePbb
587 raise TypeError(f"handle must be an integer, got {type(handle).__name__}") 2.e/e:e;e=e?e@e[e]e^e
589 # Convert the integer handle to CUkernel
590 cdef cydriver.CUkernel cu_kernel = <cydriver.CUkernel><void*><size_t>handle 2_dc Pbb
591 cdef KernelHandle h_kernel
592 cdef cydriver.CUlibrary cu_library
593 cdef cydriver.CUresult err
595 # If no module provided, create a placeholder and try to get the library
596 if mod is None: 2_dc Pbb
597 mod = ObjectCode._init(b"", "cubin") 1cb
598 if _is_cukernel_get_library_supported(): 1cb
599 # Try to get the owning library via cuKernelGetLibrary
600 with nogil: 1cb
601 err = cydriver.cuKernelGetLibrary(&cu_library, cu_kernel) 1cb
602 if err == cydriver.CUDA_SUCCESS: 1cb
603 mod._h_library = create_library_handle_ref(cu_library) 1cb
605 # Create kernel handle with library dependency
606 h_kernel = create_kernel_handle_ref(cu_kernel, mod._h_library) 2_dc Pbb
607 if not h_kernel: 2_dc Pbb
608 HANDLE_RETURN(get_last_error())
610 return Kernel._from_obj(h_kernel) 2_dc Pbb
612 def __eq__(self, other) -> bool:
613 if not isinstance(other, Kernel): 1rbwxyzAtBCuv
614 return NotImplemented 1rwxyzAtB
615 return as_intptr(self._h_kernel) == as_intptr((<Kernel>other)._h_kernel) 1rbCuv
617 def __hash__(self) -> int:
618 return hash(as_intptr(self._h_kernel)) 1bDEFGHIsJKMNuv
620 def __repr__(self) -> str:
621 return f"<Kernel handle={as_intptr(self._h_kernel):#x}>" 1L
624CodeTypeT = bytes | bytearray | str
626cdef tuple _supported_code_type = ("cubin", "ptx", "ltoir", "fatbin", "object", "library")
628cdef class ObjectCode:
629 """Represent a compiled program to be loaded onto the device.
631 This object provides a unified interface for different types of
632 compiled programs that will be loaded onto the device.
634 Note
635 ----
636 This class has no default constructor. If you already have a cubin that you would
637 like to load, use the :meth:`from_cubin` alternative constructor. Constructing directly
638 from all other possible code types should be avoided in favor of compilation through
639 :class:`~cuda.core.Program`
640 """
642 def __init__(self, *args, **kwargs):
643 raise RuntimeError( 2}e
644 "ObjectCode objects cannot be instantiated directly. "
645 "Please use ObjectCode APIs (from_cubin, from_ptx) or Program APIs (compile)."
646 )
648 @classmethod
649 def _init(cls, module, code_type, *, name: str = "", symbol_mapping: dict | None = None):
650 assert code_type in _supported_code_type, f"{code_type=} is not supported" 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
651 cdef ObjectCode self = ObjectCode.__new__(ObjectCode) 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
653 # _h_library is assigned during _lazy_load_module
654 self._h_library = LibraryHandle() # Empty handle 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
655 _lazy_init() 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
657 self._code_type = code_type 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
658 self._module = module 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
659 self._sym_map = {} if symbol_mapping is None else symbol_mapping 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
660 self._name = name if name else "" 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
662 return self 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbmd`dnd{dod|dpd}dqd~drdaesdbetdceuddevdeewdfexdgeydhezdieAdjeBdkeCdleDdmeEdneFdoeGdpeHdqeIdreJdseKdteLdueveMdwexejdyeNdzeAeMbNbc ObQbd idRbp m e f g h n i j k l SbU TbV UbkdBePcCeld-dOd.dVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw Ydx Zdy 0dz 1dA 2dt B 3dL .c/cC TcM ZcN 0cu Rcv ScW DeX Ee4d5dFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!e#e$e%e'e(e)e*e+e_ 6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRd:cSdTdUdVdWdXd
664 @staticmethod
665 def _reduce_helper(module, code_type, name, symbol_mapping):
666 return ObjectCode._init(module, code_type, name=name if name else "", symbol_mapping=symbol_mapping) 2id
668 def __reduce__(self):
669 return ObjectCode._reduce_helper, (self._module, self._code_type, self._name, self._sym_map) 2id
671 @staticmethod
672 def from_cubin(module: bytes | str, *, name: str = "", symbol_mapping: dict | None = None) -> ObjectCode:
673 """Create an :class:`ObjectCode` instance from an existing cubin.
675 Parameters
676 ----------
677 module : Union[bytes, str]
678 Either a bytes object containing the in-memory cubin to load, or
679 a file path string pointing to the on-disk cubin to load.
680 name : Optional[str]
681 A human-readable identifier representing this code object.
682 symbol_mapping : Optional[dict]
683 A dictionary specifying how the unmangled symbol names (as keys)
684 should be mapped to the mangled names before trying to retrieve
685 them (default to no mappings).
686 """
687 return ObjectCode._init(module, "cubin", name=name, symbol_mapping=symbol_mapping) 1UV
689 @staticmethod
690 def from_ptx(module: bytes | str, *, name: str = "", symbol_mapping: dict | None = None) -> ObjectCode:
691 """Create an :class:`ObjectCode` instance from an existing PTX.
693 Parameters
694 ----------
695 module : Union[bytes, str]
696 Either a bytes object containing the in-memory ptx code to load, or
697 a file path string pointing to the on-disk ptx file to load.
698 name : Optional[str]
699 A human-readable identifier representing this code object.
700 symbol_mapping : Optional[dict]
701 A dictionary specifying how the unmangled symbol names (as keys)
702 should be mapped to the mangled names before trying to retrieve
703 them (default to no mappings).
704 """
705 return ObjectCode._init(module, "ptx", name=name, symbol_mapping=symbol_mapping) 2jdldOd
707 @staticmethod
708 def from_ltoir(module: bytes | str, *, name: str = "", symbol_mapping: dict | None = None) -> ObjectCode:
709 """Create an :class:`ObjectCode` instance from an existing LTOIR.
711 Parameters
712 ----------
713 module : Union[bytes, str]
714 Either a bytes object containing the in-memory ltoir code to load, or
715 a file path string pointing to the on-disk ltoir file to load.
716 name : Optional[str]
717 A human-readable identifier representing this code object.
718 symbol_mapping : Optional[dict]
719 A dictionary specifying how the unmangled symbol names (as keys)
720 should be mapped to the mangled names before trying to retrieve
721 them (default to no mappings).
722 """
723 return ObjectCode._init(module, "ltoir", name=name, symbol_mapping=symbol_mapping) 2kdPc
725 @staticmethod
726 def from_fatbin(module: bytes | str, *, name: str = "", symbol_mapping: dict | None = None) -> ObjectCode:
727 """Create an :class:`ObjectCode` instance from an existing fatbin.
729 Parameters
730 ----------
731 module : Union[bytes, str]
732 Either a bytes object containing the in-memory fatbin to load, or
733 a file path string pointing to the on-disk fatbin to load.
734 name : Optional[str]
735 A human-readable identifier representing this code object.
736 symbol_mapping : Optional[dict]
737 A dictionary specifying how the unmangled symbol names (as keys)
738 should be mapped to the mangled names before trying to retrieve
739 them (default to no mappings).
740 """
741 return ObjectCode._init(module, "fatbin", name=name, symbol_mapping=symbol_mapping)
743 @staticmethod
744 def from_object(module: bytes | str, *, name: str = "", symbol_mapping: dict | None = None) -> ObjectCode:
745 """Create an :class:`ObjectCode` instance from an existing object code.
747 Parameters
748 ----------
749 module : Union[bytes, str]
750 Either a bytes object containing the in-memory object code to load, or
751 a file path string pointing to the on-disk object code to load.
752 name : Optional[str]
753 A human-readable identifier representing this code object.
754 symbol_mapping : Optional[dict]
755 A dictionary specifying how the unmangled symbol names (as keys)
756 should be mapped to the mangled names before trying to retrieve
757 them (default to no mappings).
758 """
759 return ObjectCode._init(module, "object", name=name, symbol_mapping=symbol_mapping)
761 @staticmethod
762 def from_library(module: bytes | str, *, name: str = "", symbol_mapping: dict | None = None) -> ObjectCode:
763 """Create an :class:`ObjectCode` instance from an existing library.
765 Parameters
766 ----------
767 module : Union[bytes, str]
768 Either a bytes object containing the in-memory library to load, or
769 a file path string pointing to the on-disk library to load.
770 name : Optional[str]
771 A human-readable identifier representing this code object.
772 symbol_mapping : Optional[dict]
773 A dictionary specifying how the unmangled symbol names (as keys)
774 should be mapped to the mangled names before trying to retrieve
775 them (default to no mappings).
776 """
777 return ObjectCode._init(module, "library", name=name, symbol_mapping=symbol_mapping)
779 # TODO: do we want to unload in a finalizer? Probably not..
781 cdef int _lazy_load_module(self) except -1:
782 if self._h_library: 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l ,eSbU TbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw x y z A t B L .c/cC TcM ZcN 0cu Rcv ScW X _
783 return 0 2Y Z 0 1 2 3 4 5 6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ^ ,eQcYcs Zc0cRcSc_
784 module = self._module 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw x y z A t B L .c/cC TcM ZcN 0cu Rcv ScW X _
785 assert_type_str_or_bytes_like(module) 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw x y z A t B L .c/cC TcM ZcN 0cu Rcv ScW X _
786 cdef bytes path_bytes
787 if isinstance(module, str): 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw x y z A t B L .c/cC TcM ZcN 0cu Rcv ScW X _
788 path_bytes = module.encode() 1U
789 self._h_library = create_library_handle_from_file(<const char*>path_bytes) 1U
790 if not self._h_library: 1U
791 HANDLE_RETURN(get_last_error())
792 return 0 1U
793 if isinstance(module, (bytes, bytearray)): 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbTbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw x y z A t B L .c/cC TcM ZcN 0cu Rcv ScW X _
794 self._h_library = create_library_handle_from_data(<const void*><char*>module) 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbTbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw x y z A t B L .c/cC TcM ZcN 0cu Rcv ScW X _
795 if not self._h_library: 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbTbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw x y z A t B L .c/cC TcM ZcN 0cu Rcv ScW X _
796 HANDLE_RETURN(get_last_error())
797 return 0 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbTbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr Qcb D YcE 'cF (cG )cH *cI +cs J ,cK -cw x y z A t B L .c/cC TcM ZcN 0cu Rcv ScW X _
798 raise_code_path_meant_to_be_unreachable()
799 return -1
801 def get_kernel(self, name) -> Kernel:
802 """Return the :obj:`~_module.Kernel` of a specified name from this object code.
804 Parameters
805 ----------
806 name : str | bytes
807 Name of the kernel to retrieve.
809 Returns
810 -------
811 :obj:`~_module.Kernel`
812 Newly created kernel object.
814 """
815 self._lazy_load_module() 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X _
816 supported_code_types = ("cubin", "ptx", "fatbin") 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X _
817 if self._code_type not in supported_code_types: 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbPcVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X _
818 raise RuntimeError(f'Unsupported code type "{self._code_type}" ({supported_code_types=})') 2Pc
819 try: 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X _
820 name = self._sym_map[name] 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X _
821 except KeyError: 1OPQRSoTdrbDEFGHIsJKwxyzAtBLCMNuvWX_
822 if isinstance(name, str): 1OPQRSoTdrbDEFGHIsJKwxyzAtBLCMNuvWX_
823 name = name.encode() 1OPQRSoTdrbDEFGHIsJKwxyzAtBLCMNuvWX_
825 cdef KernelHandle h_kernel = create_kernel_handle(self._h_library, <const char*>name) 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X _
826 if not h_kernel: 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X _
827 HANDLE_RETURN(get_last_error()) 1_
828 return Kernel._from_obj(h_kernel) 2q ` { | } ~ abY Z 0 1 2 3 4 5 bbcbdb6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ebfb^ O P Q R S o T gbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObQbd Rbp m e f g h n i j k l SbU TbV UbVbWbXbYbZb0b2b4b6b8b!b$b'b)b+b-b/b;b?b[b^b`b|b~bacbcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcr b D E F G H I s J K w x y z A t B L C M N u v W X
830 @property
831 def code(self) -> CodeTypeT:
832 """Return the underlying code object."""
833 return self._module 2mdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMd-ejdNdidU V kdPcld-dOd.d4d5d6d7d8d9d!d#d$d%d'd(d)d*d+d,dPdQdRdSdTdUdVdWdXd
835 @property
836 def name(self) -> str:
837 """Return a human-readable name of this code object."""
838 return self._name 2mdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMd-ejdNd4d5d6d7d8d9d!d#d$d%d'd(d)d*d+d,d/d:d;dPdQdRdSdTdUdVdWdXd
840 @property
841 def code_type(self) -> str:
842 """Return the type of the underlying code object."""
843 return self._code_type 2mdndodpdqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMd-ejdNdidkdPcldPdQdRdSdTdUdVdWdXd
845 @property
846 def symbol_mapping(self) -> dict:
847 """Return a copy of the symbol mapping dictionary."""
848 return dict(self._sym_map) 2idU V kdPcldOd
850 @property
851 def handle(self):
852 """Return the underlying handle object.
854 .. caution::
856 This handle is a Python object. To get the memory address of the underlying C
857 handle, call ``int(ObjectCode.handle)``.
858 """
859 self._lazy_load_module() 2,eQc
860 return as_py(self._h_library) 2,eQc
862 def __eq__(self, other) -> bool:
863 if not isinstance(other, ObjectCode): 2QcYdZd0d1d2dt 3dTcRcSc
864 return NotImplemented 2QcYdZd0d1d2dt 3d
865 # Trigger lazy load for both objects to compare handles
866 self._lazy_load_module() 2QcTcRcSc
867 (<ObjectCode>other)._lazy_load_module() 2QcTcRcSc
868 return as_intptr(self._h_library) == as_intptr((<ObjectCode>other)._h_library) 2QcTcRcSc
870 def __hash__(self) -> int:
871 # Trigger lazy load to get the handle
872 self._lazy_load_module() 2Yc'c(c)c*c+cs ,c-cZc0cRcSc
873 return hash(as_intptr(self._h_library)) 2Yc'c(c)c*c+cs ,c-cZc0cRcSc
875 def __repr__(self) -> str:
876 # Trigger lazy load to get the handle
877 self._lazy_load_module() 2.c/c_
878 return f"<ObjectCode handle={as_intptr(self._h_library):#x} code_type='{self._code_type}'>" 2.c/c_