Coverage for cuda/core/graph/_graph_builder.pyx: 77.61%
518 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-16 01:23 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-16 01:23 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from dataclasses import dataclass
6from typing import TYPE_CHECKING
8from libc.stdint cimport intptr_t
10from cuda.bindings cimport cydriver
12from cuda.core.graph._graph_definition cimport (
13 GraphCondition,
14 GraphDefinition,
15 GD_check_valid,
16)
17from cuda.core.graph._graph_node cimport GraphNode, GN_check_valid
18from cuda.core.graph._host_callback cimport _resolve_host_callback
19from cuda.core.graph._subclasses cimport (
20 ChildGraphNode,
21 EventRecordNode,
22 EventWaitNode,
23 ExecutableChildGraphNode,
24 ExecutableEventRecordNode,
25 ExecutableEventWaitNode,
26 ExecutableGraphNode,
27 ExecutableHostCallbackNode,
28 ExecutableKernelNode,
29 ExecutableMemcpyNode,
30 ExecutableMemsetNode,
31 HostCallbackNode,
32 KernelNode,
33 MemcpyNode,
34 MemsetNode,
35 create_executable_node_view,
36)
37from cuda.core._rt cimport attach_rollback_failure, report_cuda_error
38from cuda.core._rt cimport (
39 GraphExecHandle,
40 GraphHandle,
41 OpaqueHandle,
42 PreparedAttachment,
43 as_cu, as_py,
44 create_child_graph_handle, create_graph_exec_handle, create_graph_handle,
45 get_last_error,
46 graph_clone_attachments,
47 graph_commit_attachment,
48 graph_exec_update,
49 graph_prepare_attachment,
50 invalidate_child_graph_state,
51 invalidate_root_graph_state,
52 retry_deferred_cleanup,
53)
54from cuda.core._stream cimport Stream, Stream_accept
55from cuda.core._utils.cuda_utils cimport HANDLE_RETURN
56from cuda.core._utils.version cimport cy_driver_version
58from cuda.core._utils.cuda_utils import (
59 CUDAError,
60 driver,
61 handle_return,
62)
64if TYPE_CHECKING:
65 from typing import overload
67 from cuda.core.graph._graph_definition import GraphDefinition
68else:
69 # Cython applies a method decorator by rebinding the type's dict entry, so
70 # typing.overload would replace the compiled ``__getitem__`` slot wrapper
71 # with its placeholder. The overloads only serve the stub; at run time the
72 # decorator must leave the method alone.
73 def overload(f):
74 return f
76# Each ``@overload`` stub of ``Graph.__getitem__`` still compiles to a static
77# wrapper function that nothing references, because only the final definition
78# is bound. gcc and clang report those under -Wunused-function, so this file
79# turns that warning off for its own translation unit. The guard keeps the
80# pragma away from MSVC, whose equivalent warning is off at the default level.
81cdef extern from *:
82 """
83 #if defined(__GNUC__)
84 #pragma GCC diagnostic ignored "-Wunused-function"
85 #endif
86 """
88__all__ = ['Graph', 'GraphBuilder', 'GraphCompleteOptions', 'GraphDebugPrintOptions']
91@dataclass
92class GraphDebugPrintOptions:
93 """Options for debug_dot_print().
95 Attributes
96 ----------
97 verbose : bool
98 Output all debug data as if every debug flag is enabled (Default to False)
99 runtime_types : bool
100 Use CUDA Runtime structures for output (Default to False)
101 kernel_node_params : bool
102 Adds kernel parameter values to output (Default to False)
103 memcpy_node_params : bool
104 Adds memcpy parameter values to output (Default to False)
105 memset_node_params : bool
106 Adds memset parameter values to output (Default to False)
107 host_node_params : bool
108 Adds host parameter values to output (Default to False)
109 event_node_params : bool
110 Adds event parameter values to output (Default to False)
111 ext_semas_signal_node_params : bool
112 Adds external semaphore signal parameter values to output (Default to False)
113 ext_semas_wait_node_params : bool
114 Adds external semaphore wait parameter values to output (Default to False)
115 kernel_node_attributes : bool
116 Adds kernel node attributes to output (Default to False)
117 handles : bool
118 Adds node handles and every kernel function handle to output (Default to False)
119 mem_alloc_node_params : bool
120 Adds memory alloc parameter values to output (Default to False)
121 mem_free_node_params : bool
122 Adds memory free parameter values to output (Default to False)
123 batch_mem_op_node_params : bool
124 Adds batch mem op parameter values to output (Default to False)
125 extra_topo_info : bool
126 Adds edge numbering information (Default to False)
127 conditional_node_params : bool
128 Adds conditional node parameter values to output (Default to False)
130 """
132 verbose: bool = False
133 runtime_types: bool = False
134 kernel_node_params: bool = False
135 memcpy_node_params: bool = False
136 memset_node_params: bool = False
137 host_node_params: bool = False
138 event_node_params: bool = False
139 ext_semas_signal_node_params: bool = False
140 ext_semas_wait_node_params: bool = False
141 kernel_node_attributes: bool = False
142 handles: bool = False
143 mem_alloc_node_params: bool = False
144 mem_free_node_params: bool = False
145 batch_mem_op_node_params: bool = False
146 extra_topo_info: bool = False
147 conditional_node_params: bool = False
149 def _to_flags(self) -> int:
150 """Convert options to CUDA driver API flags (internal use)."""
151 flags = 0 2]ca
152 if self.verbose: 2]ca
153 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_VERBOSE 2]ca
154 if self.runtime_types: 2]ca
155 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_RUNTIME_TYPES 1a
156 if self.kernel_node_params: 2]ca
157 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_KERNEL_NODE_PARAMS 1a
158 if self.memcpy_node_params: 2]ca
159 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEMCPY_NODE_PARAMS 1a
160 if self.memset_node_params: 2]ca
161 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEMSET_NODE_PARAMS 1a
162 if self.host_node_params: 2]ca
163 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_HOST_NODE_PARAMS 1a
164 if self.event_node_params: 2]ca
165 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EVENT_NODE_PARAMS 1a
166 if self.ext_semas_signal_node_params: 2]ca
167 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXT_SEMAS_SIGNAL_NODE_PARAMS 1a
168 if self.ext_semas_wait_node_params: 2]ca
169 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXT_SEMAS_WAIT_NODE_PARAMS 1a
170 if self.kernel_node_attributes: 2]ca
171 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_KERNEL_NODE_ATTRIBUTES 1a
172 if self.handles: 2]ca
173 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_HANDLES 2]ca
174 if self.mem_alloc_node_params: 2]ca
175 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEM_ALLOC_NODE_PARAMS 1a
176 if self.mem_free_node_params: 2]ca
177 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEM_FREE_NODE_PARAMS 1a
178 if self.batch_mem_op_node_params: 2]ca
179 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_BATCH_MEM_OP_NODE_PARAMS 1a
180 if self.extra_topo_info: 2]ca
181 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXTRA_TOPO_INFO 1a
182 if self.conditional_node_params: 2]ca
183 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_CONDITIONAL_NODE_PARAMS 1a
184 return flags 2]ca
187@dataclass
188class GraphCompleteOptions:
189 """Options for graph instantiation.
191 Attributes
192 ----------
193 auto_free_on_launch : bool, optional
194 Automatically free memory allocated in a graph before relaunching. (Default to False)
195 upload_stream : Stream, optional
196 Stream to use to automatically upload the graph after completion. (Default to None)
197 device_launch : bool, optional
198 Configure the graph to be launchable from the device. This flag can only
199 be used on platforms which support unified addressing. This flag cannot be
200 used in conjunction with auto_free_on_launch. (Default to False)
201 use_node_priority : bool, optional
202 Run the graph using the per-node priority attributes rather than the
203 priority of the stream it is launched into. (Default to False)
205 """
207 auto_free_on_launch: bool = False
208 upload_stream: Stream | None = None
209 device_launch: bool = False
210 use_node_priority: bool = False
213def _instantiate_graph(source, options: GraphCompleteOptions | None = None) -> Graph:
214 cdef GraphHandle h_graph
215 cdef GraphExecHandle h_exec
216 cdef cydriver.CUresult status
218 if isinstance(source, GraphBuilder): 2N kbF J K L M ~ H . x z 1 y `cG / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
219 GB_check_open(<GraphBuilder>source) 2N F J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % w Z ' ; @ cb( = ?
220 h_graph = (<GraphBuilder>source)._h_graph 2N F J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % w Z ' ; @ cb( = ?
221 elif isinstance(source, GraphDefinition): 2kb`c5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc/b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWb2b3b
222 GD_check_valid(<GraphDefinition>source) 2kb`c5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc/b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWb2b3b
223 h_graph = (<GraphDefinition>source)._h_graph 2kb`c5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc/b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWb2b3b
224 else:
225 raise TypeError(
226 f"expected GraphBuilder or GraphDefinition, got {type(source).__name__}")
228 cdef cydriver.CUDA_GRAPH_INSTANTIATE_PARAMS params = cydriver.CUDA_GRAPH_INSTANTIATE_PARAMS( 2N kbF J K L M ~ H . x z 1 y `cG / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
229 flags=0,
230 hUploadStream=<cydriver.CUstream>NULL, 2N kbF J K L M ~ H . x z 1 y `cG / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
231 hErrNode_out=<cydriver.CUgraphNode>NULL, 2N kbF J K L M ~ H . x z 1 y `cG / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
232 result_out=cydriver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_SUCCESS, 2N kbF J K L M ~ H . x z 1 y `cG / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
233 )
234 if options: 2N kbF J K L M ~ H . x z 1 y `cG / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
235 flags = 0 2`cGbHbYbIbJbZbKbLbMb0bNbOb1bgchcY T U cb(
236 if options.auto_free_on_launch: 2`cGbHbYbIbJbZbKbLbMb0bNbOb1bgchcY T U cb(
237 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_AUTO_FREE_ON_LAUNCH 2GbIbLbNbgchcY T U cb(
238 if options.upload_stream is not None: 2`cGbHbYbIbJbZbKbLbMb0bNbOb1bgchcY T U cb(
239 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_UPLOAD 2`cYbZb0b1b(
240 params.hUploadStream = as_cu(Stream_accept(options.upload_stream)._h_stream) 2`cYbZb0b1b(
241 if options.device_launch: 2GbHbYbIbJbZbKbLbMb0bNbOb1bgchcY T U cb(
242 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_DEVICE_LAUNCH 2Kbcb(
243 if options.use_node_priority: 2GbHbYbIbJbZbKbLbMb0bNbOb1bgchcY T U cb(
244 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_USE_NODE_PRIORITY 2HbJbMbObgchc(
245 params.flags = flags 2GbHbYbIbJbZbKbLbMb0bNbOb1bgchcY T U cb(
247 # The exec is adopted only when result_out reports success, so the
248 # diagnostics below run before the handle is checked.
249 h_exec = create_graph_exec_handle(h_graph, ¶ms) 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
250 status = get_last_error() 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
251 if params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_ERROR: 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ cb( = ?
252 # HANDLE_RETURN raises CUDAError with the CUresult name and message (e.g. CUDA_ERROR_INVALID_VALUE)
253 # when status is not CUDA_SUCCESS.
254 HANDLE_RETURN(status) 2cb
255 raise RuntimeError(
256 "CUDA graph instantiation failed, but cuGraphInstantiateWithParams "
257 "returned CUDA_SUCCESS; no driver error details are available."
258 )
259 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_INVALID_STRUCTURE: 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
260 raise RuntimeError("Instantiation failed due to invalid structure, such as cycles.")
261 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_NODE_OPERATION_NOT_SUPPORTED: 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
262 raise RuntimeError(
263 "Instantiation for device launch failed because the graph contained an unsupported operation."
264 )
265 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_MULTIPLE_CTXS_NOT_SUPPORTED: 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
266 raise RuntimeError("Instantiation for device launch failed due to the nodes belonging to different contexts.")
267 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_CONDITIONAL_HANDLE_UNUSED: 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
268 raise RuntimeError("One or more conditional handles are not associated with conditional builders.")
269 elif params.result_out != driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_SUCCESS: 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
270 raise RuntimeError(f"Graph instantiation failed with unexpected error code: {params.result_out}")
272 if as_cu(h_exec) == NULL: 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
273 HANDLE_RETURN(status)
274 return Graph._init(h_exec) 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
277# Distinguishes the three kinds of GraphBuilder, which differ in how they
278# begin/end stream capture and whether they own the resulting CUgraph.
279# Each kind progresses through _CaptureState as follows:
280#
281# PRIMARY: NOT_STARTED -> CAPTURING -> ENDED | INVALIDATED
282# FORKED: CAPTURING (never transitions; joined and closed)
283# CONDITIONAL_BODY: NOT_STARTED -> CAPTURING -> ENDED | INVALIDATED
284#
285cdef enum _BuilderKind:
286 # PRIMARY: The top-level builder created by Device or Stream. Owns the
287 # captured CUgraph via an owning GraphHandle. Progresses through all three
288 # capture states; responsible for ending capture if destroyed early. When
289 # the capture ends invalidated, the driver discards the graph and the
290 # handle is dropped without destroying it (see GB_end_capture).
291 PRIMARY = 0
292 # FORKED: Created by split(). Captures on a private stream forked from the
293 # primary. Starts in CAPTURING state and never transitions; the user joins
294 # it back to the primary via join(), which closes the builder. Must NOT
295 # call cuStreamEndCapture (the driver requires all forked streams to be
296 # joined first).
297 FORKED = 1
298 # CONDITIONAL_BODY: Created by if_then/if_else/switch/while_loop. Captures
299 # into a non-owned body graph via cuStreamBeginCaptureToGraph. The body
300 # graph's lifetime is tied to a parent graph. Progresses through all three
301 # capture states like PRIMARY.
302 CONDITIONAL_BODY = 2
305# Tracks the capture lifecycle of a GraphBuilder.
306cdef enum _CaptureState:
307 CAPTURE_NOT_STARTED = 0
308 CAPTURING = 1
309 CAPTURE_ENDED = 2 # Finished, valid handle
310 CLOSED = 3 # No valid handle
311 CAPTURE_INVALIDATED = 4 # Ended in error; the driver discarded the graph
314cdef class GraphBuilder:
315 """A graph under construction by stream capture.
317 A graph groups a set of CUDA kernels and other CUDA operations together and executes
318 them with a specified dependency tree. It speeds up the workflow by combining the
319 driver activities associated with CUDA kernel launches and CUDA API calls.
321 Directly creating a :obj:`~graph.GraphBuilder` is not supported due
322 to ambiguity. New graph builders should instead be created through a
323 :obj:`~_device.Device`, or a :obj:`~_stream.stream` object.
325 .. note::
327 Operations recorded during capture reference your memory but do not
328 take ownership of it. As with ordinary stream work, you must keep the
329 operands alive for as long as the completed graph may execute -- for
330 example, the :obj:`~_memory.Buffer` objects passed to :func:`~launch`
331 or :meth:`~_memory.Buffer.copy_to`. Host callbacks added with
332 :meth:`callback` are the exception: the callable (and any copied
333 ``user_data``) are retained for the graph's lifetime. This differs from
334 building a graph explicitly with :class:`~graph.GraphDefinition`, which
335 retains the operands it is given.
337 """
339 def __init__(self):
340 raise NotImplementedError( 2|c
341 "directly creating a GraphBuilder object can be ambiguous. Please either "
342 "call Device.create_graph_builder() or stream.create_graph_builder()"
343 )
345 def __dealloc__(self):
346 cdef cydriver.CUresult err = GB_end_capture(self) 2)c-cN zbkbXb[cmblbF ibfbgb_cPb|cnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I }c` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
347 if err != cydriver.CUDA_SUCCESS: 2)c-cN zbkbXb[cmblbF ibfbgb_cPb|cnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I }c` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
348 # Nothing can be raised from __dealloc__: report instead.
349 report_cuda_error( 2Xb
350 b"cuStreamEndCapture", err,
351 b"failed while releasing a GraphBuilder that was still building")
353 @staticmethod
354 def _init(Stream stream):
355 cdef GraphBuilder self = GraphBuilder.__new__(GraphBuilder) 2)c-cN zbkbXb[cmblbF ibfbgb_cPbnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
356 # _h_graph set by begin_building
357 self._h_stream = stream._h_stream 2)c-cN zbkbXb[cmblbF ibfbgb_cPbnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
358 self._kind = PRIMARY 2)c-cN zbkbXb[cmblbF ibfbgb_cPbnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
359 self._state = CAPTURE_NOT_STARTED 2)c-cN zbkbXb[cmblbF ibfbgb_cPbnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
360 self._stream = stream 2)c-cN zbkbXb[cmblbF ibfbgb_cPbnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
361 return self 2)c-cN zbkbXb[cmblbF ibfbgb_cPbnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
363 def close(self):
364 """Destroy the graph builder.
366 A builder that is still building ends its capture first. The builder
367 is closed even when that fails; the driver error is raised afterwards.
368 """
369 HANDLE_RETURN(GB_close(self)) 2)czbkbF ibfbgbnb. 9 obX jby G R S : 4 b c d e f g h i j k l m n o p q r s t u v a qbxbrbsb*c+cCbBbtbubvbyb,c
371 @property
372 def is_closed(self) -> bool:
373 """Whether this graph builder has been closed."""
374 return self._state == CLOSED 2zbkbR S ,c
376 @property
377 def stream(self) -> Stream:
378 """Returns the stream associated with the graph builder."""
379 GB_check_open(self) 2)cF nbH . 9 x z obX pb1 jby 4bG R S / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E db| abeb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbrbsb= *c+ctbubvb,c?
380 return self._stream 2)cF nbH . 9 x z obX pb1 jby 4bG R S / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E db| abeb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbrbsb= *c+ctbubvb?
382 @property
383 def is_join_required(self) -> bool:
384 """Returns True if this graph builder must be joined before building is ended."""
385 return self._kind == FORKED 1F9XyGRSbcdefghijklmnopqrstuva
387 @property
388 def graph_definition(self) -> GraphDefinition:
389 """The captured graph as an explicit :class:`~graph.GraphDefinition`.
391 .. versionadded:: 1.1.0
393 The returned :class:`~graph.GraphDefinition` is a view of the same
394 graph this builder is producing: nodes added through it appear in
395 subsequent :meth:`complete` and :meth:`debug_dot_print` calls, and
396 the view stays valid even after the builder is closed.
398 This lets you mix the capture and explicit APIs on a single graph,
399 for example to inspect what was captured, augment it with extra
400 nodes, or build a conditional body entirely with the explicit API.
402 Availability:
404 - **Primary builders** (created by :meth:`Device.create_graph_builder`
405 or :meth:`Stream.create_graph_builder`): only after
406 :meth:`end_building`.
408 - **Conditional-body builders** (returned by :meth:`if_then`,
409 :meth:`if_else`, :meth:`while_loop`, :meth:`switch`): both before
410 :meth:`begin_building` and after :meth:`end_building`. The body
411 graph already exists when the conditional is created, so you may
412 populate it through this view without ever calling
413 :meth:`begin_building` on the body builder.
415 - **Forked builders** (returned by :meth:`split`): never. Forked
416 builders share the primary builder's graph; access it through the
417 primary instead.
419 Returns
420 -------
421 GraphDefinition
422 A view of the graph being built.
424 Raises
425 ------
426 RuntimeError
427 If the builder is closed, forked, currently building, or (for
428 primary builders) has not started building yet. A
429 :class:`~graph.GraphDefinition` obtained before :meth:`close`
430 keeps working; only fresh access through this property is
431 rejected once the builder is closed.
432 """
433 GB_check_open(self) 2ibfbgbx Q z ob.cEbX pb1 jb2 I 0 P O V W -
434 if self._kind == FORKED: 2ibfbgbx Q z .cEbX pb1 jb2 I 0 P O V W -
435 raise RuntimeError( 1X
436 "graph_definition is unavailable on forked graph builders; "
437 "access it through the primary builder instead."
438 )
439 elif self._state == CAPTURING: 2ibfbgbx Q z .cEbpb1 jb2 I 0 P O V W -
440 raise RuntimeError( 2Q Eb
441 "graph_definition is unavailable while capture is in "
442 "progress; call end_building() first."
443 )
444 GB_check_has_graph(self) 2ibfbgbx z .cpb1 jb2 I 0 P O V W -
445 if self._kind == PRIMARY: 2x z .cpb1 jb2 I 0 P O V W -
446 if self._state == CAPTURE_NOT_STARTED: 2.cpb1 jb2 I 0 P O V W -
447 raise RuntimeError( 2.c
448 "graph_definition is unavailable before begin_building() on "
449 "a primary builder; no graph has been created yet."
450 )
451 return GraphDefinition._from_handle(self._h_graph) 2x z pb1 jb2 I 0 P O V W -
453 def begin_building(self, mode: str | None = "relaxed") -> GraphBuilder:
454 """Begins the building process.
456 Build `mode` for controlling interaction with other API calls must be one of the following:
458 - `global` : Prohibit potentially unsafe operations across all streams in the process.
459 - `thread_local` : Prohibit potentially unsafe operations in streams created by the current thread.
460 - `relaxed` : The local thread is not prohibited from potentially unsafe operations.
462 Parameters
463 ----------
464 mode : str, optional
465 Build mode to control the interaction with other API calls that are porentially unsafe.
466 Default set to use relaxed.
468 """
469 GB_check_open(self) 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
470 if self._state != CAPTURE_NOT_STARTED: 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
471 if self._state == CAPTURING: 2Pb/
472 raise RuntimeError("Graph builder is already building.") 2Pb
473 else:
474 raise RuntimeError("Cannot resume building after building has ended.") 1/
475 cdef cydriver.CUstreamCaptureMode c_mode
476 if mode == "global": 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
477 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_GLOBAL 2ib` dbUb{ eb) * Y + , DbCb
478 elif mode == "thread_local": 2N zbXbmblbF fbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I [ ^ | abSb] _ } bb5 ! 6 # T U 7 $ 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= Bbtbubvbyb?
479 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_THREAD_LOCAL 2gb^ abSb_ bb! # U $ % DbBb
480 elif mode == "relaxed": 2N zbXbmblbF fbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I [ | ] } 5 6 T 7 8 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= tbubvbyb?
481 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_RELAXED 2N zbXbmblbF fbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I [ | ] } 5 6 T 7 8 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= tbubvbyb?
482 else:
483 raise ValueError(f"Unsupported build mode: {mode}") 2Db
485 cdef cydriver.CUstream c_stream = as_cu(self._h_stream) 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
486 cdef cydriver.CUgraph c_graph
487 cdef cydriver.CUstreamCaptureStatus c_status
488 if self._kind == CONDITIONAL_BODY: 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
489 c_graph = as_cu(self._h_graph) 1xQbcdefghijklmnopqArstuvBCDEwa
490 with nogil: 1xQbcdefghijklmnopqArstuvBCDEwa
491 HANDLE_RETURN(cydriver.cuStreamBeginCaptureToGraph( 1xQbcdefghijklmnopqArstuvBCDEwa
492 c_stream, c_graph, NULL, NULL, 0, c_mode))
493 self._state = CAPTURING 1xQbcdefghijklmnopqArstuvBCDEwa
494 else:
495 with nogil: 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
496 HANDLE_RETURN(cydriver.cuStreamBeginCapture(c_stream, c_mode)) 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
497 # Capture is active now; set CAPTURING before the calls below so a
498 # failure in _get_capture_info/create_graph_handle still lets
499 # cleanup end the capture rather than leaving the stream poisoned.
500 self._state = CAPTURING 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
501 with nogil: 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
502 # The driver rejects a NULL captureStatus_out, so pass a
503 # stack-local even though we only want the graph handle.
504 _get_capture_info(c_stream, &c_status, &c_graph) 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
505 self._h_graph = create_graph_handle(c_graph) 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
506 return self 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
508 @property
509 def is_building(self) -> bool:
510 """Returns True if the graph builder is currently building."""
511 GB_check_open(self) 2lbibfbgbnbH AbI ` [ ^ { ] _
512 cdef cydriver.CUstream c_stream = as_cu(self._h_stream) 2lbibfbgbnbH AbI ` [ ^ { ] _
513 cdef cydriver.CUstreamCaptureStatus status
514 with nogil: 2lbibfbgbnbH AbI ` [ ^ { ] _
515 _get_capture_info(c_stream, &status, NULL) 2lbibfbgbnbH AbI ` [ ^ { ] _
516 if status == cydriver.CU_STREAM_CAPTURE_STATUS_NONE: 2lbibfbgbnbH AbI ` [ ^ { ] _
517 return False 2lbibfbgbAb
518 elif status == cydriver.CU_STREAM_CAPTURE_STATUS_ACTIVE:
519 return True 2nbH AbI ` [ ^ { ] _
520 elif status == cydriver.CU_STREAM_CAPTURE_STATUS_INVALIDATED:
521 raise RuntimeError( 2ibfbgb
522 "Build process encountered an error and has been invalidated. "
523 "Call end_building() to end it; the error is raised there."
524 )
525 else:
526 raise NotImplementedError(f"Unsupported capture status type received: {status}")
528 def end_building(self) -> GraphBuilder:
529 """Ends the building process.
531 Raises
532 ------
533 RuntimeError
534 If the builder is not building. A forked builder is ended by
535 :meth:`join`, not by this method.
536 CUDAError
537 If the capture was invalidated, for example by a CUDA call that is
538 not permitted while capturing. The capture is ended and the
539 builder holds no graph afterwards, so :meth:`complete` and
540 :attr:`graph_definition` are unavailable. This applies to a
541 top-level builder. An invalidated capture of a conditional body
542 leaves the parent builder's graph invalid as well; ending it may
543 crash the process (see issue #2918).
544 """
545 GB_check_open(self) 2N mblbF ibfbgb_cPbwbJ K L M ~ H . x Q z obEbX pb1 jbTby AbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
546 if self._state != CAPTURING: 2N mblbF ibfbgb_cPbwbJ K L M ~ H . x Q z obEbX pb1 jbTby AbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
547 raise RuntimeError("Graph builder is not building.") 2_c
548 if self._kind == FORKED: 2N mblbF ibfbgbPbwbJ K L M ~ H . x Q z obEbX pb1 jbTby AbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
549 raise RuntimeError( 1F
550 "A forked graph builder is ended by GraphBuilder.join(), not end_building().")
551 HANDLE_RETURN(GB_end_capture(self)) 2N mblbF ibfbgbPbwbJ K L M ~ H . x Q z obEbX pb1 jbTby AbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
553 # TODO: Resolving https://github.com/NVIDIA/cuda-python/issues/617 would allow us to
554 # resume the build process after the first call to end_building()
555 return self 2N mblbF PbwbJ K L M ~ H . x Q z obEbX pb1 jbTby AbG / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
557 def complete(self, options: GraphCompleteOptions | None = None) -> Graph:
558 """Completes the graph builder and returns the built :obj:`~graph.Graph` object.
560 Parameters
561 ----------
562 options : :obj:`~graph.GraphCompleteOptions`, optional
563 Customizable dataclass for the graph builder completion options.
565 Returns
566 -------
567 graph : :obj:`~graph.Graph`
568 The newly built graph.
570 """
571 GB_check_open(self) 2N F ibfbgbJ K L M ~ H . 9 x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % w Z ' ; @ cb( = ?
572 GB_check_has_graph(self) 2N F ibfbgbJ K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % w Z ' ; @ cb( = ?
573 if self._state != CAPTURE_ENDED: 2N F J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % w Z ' ; @ cb( = ?
574 raise RuntimeError("Graph has not finished building.") 1~
576 return _instantiate_graph(self, options) 2N F J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % w Z ' ; @ cb( = ?
578 def debug_dot_print(self, path: str, options: GraphDebugPrintOptions | None = None) -> None:
579 """Generates a DOT debug file for the graph builder.
581 Parameters
582 ----------
583 path : str
584 File path to use for writting debug DOT output
585 options : :obj:`~graph.GraphDebugPrintOptions`, optional
586 Customizable dataclass for the debug print options.
588 """
589 GB_check_open(self) 2mba
590 GB_check_has_graph(self) 2mba
591 if self._state != CAPTURE_ENDED: 2mba
592 raise RuntimeError("Graph has not finished building.") 2mb
593 cdef unsigned int c_flags = options._to_flags() if options else 0 2mba
594 cdef cydriver.CUgraph c_graph = as_cu(self._h_graph) 2mba
595 cdef bytes b_path = path.encode('utf-8') 2mba
596 cdef const char* c_path = b_path 2mba
597 with nogil: 2mba
598 HANDLE_RETURN(cydriver.cuGraphDebugDotPrint(c_graph, c_path, c_flags)) 2mba
600 def split(self, count: int) -> tuple[GraphBuilder, ...]:
601 """Splits the original graph builder into multiple graph builders.
603 The new builders inherit work dependencies from the original builder.
604 The original builder is reused for the split and is returned first in the tuple.
606 Parameters
607 ----------
608 count : int
609 The number of graph builders to split the graph builder into.
611 Returns
612 -------
613 graph_builders : tuple[:obj:`~graph.GraphBuilder`, ...]
614 A tuple of split graph builders. The first graph builder in the tuple
615 is always the original graph builder.
617 """
618 if count < 2: 2F 9 X y G R S ^cb c d e f g h i j k l m n o p q r s t u v a
619 raise ValueError(f"Invalid split count: expecting >= 2, got {count}") 1y
620 GB_check_open(self) 2F 9 X y G R S ^cb c d e f g h i j k l m n o p q r s t u v a
621 if self._state != CAPTURING: 2F 9 X y G R S ^cb c d e f g h i j k l m n o p q r s t u v a
622 raise RuntimeError("Graph builder must be building before it can be split.") 2^c
624 event = self._stream.record() 1F9XyGRSbcdefghijklmnopqrstuva
625 result = [self] 1F9XyGRSbcdefghijklmnopqrstuva
626 for _ in range(count - 1): 1F9XyGRSbcdefghijklmnopqrstuva
627 stream = self._stream.device.create_stream() 1F9XyGRSbcdefghijklmnopqrstuva
628 stream.wait(event) 1F9XyGRSbcdefghijklmnopqrstuva
629 result.append(GB_init_forked(stream, self._h_graph)) 1F9XyGRSbcdefghijklmnopqrstuva
630 event.close() 1F9XyGRSbcdefghijklmnopqrstuva
631 return tuple(result) 1F9XyGRSbcdefghijklmnopqrstuva
633 @staticmethod
634 def join(*graph_builders: GraphBuilder) -> GraphBuilder:
635 """Joins multiple graph builders into a single graph builder.
637 The returned builder inherits work dependencies from the provided builders.
638 If joining fails partway, the builders that were not joined are closed
639 before the error propagates, so none is left capturing. A driver error
640 from one of those closes is attached to the propagating error as a note.
642 Parameters
643 ----------
644 *graph_builders : :obj:`~graph.GraphBuilder`
645 The graph builders to join.
647 Returns
648 -------
649 graph_builder : :obj:`~graph.GraphBuilder`
650 The newly joined graph builder.
652 """
653 if any(not isinstance(builder, GraphBuilder) for builder in graph_builders): 2kbF 9 X y G R S {cb c d e f g h i j k l m n o p q r s t u v a
654 raise TypeError("All arguments must be GraphBuilder instances") 2{c
655 if len(graph_builders) < 2: 2kbF 9 X y G R S b c d e f g h i j k l m n o p q r s t u v a
656 raise ValueError("Must join with at least two graph builders") 1y
657 for builder in graph_builders: 2kbF 9 X y G R S b c d e f g h i j k l m n o p q r s t u v a
658 GB_check_open(builder) 2kbF 9 X y G R S b c d e f g h i j k l m n o p q r s t u v a
660 # Discover the root builder others should join
661 root_idx = 0 1F9XyGRSbcdefghijklmnopqrstuva
662 for i, builder in enumerate(graph_builders): 1F9XyGRSbcdefghijklmnopqrstuva
663 if not builder.is_join_required: 1F9XyGRSbcdefghijklmnopqrstuva
664 root_idx = i 1F9XyGRSbcdefghijklmnopqrstuva
665 break 1F9XyGRSbcdefghijklmnopqrstuva
667 # Join all onto the root builder
668 root_bdr = graph_builders[root_idx] 1F9XyGRSbcdefghijklmnopqrstuva
669 cdef GraphBuilder unjoined
670 try: 1F9XyGRSbcdefghijklmnopqrstuva
671 for idx, builder in enumerate(graph_builders): 1F9XyGRSbcdefghijklmnopqrstuva
672 if idx == root_idx: 1F9XyGRSbcdefghijklmnopqrstuva
673 continue 1F9XyGRSbcdefghijklmnopqrstuva
674 root_bdr.stream.wait(builder.stream) 1F9XyGRSbcdefghijklmnopqrstuva
675 builder.close() 1F9XyGbcdefghijklmnopqrstuva
676 except BaseException: 1RS
677 # A fork left open mid-capture crashed the interpreter when it was
678 # collected later (#2776). Close whatever the loop did not reach. A
679 # close that fails (a builder from another capture, which the
680 # refused wait has invalidated) must neither stop this sweep nor
681 # replace the error being raised, so its status is attached to
682 # that error as a note (error handling policy).
683 for idx, builder in enumerate(graph_builders): 1RS
684 if idx != root_idx and not builder.is_closed: 1RS
685 unjoined = builder 1RS
686 attach_rollback_failure( 1RS
687 b"cuStreamEndCapture", GB_close(unjoined),
688 b"failed while closing a graph builder that GraphBuilder.join did not join")
689 raise 1RS
691 return root_bdr 1F9XyGbcdefghijklmnopqrstuva
693 def __cuda_stream__(self) -> tuple[int, int]:
694 """Return an instance of a __cuda_stream__ protocol."""
695 GB_check_open(self) 2)c
696 return self.stream.__cuda_stream__() 2)c
698 def _get_conditional_context(self) -> driver.CUcontext:
699 return self._stream.context.handle 2x Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
701 def create_condition(self, default_value: int | None = None) -> GraphCondition:
702 """Create a condition variable for use with conditional nodes.
704 The returned :class:`GraphCondition` object is passed to conditional-node
705 builder methods (:meth:`if_then`, :meth:`if_else`, :meth:`while_loop`,
706 :meth:`switch`). Its value is controlled at runtime by device code via
707 ``cudaGraphSetConditional``.
709 Parameters
710 ----------
711 default_value : int, optional
712 The default value to assign to the condition. If None, no
713 default is assigned.
715 Returns
716 -------
717 GraphCondition
718 A condition variable for controlling conditional execution.
719 """
720 GB_check_open(self) 2[cx Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
721 if cy_driver_version() < (12, 3, 0): 2[cx Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
722 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional handles")
723 if default_value is not None: 2[cx Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
724 flags = driver.CU_GRAPH_COND_ASSIGN_DEFAULT 2x Q z hbB C D E w
725 else:
726 default_value = 0 2[cb c d e f g h i j k l m n o p q A r s t u v a
727 flags = 0 2[cb c d e f g h i j k l m n o p q A r s t u v a
729 status, _, graph, *_, _ = handle_return(driver.cuStreamGetCaptureInfo(self._stream.handle)) 2[cx Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
730 if status != driver.CUstreamCaptureStatus.CU_STREAM_CAPTURE_STATUS_ACTIVE: 2[cx Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
731 raise RuntimeError("Cannot create a condition when graph is not being built") 2[c
733 raw_handle = handle_return( 2x Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
734 driver.cuGraphConditionalHandleCreate(graph, self._get_conditional_context(), default_value, flags) 2x Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
735 )
736 return GraphCondition._from_handle(<cydriver.CUgraphConditionalHandle><intptr_t>int(raw_handle)) 2x Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
738 def if_then(self, GraphCondition condition not None: GraphCondition) -> GraphBuilder:
739 """Adds an if condition branch and returns a new graph builder for it.
741 The resulting if graph will only execute the branch if the
742 condition evaluates to true at runtime.
744 The new builder inherits work dependencies from the original builder.
746 Parameters
747 ----------
748 condition : :class:`~graph.GraphCondition`
749 The condition variable from :meth:`create_condition` controlling
750 whether the branch executes.
752 Returns
753 -------
754 graph_builder : :obj:`~graph.GraphBuilder`
755 The newly created conditional graph builder.
757 """
758 GB_check_open(self) 2x Q z hbb c d e f g h i A r a
759 if cy_driver_version() < (12, 3, 0): 2x Q z hbb c d e f g h i A r a
760 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional if")
761 if not isinstance(condition, GraphCondition): 2x Q z hbb c d e f g h i A r a
762 raise TypeError(
763 f"condition must be a GraphCondition object (from "
764 f"GraphBuilder.create_condition()), got {type(condition).__name__}")
765 node_params = driver.CUgraphNodeParams() 2x Q z hbb c d e f g h i A r a
766 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 2x Q z hbb c d e f g h i A r a
767 node_params.conditional.handle = condition.handle 2x Q z hbb c d e f g h i A r a
768 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_IF 2x Q z hbb c d e f g h i A r a
769 node_params.conditional.size = 1 2x Q z hbb c d e f g h i A r a
770 node_params.conditional.ctx = self._get_conditional_context() 2x Q z hbb c d e f g h i A r a
771 return GB_cond_with_params(self, node_params)[0] 2x Q z hbb c d e f g h i A r a
773 def if_else(self, GraphCondition condition not None: GraphCondition) -> tuple[GraphBuilder, GraphBuilder]:
774 """Adds an if-else condition branch and returns new graph builders for both branches.
776 The resulting if graph will execute the branch if the condition
777 evaluates to true at runtime, otherwise the else branch will execute.
779 The new builders inherit work dependencies from the original builder.
781 Parameters
782 ----------
783 condition : :class:`~graph.GraphCondition`
784 The condition variable from :meth:`create_condition` controlling
785 which branch executes.
787 Returns
788 -------
789 graph_builders : tuple[:obj:`~graph.GraphBuilder`, :obj:`~graph.GraphBuilder`]
790 A tuple of two new graph builders, one for the if branch and one for the else branch.
792 """
793 GB_check_open(self) 1jklmnopq
794 if cy_driver_version() < (12, 8, 0): 1jklmnopq
795 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional if-else")
796 if not isinstance(condition, GraphCondition): 1jklmnopq
797 raise TypeError(
798 f"condition must be a GraphCondition object (from "
799 f"GraphBuilder.create_condition()), got {type(condition).__name__}")
800 node_params = driver.CUgraphNodeParams() 1jklmnopq
801 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 1jklmnopq
802 node_params.conditional.handle = condition.handle 1jklmnopq
803 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_IF 1jklmnopq
804 node_params.conditional.size = 2 1jklmnopq
805 node_params.conditional.ctx = self._get_conditional_context() 1jklmnopq
806 return GB_cond_with_params(self, node_params) 1jklmnopq
808 def switch(self, GraphCondition condition not None: GraphCondition, count: int) -> tuple[GraphBuilder, ...]:
809 """Adds a switch condition branch and returns new graph builders for all cases.
811 The resulting switch graph will execute the branch whose case index
812 matches the value of the condition at runtime. If no match is found, no
813 branch will be executed.
815 The new builders inherit work dependencies from the original builder.
817 Parameters
818 ----------
819 condition : :class:`~graph.GraphCondition`
820 The condition variable from :meth:`create_condition` selecting
821 which case executes.
822 count : int
823 The number of cases to add to the switch conditional.
825 Returns
826 -------
827 graph_builders : tuple[:obj:`~graph.GraphBuilder`, ...]
828 A tuple of new graph builders, one for each branch.
830 """
831 GB_check_open(self) 1stuvw
832 if cy_driver_version() < (12, 8, 0): 1stuvw
833 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional switch")
834 if not isinstance(condition, GraphCondition): 1stuvw
835 raise TypeError(
836 f"condition must be a GraphCondition object (from "
837 f"GraphBuilder.create_condition()), got {type(condition).__name__}")
838 node_params = driver.CUgraphNodeParams() 1stuvw
839 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 1stuvw
840 node_params.conditional.handle = condition.handle 1stuvw
841 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_SWITCH 1stuvw
842 node_params.conditional.size = count 1stuvw
843 node_params.conditional.ctx = self._get_conditional_context() 1stuvw
844 return GB_cond_with_params(self, node_params) 1stuvw
846 def while_loop(self, GraphCondition condition not None: GraphCondition) -> GraphBuilder:
847 """Adds a while loop and returns a new graph builder for it.
849 The resulting while loop graph will execute the branch repeatedly at runtime
850 until the condition evaluates to false.
852 The new builder inherits work dependencies from the original builder.
854 Parameters
855 ----------
856 condition : :class:`~graph.GraphCondition`
857 The condition variable from :meth:`create_condition` controlling
858 loop continuation.
860 Returns
861 -------
862 graph_builder : :obj:`~graph.GraphBuilder`
863 The newly created while loop graph builder.
865 """
866 GB_check_open(self) 1BCDE
867 if cy_driver_version() < (12, 3, 0): 1BCDE
868 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional while loop")
869 if not isinstance(condition, GraphCondition): 1BCDE
870 raise TypeError(
871 f"condition must be a GraphCondition object (from "
872 f"GraphBuilder.create_condition()), got {type(condition).__name__}")
873 node_params = driver.CUgraphNodeParams() 1BCDE
874 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 1BCDE
875 node_params.conditional.handle = condition.handle 1BCDE
876 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_WHILE 1BCDE
877 node_params.conditional.size = 1 1BCDE
878 node_params.conditional.ctx = self._get_conditional_context() 1BCDE
879 return GB_cond_with_params(self, node_params)[0] 1BCDE
881 def embed(self, GraphBuilder child):
882 """Embed a previously-built :obj:`~graph.GraphBuilder` as a child node.
884 Parameters
885 ----------
886 child : :obj:`~graph.GraphBuilder`
887 The child graph builder. Must have finished building.
888 """
889 GB_check_open(self) 2lbH I
890 GB_check_open(child) 2lbH I
891 GB_check_has_graph(child) 2lbH I
892 if child._state != CAPTURE_ENDED: 2lbH I
893 raise ValueError("Child graph has not finished building.") 2lb
895 if not self.is_building: 2lbH I
896 raise ValueError("Parent graph is not being built.") 2lb
898 stream_handle = self._stream.handle 1HI
899 _, _, graph_out, *deps_info_out, num_dependencies_out = handle_return( 1HI
900 driver.cuStreamGetCaptureInfo(stream_handle) 1HI
901 )
903 # See https://github.com/NVIDIA/cuda-python/pull/879#issuecomment-3211054159
904 # for rationale
905 dependencies_out = deps_info_out[0] 1HI
906 new_node = handle_return( 1HI
907 driver.cuGraphAddChildGraphNode( 1HI
908 graph_out, dependencies_out,
909 num_dependencies_out, as_py(child._h_graph) 1HI
910 )
911 )
912 cdef cydriver.CUgraphNode c_new_node = (
913 <cydriver.CUgraphNode><intptr_t>int(new_node) 1HI
914 )
915 cdef cydriver.CUgraph embedded_graph = NULL 1HI
916 cdef cydriver.CUresult rollback_status
917 cdef GraphHandle h_embedded
918 try: 1HI
919 with nogil: 1HI
920 HANDLE_RETURN(cydriver.cuGraphChildGraphNodeGetGraph( 1HI
921 c_new_node, &embedded_graph))
922 h_embedded = create_child_graph_handle( 1HI
923 embedded_graph, self._h_graph, c_new_node)
924 HANDLE_RETURN(graph_clone_attachments( 1HI
925 h_embedded, child._h_graph))
926 except:
927 with nogil:
928 rollback_status = cydriver.cuGraphDestroyNode(c_new_node)
929 if rollback_status == cydriver.CUDA_SUCCESS:
930 invalidate_child_graph_state(
931 self._h_graph, c_new_node)
932 else:
933 # The original exception propagates with the failed rollback
934 # attached as a note (error handling policy).
935 attach_rollback_failure(
936 b"cuGraphDestroyNode", rollback_status,
937 b"failed while rolling back a child graph node; the node remains in the graph")
938 raise
940 deps_info_update = [[new_node]] + [None] * (len(deps_info_out) - 1) 1HI
941 handle_return( 1HI
942 driver.cuStreamUpdateCaptureDependencies( 1HI
943 stream_handle, 1HI
944 *deps_info_update, # dependencies, edgeData
945 1,
946 driver.CUstreamUpdateCaptureDependencies_flags.CU_STREAM_SET_CAPTURE_DEPENDENCIES, 1HI
947 )
948 )
950 def callback(self, fn, *, user_data=None) -> None:
951 """Add a host callback to the graph during stream capture.
953 The callback runs on the host CPU when the graph reaches this point
954 in execution. Two modes are supported:
956 - **Python callable**: Pass any callable. The GIL is acquired
957 automatically. The callable must take no arguments; use closures
958 or ``functools.partial`` to bind state.
959 - **ctypes function pointer**: The function receives a single
960 ``void*`` argument (the ``user_data``), and the caller must keep
961 the ctypes wrapper alive for the lifetime of the graph. Its
962 declared prototype must match the driver's ``CUhostFn``
963 (``void (*)(void*)``): ``ctypes.CFUNCTYPE(None, ctypes.c_void_p)``,
964 or ``ctypes.WINFUNCTYPE(None, ctypes.c_void_p)`` on Windows.
966 .. warning::
968 Callbacks must not call CUDA API functions. Doing so may
969 deadlock or corrupt driver state.
971 Use caution when a Python callback retains an object that owns a
972 graph. Any reference cycle involving the callback and a graph that
973 retains it cannot be broken by Python's cyclic garbage collector.
974 Use a weak reference to break such cycles.
976 Parameters
977 ----------
978 fn : callable or ctypes function pointer
979 The callback function.
980 user_data : int or bytes-like, optional
981 Only for ctypes function pointers. If ``int``, passed as a raw
982 pointer (caller manages lifetime). If bytes-like, the data is
983 copied and its lifetime is tied to the graph.
985 Raises
986 ------
987 TypeError
988 If ``fn`` is a ctypes function pointer whose declared prototype
989 does not match ``CUhostFn``.
990 ValueError
991 If ``user_data`` is given for a Python callable.
992 """
993 GB_callback(self, fn, user_data, False) 2-cwbJ K L M I
996cdef inline void GB_callback(
997 GraphBuilder gb, object fn, object user_data,
998 bint fail_tail_discovery_for_testing) except *:
999 GB_check_open(gb) 2-cN wbJ K L M I
1000 cdef Stream stream = gb._stream 2-cN wbJ K L M I
1001 cdef cydriver.CUstream c_stream = as_cu(stream._h_stream) 2-cN wbJ K L M I
1002 cdef cydriver.CUstreamCaptureStatus capture_status
1004 with nogil: 2-cN wbJ K L M I
1005 _get_capture_info(c_stream, &capture_status, NULL) 2-cN wbJ K L M I
1007 if capture_status != cydriver.CU_STREAM_CAPTURE_STATUS_ACTIVE: 2-cN wbJ K L M I
1008 raise RuntimeError("Cannot add callback when graph is not being built") 2-c
1010 cdef cydriver.CUhostFn c_fn
1011 cdef void* c_user_data = NULL 2N wbJ K L M I
1012 cdef OpaqueHandle fn_owner, data_owner
1013 cdef PreparedAttachment prepared
1014 _resolve_host_callback( 2N wbJ K L M I
1015 fn, user_data, &c_fn, &c_user_data, &fn_owner, &data_owner)
1016 HANDLE_RETURN(graph_prepare_attachment( 1NJKLMI
1017 gb._h_graph, fn_owner, data_owner, &prepared))
1019 with nogil: 1NJKLMI
1020 HANDLE_RETURN(cydriver.cuLaunchHostFunc(c_stream, c_fn, c_user_data)) 1NJKLMI
1022 # Capturing the host function added a node to the graph; it is now the
1023 # stream's sole capture dependency. Attach the callback's owners to it.
1024 cdef cydriver.CUgraphNode host_node
1025 cdef cydriver.CUresult commit_status
1026 try: 1NJKLMI
1027 if fail_tail_discovery_for_testing: 1NJKLMI
1028 raise RuntimeError("forced capture tail discovery failure") 1N
1029 host_node = _capture_tail_node(c_stream) 1JKLMI
1030 except BaseException as orig_exc: 1N
1031 # CUDA added the callback, but its node cannot be identified.
1032 # Retain its owners anonymously to prevent dangling pointers.
1033 commit_status = graph_commit_attachment(prepared, NULL) 1N
1034 try: 1N
1035 HANDLE_RETURN(commit_status) 1N
1036 except Exception as commit_exc:
1037 raise commit_exc from orig_exc
1038 raise 1N
1039 HANDLE_RETURN(graph_commit_attachment(prepared, host_node)) 1JKLMI
1042def _capture_callback_with_tail_failure_for_testing(
1043 GraphBuilder gb, fn, *, user_data=None):
1044 """Exercise anonymous attachment retention after node discovery fails."""
1045 GB_callback(gb, fn, user_data, True) 1N
1048cdef inline int GB_check_open(GraphBuilder gb) except -1:
1049 """Reject operations on a builder that has been closed.
1051 A CLOSED builder has reset its stream and graph handles, so any method
1052 that dereferences them would read a null handle (or, for the cached
1053 Stream, a None typed as cdef Stream). Guarding here yields a clear error
1054 instead.
1055 """
1056 if gb._state == CLOSED: 2)c-cN zbkbXb[cmblbF ibfbgb_cPbnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
1057 raise RuntimeError("GraphBuilder has been closed") 2)ckbnb9 ob4 ,c
1058 return 0 2)c-cN zbXb[cmblbF ibfbgb_cPbnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb?
1061cdef inline int GB_check_has_graph(GraphBuilder gb) except -1:
1062 """Reject graph access on a builder whose capture ended invalidated.
1064 The driver discards the capture graph when it ends an invalidated
1065 capture, so such a builder has nothing to complete, print, embed, or
1066 update from.
1067 """
1068 if gb._state == CAPTURE_INVALIDATED: 2N mblbF ibfbgbJ K L M ~ H . x z .cpb1 jby G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ cb( a = ?
1069 raise RuntimeError( 2ibfbgb
1070 "The capture was invalidated and the driver discarded its graph; "
1071 "this graph builder has no graph.")
1072 return 0 2N mblbF J K L M ~ H . x z .cpb1 jby G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ cb( a = ?
1075cdef inline cydriver.CUresult GB_end_capture(GraphBuilder gb) noexcept:
1076 """End the capture if this builder owns a live one, and settle ownership
1077 of the graph. Returns the driver status; the caller raises or reports it.
1079 Only a CAPTURING PRIMARY or CONDITIONAL_BODY builder owns the live
1080 capture. A FORKED builder must not call cuStreamEndCapture: the driver
1081 requires forked streams to be joined first.
1083 On success the driver hands back the graph this builder already holds.
1084 When the capture was invalidated (or left unjoined), the driver destroys
1085 the capture graph and returns NULL. The owning handle a PRIMARY builder
1086 took in begin_building() must then forget that graph rather than destroy
1087 it a second time, and the builder ends up with no graph at all.
1088 """
1089 cdef cydriver.CUgraph c_graph = NULL 2)c-cN zbkbXb[cmblbF ibfbgb_cPb|cnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I }c` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
1090 cdef cydriver.CUresult err = cydriver.CUDA_SUCCESS 2)c-cN zbkbXb[cmblbF ibfbgb_cPb|cnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I }c` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
1091 cdef cydriver.CUstream c_stream
1092 if not gb._h_stream or gb._state != CAPTURING or gb._kind == FORKED: 2)c-cN zbkbXb[cmblbF ibfbgb_cPb|cnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby 4bAbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I }c` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
1093 return err 2)c-cN zbkb[cmblbF ibfbgb_cPb|cnbwbJ K L M ~ H . 9 x Q z ob.cEbX pb1 jbTby AbG R S / ^c3 : 4 hb{c2 b c d e f g h i j k l m n o p q A r s t u v B C D E I }c` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= *c+cCbBbtbubvbyb,c?
1094 c_stream = as_cu(gb._h_stream) 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
1095 with nogil: 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
1096 err = cydriver.cuStreamEndCapture(c_stream, &c_graph) 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
1097 if c_graph == NULL: 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
1098 # Only a PRIMARY builder owns a graph hierarchy to retire. A
1099 # CONDITIONAL_BODY graph belongs to the parent's conditional node; the
1100 # driver destroys it as well when the body capture ends invalidated and
1101 # leaves the parent graph referring to it, which cuda.core cannot
1102 # repair (see the end_building docstring). Only this builder's alias
1103 # is dropped here.
1104 if gb._kind == PRIMARY: 2zbXbibfbgbR S UbSb
1105 invalidate_root_graph_state(gb._h_graph) 2zbXbibfbgbR S UbSb
1106 gb._h_graph.reset() 2zbXbibfbgbR S UbSb
1107 gb._state = CAPTURE_INVALIDATED 2zbXbibfbgbR S UbSb
1108 else:
1109 gb._state = CAPTURE_ENDED 2N mblbF PbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
1110 return err 2N zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
1113cdef inline cydriver.CUresult GB_close(GraphBuilder gb) noexcept:
1114 """Close the builder and return the status of ending its capture.
1116 The builder is closed whatever that status is. close() raises it; join()
1117 attaches it to the error already propagating.
1118 """
1119 cdef cydriver.CUresult err = GB_end_capture(gb) 2)czbkbF ibfbgbnb. 9 obX jby G R S : 4 b c d e f g h i j k l m n o p q r s t u v a qbxbrbsb*c+cCbBbtbubvbyb,c
1120 gb._h_graph.reset() 2)czbkbF ibfbgbnb. 9 obX jby G R S : 4 b c d e f g h i j k l m n o p q r s t u v a qbxbrbsb*c+cCbBbtbubvbyb,c
1121 gb._h_stream.reset() 2)czbkbF ibfbgbnb. 9 obX jby G R S : 4 b c d e f g h i j k l m n o p q r s t u v a qbxbrbsb*c+cCbBbtbubvbyb,c
1122 retry_deferred_cleanup() 2)czbkbF ibfbgbnb. 9 obX jby G R S : 4 b c d e f g h i j k l m n o p q r s t u v a qbxbrbsb*c+cCbBbtbubvbyb,c
1123 gb._state = CLOSED 2)czbkbF ibfbgbnb. 9 obX jby G R S : 4 b c d e f g h i j k l m n o p q r s t u v a qbxbrbsb*c+cCbBbtbubvbyb,c
1124 gb._stream = None 2)czbkbF ibfbgbnb. 9 obX jby G R S : 4 b c d e f g h i j k l m n o p q r s t u v a qbxbrbsb*c+cCbBbtbubvbyb,c
1125 return err 2)czbkbF ibfbgbnb. 9 obX jby G R S : 4 b c d e f g h i j k l m n o p q r s t u v a qbxbrbsb*c+cCbBbtbubvbyb,c
1128cdef inline GraphBuilder GB_init_forked(Stream stream, GraphHandle h_primary_graph):
1129 cdef GraphBuilder gb = GraphBuilder.__new__(GraphBuilder) 1F9XyGRSbcdefghijklmnopqrstuva
1130 # A FORKED builder captures into the primary's CUgraph. It holds the
1131 # primary's GraphHandle so conditional bodies share its graph hierarchy.
1132 gb._h_graph = h_primary_graph 1F9XyGRSbcdefghijklmnopqrstuva
1133 gb._h_stream = stream._h_stream 1F9XyGRSbcdefghijklmnopqrstuva
1134 gb._kind = FORKED 1F9XyGRSbcdefghijklmnopqrstuva
1135 gb._state = CAPTURING 1F9XyGRSbcdefghijklmnopqrstuva
1136 gb._stream = stream 1F9XyGRSbcdefghijklmnopqrstuva
1137 return gb 1F9XyGRSbcdefghijklmnopqrstuva
1140cdef inline GraphBuilder GB_init_conditional(
1141 Stream stream, cydriver.CUgraph cond_graph,
1142 GraphBuilder parent, cydriver.CUgraphNode owner_node):
1143 cdef GraphBuilder gb = GraphBuilder.__new__(GraphBuilder) 1xQzbcdefghijklmnopqArstuvBCDEwa
1144 gb._h_graph = create_child_graph_handle( 1xQzbcdefghijklmnopqArstuvBCDEwa
1145 cond_graph, parent._h_graph, owner_node)
1146 gb._h_stream = stream._h_stream 1xQzbcdefghijklmnopqArstuvBCDEwa
1147 gb._kind = CONDITIONAL_BODY 1xQzbcdefghijklmnopqArstuvBCDEwa
1148 gb._state = CAPTURE_NOT_STARTED 1xQzbcdefghijklmnopqArstuvBCDEwa
1149 gb._stream = stream 1xQzbcdefghijklmnopqArstuvBCDEwa
1150 return gb 1xQzbcdefghijklmnopqArstuvBCDEwa
1153cdef inline int _get_capture_info(
1154 cydriver.CUstream stream,
1155 cydriver.CUstreamCaptureStatus* status,
1156 cydriver.CUgraph* graph) except?-1 nogil:
1157 """Thin wrapper around ``cuStreamGetCaptureInfo`` that papers over the
1158 CUDA 12 vs 13 signature change.
1160 ``status`` must be non-NULL: the driver rejects ``captureStatus_out=NULL``
1161 with ``CUDA_ERROR_INVALID_VALUE``. ``graph`` may be NULL when the caller
1162 does not need the graph handle.
1163 """
1164 IF CUDA_CORE_BUILD_MAJOR >= 13:
1165 return HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 2-cN zbXbmblbF ibfbgbPbnbwbJ K L M ~ H . 9 x Q z obEbX pb1 jbTby 4bAbG R S / 3 : 4 hb2 b c d e f g h i j k l m n o p q A r s t u v B C D E I ` [ ^ db| abUbSb{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % 0 P O V W - w Z ' ; @ Dbcb( a qbxbrbsb= CbBbtbubvbyb?
1166 stream, status, NULL, graph, NULL, NULL, NULL))
1167 ELSE:
1168 return HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo(
1169 stream, status, NULL, graph, NULL, NULL))
1172cdef inline cydriver.CUgraphNode _capture_tail_node(cydriver.CUstream stream) except *:
1173 """Return the node a freshly-captured single-node operation left as the
1174 stream's sole capture dependency (e.g. the host node added by
1175 ``cuLaunchHostFunc``). The driver advances the stream's dependency set to
1176 the new node, so the next captured op would depend on it.
1177 """
1178 cdef cydriver.CUstreamCaptureStatus status
1179 cdef const cydriver.CUgraphNode* deps = NULL 1JKLMI
1180 cdef size_t num_deps = 0 1JKLMI
1181 with nogil: 1JKLMI
1182 IF CUDA_CORE_BUILD_MAJOR >= 13:
1183 HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 1JKLMI
1184 stream, &status, NULL, NULL, &deps, NULL, &num_deps))
1185 ELSE:
1186 HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo(
1187 stream, &status, NULL, NULL, &deps, &num_deps))
1188 if num_deps != 1: 1JKLMI
1189 raise RuntimeError(
1190 f"expected exactly one capture dependency after a host callback, got {num_deps}")
1191 return <cydriver.CUgraphNode>deps[0] 1JKLMI
1194cdef inline tuple GB_cond_with_params(GraphBuilder gb, node_params):
1195 status, _, graph, *deps_info, num_dependencies = handle_return( 2x Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
1196 driver.cuStreamGetCaptureInfo(gb._stream.handle) 2x Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
1197 )
1198 if status != driver.CUstreamCaptureStatus.CU_STREAM_CAPTURE_STATUS_ACTIVE: 2x Q z hbb c d e f g h i j k l m n o p q A r s t u v B C D E w a
1199 raise RuntimeError("Cannot add conditional node when not actively capturing") 2hb
1201 new_node = handle_return( 1xQzbcdefghijklmnopqArstuvBCDEwa
1202 driver.cuGraphAddNode(graph, *deps_info, num_dependencies, node_params)) 1xQzbcdefghijklmnopqArstuvBCDEwa
1203 deps_info_update = [[new_node]] + [None] * (len(deps_info) - 1) 1xQzbcdefghijklmnopqArstuvBCDEwa
1205 handle_return( 1xQzbcdefghijklmnopqArstuvBCDEwa
1206 driver.cuStreamUpdateCaptureDependencies( 1xQzbcdefghijklmnopqArstuvBCDEwa
1207 gb._stream.handle, 1xQzbcdefghijklmnopqArstuvBCDEwa
1208 *deps_info_update, # dependencies, edgeData 1xQzbcdefghijklmnopqArstuvBCDEwa
1209 1, # numDependencies
1210 driver.CUstreamUpdateCaptureDependencies_flags.CU_STREAM_SET_CAPTURE_DEPENDENCIES, 1xQzbcdefghijklmnopqArstuvBCDEwa
1211 )
1212 )
1214 return tuple( 1xQzbcdefghijklmnopqArstuvBCDEwa
1215 GB_init_conditional( 1xQzbcdefghijklmnopqArstuvBCDEwa
1216 gb._stream.device.create_stream(), 1xQzbcdefghijklmnopqArstuvBCDEwa
1217 <cydriver.CUgraph><intptr_t>int(node_params.conditional.phGraph_out[i]), 1xQzbcdefghijklmnopqArstuvBCDEwa
1218 gb, 1xQzbcdefghijklmnopqArstuvBCDEwa
1219 <cydriver.CUgraphNode><intptr_t>int(new_node), 1xQzbcdefghijklmnopqArstuvBCDEwa
1220 )
1221 for i in range(node_params.conditional.size) 1xQzbcdefghijklmnopqArstuvBCDEwa
1222 )
1225cdef class Graph:
1226 """An executable graph.
1228 A graph groups a set of CUDA kernels and other CUDA operations together and executes
1229 them with a specified dependency tree. It speeds up the workflow by combining the
1230 driver activities associated with CUDA kernel launches and CUDA API calls.
1232 Graphs must be built using a :obj:`~graph.GraphBuilder` object.
1234 """
1236 def __init__(self):
1237 raise RuntimeError("directly constructing a Graph instance is not supported") 2|c
1239 @staticmethod
1240 cdef Graph _init(GraphExecHandle h_graph_exec):
1241 cdef Graph self = Graph.__new__(Graph) 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
1242 self._h_graph_exec = h_graph_exec 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
1243 return self 2N kbF J K L M ~ H . x z 1 y G / 3 : 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bgc/c:chc;c=c?cicjckc+b,b@clcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc` [ ^ db| ab{ ] _ eb} bb) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ ( = ?
1245 def close(self) -> None:
1246 """Destroy the graph."""
1247 self._h_graph_exec.reset() 2kb. : dcecfc.b(
1248 retry_deferred_cleanup() 2kb. : dcecfc.b(
1250 @property
1251 def is_closed(self) -> bool:
1252 """Whether this executable graph has been closed."""
1253 return self._h_graph_exec.get() == NULL 2kb
1255 @property
1256 def handle(self) -> driver.CUgraphExec:
1257 """Return the underlying ``CUgraphExec`` object.
1259 .. caution::
1261 This handle is a Python object. To get the memory address of the underlying C
1262 handle, call ``int()`` on the returned object.
1264 """
1265 return as_py(self._h_graph_exec) 2. 6c
1267 @overload
1268 def __getitem__(self, node: KernelNode) -> ExecutableKernelNode: ...
1269 @overload
1270 def __getitem__(self, node: MemsetNode) -> ExecutableMemsetNode: ...
1271 @overload
1272 def __getitem__(self, node: MemcpyNode) -> ExecutableMemcpyNode: ...
1273 @overload
1274 def __getitem__(self, node: ChildGraphNode) -> ExecutableChildGraphNode: ...
1275 @overload
1276 def __getitem__(self, node: EventRecordNode) -> ExecutableEventRecordNode: ...
1277 @overload
1278 def __getitem__(self, node: EventWaitNode) -> ExecutableEventWaitNode: ...
1279 @overload
1280 def __getitem__(self, node: HostCallbackNode) -> ExecutableHostCallbackNode: ...
1282 def __getitem__(self, GraphNode node not None: GraphNode) -> ExecutableGraphNode:
1283 """Return a view for updating *node* in this executable graph.
1285 *node* is a definition node from the graph used to instantiate this
1286 executable. Call ``update()`` on the returned view to replace that
1287 node's parameters for future launches. Kernel, memcpy, and memset
1288 views also support enabling and disabling the node.
1289 """
1290 Graph_check_open(self) 2kb/b.b:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacFbQbP O bcccRb
1291 GN_check_valid(node) 2/b.b:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacFbQbP O bcccRb
1292 return create_executable_node_view( 2/b.b:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacFbQbP O bcccRb
1293 self._h_graph_exec, node) 2/b.b:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacFbQbP O bcccRb
1295 def update(self, source: "GraphBuilder | GraphDefinition") -> None:
1296 """Update the graph using a new graph definition.
1298 The topology of the provided source must be identical to this graph.
1300 Parameters
1301 ----------
1302 source : :obj:`~graph.GraphBuilder` or :obj:`~graph.GraphDefinition`
1303 The graph definition to update from. A GraphBuilder must have
1304 finished building.
1306 """
1307 Graph_check_open(self) 2kb4 FbQbP O V W RbVbWbw Z 2b3b' ; @
1308 cdef GraphHandle h_source
1310 if isinstance(source, GraphBuilder): 24 FbQbP O V W RbVbWbw Z 2b3b' ; @
1311 GB_check_open(<GraphBuilder>source) 14wZ';
1312 GB_check_has_graph(<GraphBuilder>source) 1wZ';
1313 if (<GraphBuilder>source)._state != CAPTURE_ENDED: 1wZ';
1314 raise ValueError("Graph has not finished building.") 1;
1315 h_source = (<GraphBuilder>source)._h_graph 1wZ'
1316 elif isinstance(source, GraphDefinition): 2FbQbP O V W RbVbWb2b3b@
1317 GD_check_valid(<GraphDefinition>source) 2FbQbP O V W RbVbWb2b3b
1318 h_source = (<GraphDefinition>source)._h_graph 2FbQbP O V W RbVbWb2b3b
1319 else:
1320 raise TypeError( 1@
1321 f"expected GraphBuilder or GraphDefinition, got {type(source).__name__}") 1@
1323 cdef cydriver.CUgraphExecUpdateResultInfo result_info
1324 cdef cydriver.CUresult err = graph_exec_update( 2FbQbP O V W RbVbWbw Z 2b3b'
1325 self._h_graph_exec, h_source, &result_info)
1326 if err == cydriver.CUresult.CUDA_ERROR_GRAPH_EXEC_UPDATE_FAILURE: 2FbQbP O V W RbVbWbw Z 2b3b'
1327 reason = driver.CUgraphExecUpdateResult(result_info.result) 2FbO VbWb'
1328 msg = f"Graph update failed: {reason.__doc__.strip()} ({reason.name})" 2FbO VbWb'
1329 raise CUDAError(msg) 2FbO VbWb'
1330 HANDLE_RETURN(err) 2QbP V W Rbw Z 2b3b
1332 def upload(self, Stream stream not None: Stream) -> None:
1333 """Uploads the graph in a stream.
1335 Parameters
1336 ----------
1337 stream : :obj:`~_stream.Stream`
1338 The stream in which to upload the graph
1340 """
1341 Graph_check_open(self) 2kby 3 5b6b7b8b9bGb!bHb#b$b%b'bIb(bJbKbLb)bMbNb*bOb+b,b-b) 5 ! * 6 # Y T U + 7 $ , 8 %
1342 cdef Stream s = Stream_accept(stream) 2y 3 5b6b7b8b9bGb!bHb#b$b%b'bIb(bJbKbLb)bMbNb*bOb+b,b-b) 5 ! * 6 # Y T U + 7 $ , 8 %
1343 cdef cydriver.CUgraphExec c_exec = as_cu(self._h_graph_exec) 2y 3 5b6b7b8b9bGb!bHb#b$b%b'bIb(bJbKbLb)bMbNb*bOb+b,b-b) 5 ! * 6 # Y T U + 7 $ , 8 %
1344 cdef cydriver.CUstream c_stream = as_cu(s._h_stream) 2y 3 5b6b7b8b9bGb!bHb#b$b%b'bIb(bJbKbLb)bMbNb*bOb+b,b-b) 5 ! * 6 # Y T U + 7 $ , 8 %
1345 with nogil: 2y 3 5b6b7b8b9bGb!bHb#b$b%b'bIb(bJbKbLb)bMbNb*bOb+b,b-b) 5 ! * 6 # Y T U + 7 $ , 8 %
1346 HANDLE_RETURN(cydriver.cuGraphUpload(c_exec, c_stream)) 2y 3 5b6b7b8b9bGb!bHb#b$b%b'bIb(bJbKbLb)bMbNb*bOb+b,b-b) 5 ! * 6 # Y T U + 7 $ , 8 %
1348 def launch(self, Stream stream not None: Stream) -> None:
1349 """Launches the graph in a stream.
1351 Parameters
1352 ----------
1353 stream : :obj:`~_stream.Stream`
1354 The stream in which to launch the graph.
1356 """
1357 Graph_check_open(self) 2N kbJ K L M H x z 1 y / 3 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bicjckc+b,blcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b0 ;b=b?b@b[b]b^b_b`b{b|b}b~bacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b= ?
1358 cdef Stream s = Stream_accept(stream) 2N J K L M H x z 1 y / 3 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bicjckc+b,blcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b0 ;b=b?b@b[b]b^b_b`b{b|b}b~bacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b= ?
1359 cdef cydriver.CUgraphExec c_exec = as_cu(self._h_graph_exec) 2N J K L M H x z 1 y / 3 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bicjckc+b,blcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b0 ;b=b?b@b[b]b^b_b`b{b|b}b~bacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b= ?
1360 cdef cydriver.CUstream c_stream = as_cu(s._h_stream) 2N J K L M H x z 1 y / 3 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bicjckc+b,blcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b0 ;b=b?b@b[b]b^b_b`b{b|b}b~bacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b= ?
1361 with nogil: 2N J K L M H x z 1 y / 3 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bicjckc+b,blcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b0 ;b=b?b@b[b]b^b_b`b{b|b}b~bacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b= ?
1362 HANDLE_RETURN(cydriver.cuGraphLaunch(c_exec, c_stream)) 2N J K L M H x z 1 y / 3 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bicjckc+b,blcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b0 ;b=b?b@b[b]b^b_b`b{b|b}b~bacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b= ?
1365cdef inline int Graph_check_open(Graph self) except -1:
1366 if not self._h_graph_exec: 2N kbJ K L M H x z 1 y / 3 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bicjckc+b,blcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ = ?
1367 raise RuntimeError("Graph has been closed") 2kb
1368 return 0 2N J K L M H x z 1 y / 3 4 2 b c d e f g h i j k l m n o p q A r s t u v B C D E 5b6b7b8b9bGb!bHbYb#b$b%b'bIb(bJbZbKbLb)bMb0bNb*bOb1bicjckc+b,blcdcecmcncocpcqcrcfcsctcucvcwc-bxcyczcAcBcCcDc) 5 ! * 6 # Y T U + 7 $ , 8 % /b.bEcFcGcHcIcJcKcLcMcNcOcPcQc:b7c8c9c!c#c0 $c%c'c6c;b=b?b@b[b]b^b_b`b{b|b}b~b(cacRcScTcUcVcWcXcYcZc0c1c2c3cFbQb4c5cP O V W - bcccRbVbWbw Z 2b3b' ; @ = ?