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

1# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 

2# 

3# SPDX-License-Identifier: Apache-2.0 

4  

5from dataclasses import dataclass 

6from typing import TYPE_CHECKING 

7  

8from libc.stdint cimport intptr_t 

9  

10from cuda.bindings cimport cydriver 

11  

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 

57  

58from cuda.core._utils.cuda_utils import ( 

59 CUDAError, 

60 driver, 

61 handle_return, 

62) 

63  

64if TYPE_CHECKING: 

65 from typing import overload 

66  

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 

75  

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 """ 

87  

88__all__ = ['Graph', 'GraphBuilder', 'GraphCompleteOptions', 'GraphDebugPrintOptions'] 

89  

90  

91@dataclass 

92class GraphDebugPrintOptions: 

93 """Options for debug_dot_print(). 

94  

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) 

129  

130 """ 

131  

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 

148  

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

185  

186  

187@dataclass 

188class GraphCompleteOptions: 

189 """Options for graph instantiation. 

190  

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) 

204  

205 """ 

206  

207 auto_free_on_launch: bool = False 

208 upload_stream: Stream | None = None 

209 device_launch: bool = False 

210 use_node_priority: bool = False 

211  

212  

213def _instantiate_graph(source, options: GraphCompleteOptions | None = None) -> Graph: 

214 cdef GraphHandle h_graph 

215 cdef GraphExecHandle h_exec 

216 cdef cydriver.CUresult status 

217  

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__}") 

227  

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(

246  

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, &params) 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}") 

271  

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' ; @ ( = ?

275  

276  

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 

303  

304  

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 

312  

313  

314cdef class GraphBuilder: 

315 """A graph under construction by stream capture. 

316  

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. 

320  

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. 

324  

325 .. note:: 

326  

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. 

336  

337 """ 

338  

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 ) 

344  

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") 

352  

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?

362  

363 def close(self): 

364 """Destroy the graph builder. 

365  

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

370  

371 @property 

372 def is_closed(self) -> bool: 

373 """Whether this graph builder has been closed.""" 

374 return self._state == CLOSED 2zbkbR S ,c

375  

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?

381  

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

386  

387 @property 

388 def graph_definition(self) -> GraphDefinition: 

389 """The captured graph as an explicit :class:`~graph.GraphDefinition`. 

390  

391 .. versionadded:: 1.1.0 

392  

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. 

397  

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. 

401  

402 Availability: 

403  

404 - **Primary builders** (created by :meth:`Device.create_graph_builder` 

405 or :meth:`Stream.create_graph_builder`): only after 

406 :meth:`end_building`. 

407  

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. 

414  

415 - **Forked builders** (returned by :meth:`split`): never. Forked 

416 builders share the primary builder's graph; access it through the 

417 primary instead. 

418  

419 Returns 

420 ------- 

421 GraphDefinition 

422 A view of the graph being built. 

423  

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 -

452  

453 def begin_building(self, mode: str | None = "relaxed") -> GraphBuilder: 

454 """Begins the building process. 

455  

456 Build `mode` for controlling interaction with other API calls must be one of the following: 

457  

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. 

461  

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. 

467  

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

484  

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?

507  

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}") 

527  

528 def end_building(self) -> GraphBuilder: 

529 """Ends the building process. 

530  

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?

552  

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?

556  

557 def complete(self, options: GraphCompleteOptions | None = None) -> Graph: 

558 """Completes the graph builder and returns the built :obj:`~graph.Graph` object. 

559  

560 Parameters 

561 ---------- 

562 options : :obj:`~graph.GraphCompleteOptions`, optional 

563 Customizable dataclass for the graph builder completion options. 

564  

565 Returns 

566 ------- 

567 graph : :obj:`~graph.Graph` 

568 The newly built graph. 

569  

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~

575  

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( = ?

577  

578 def debug_dot_print(self, path: str, options: GraphDebugPrintOptions | None = None) -> None: 

579 """Generates a DOT debug file for the graph builder. 

580  

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. 

587  

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

599  

600 def split(self, count: int) -> tuple[GraphBuilder, ...]: 

601 """Splits the original graph builder into multiple graph builders. 

602  

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. 

605  

606 Parameters 

607 ---------- 

608 count : int 

609 The number of graph builders to split the graph builder into. 

610  

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. 

616  

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

623  

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

632  

633 @staticmethod 

634 def join(*graph_builders: GraphBuilder) -> GraphBuilder: 

635 """Joins multiple graph builders into a single graph builder. 

636  

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. 

641  

642 Parameters 

643 ---------- 

644 *graph_builders : :obj:`~graph.GraphBuilder` 

645 The graph builders to join. 

646  

647 Returns 

648 ------- 

649 graph_builder : :obj:`~graph.GraphBuilder` 

650 The newly joined graph builder. 

651  

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

659  

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

666  

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

690  

691 return root_bdr 1F9XyGbcdefghijklmnopqrstuva

692  

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

697  

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

700  

701 def create_condition(self, default_value: int | None = None) -> GraphCondition: 

702 """Create a condition variable for use with conditional nodes. 

703  

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``. 

708  

709 Parameters 

710 ---------- 

711 default_value : int, optional 

712 The default value to assign to the condition. If None, no 

713 default is assigned. 

714  

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

728  

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

732  

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

737  

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. 

740  

741 The resulting if graph will only execute the branch if the 

742 condition evaluates to true at runtime. 

743  

744 The new builder inherits work dependencies from the original builder. 

745  

746 Parameters 

747 ---------- 

748 condition : :class:`~graph.GraphCondition` 

749 The condition variable from :meth:`create_condition` controlling 

750 whether the branch executes. 

751  

752 Returns 

753 ------- 

754 graph_builder : :obj:`~graph.GraphBuilder` 

755 The newly created conditional graph builder. 

756  

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

772  

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. 

775  

776 The resulting if graph will execute the branch if the condition 

777 evaluates to true at runtime, otherwise the else branch will execute. 

778  

779 The new builders inherit work dependencies from the original builder. 

780  

781 Parameters 

782 ---------- 

783 condition : :class:`~graph.GraphCondition` 

784 The condition variable from :meth:`create_condition` controlling 

785 which branch executes. 

786  

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. 

791  

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

807  

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. 

810  

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. 

814  

815 The new builders inherit work dependencies from the original builder. 

816  

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. 

824  

825 Returns 

826 ------- 

827 graph_builders : tuple[:obj:`~graph.GraphBuilder`, ...] 

828 A tuple of new graph builders, one for each branch. 

829  

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

845  

846 def while_loop(self, GraphCondition condition not None: GraphCondition) -> GraphBuilder: 

847 """Adds a while loop and returns a new graph builder for it. 

848  

849 The resulting while loop graph will execute the branch repeatedly at runtime 

850 until the condition evaluates to false. 

851  

852 The new builder inherits work dependencies from the original builder. 

853  

854 Parameters 

855 ---------- 

856 condition : :class:`~graph.GraphCondition` 

857 The condition variable from :meth:`create_condition` controlling 

858 loop continuation. 

859  

860 Returns 

861 ------- 

862 graph_builder : :obj:`~graph.GraphBuilder` 

863 The newly created while loop graph builder. 

864  

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

880  

881 def embed(self, GraphBuilder child): 

882 """Embed a previously-built :obj:`~graph.GraphBuilder` as a child node. 

883  

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

894  

895 if not self.is_building: 2lbH I

896 raise ValueError("Parent graph is not being built.") 2lb

897  

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 ) 

902  

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 

939  

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 ) 

949  

950 def callback(self, fn, *, user_data=None) -> None: 

951 """Add a host callback to the graph during stream capture. 

952  

953 The callback runs on the host CPU when the graph reaches this point 

954 in execution. Two modes are supported: 

955  

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. 

965  

966 .. warning:: 

967  

968 Callbacks must not call CUDA API functions. Doing so may 

969 deadlock or corrupt driver state. 

970  

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. 

975  

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. 

984  

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

994  

995  

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 

1003  

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

1006  

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

1009  

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)) 

1018  

1019 with nogil: 1NJKLMI

1020 HANDLE_RETURN(cydriver.cuLaunchHostFunc(c_stream, c_fn, c_user_data)) 1NJKLMI

1021  

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

1040  

1041  

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

1046  

1047  

1048cdef inline int GB_check_open(GraphBuilder gb) except -1: 

1049 """Reject operations on a builder that has been closed. 

1050  

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?

1059  

1060  

1061cdef inline int GB_check_has_graph(GraphBuilder gb) except -1: 

1062 """Reject graph access on a builder whose capture ended invalidated. 

1063  

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 = ?

1073  

1074  

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. 

1078  

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. 

1082  

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?

1111  

1112  

1113cdef inline cydriver.CUresult GB_close(GraphBuilder gb) noexcept: 

1114 """Close the builder and return the status of ending its capture. 

1115  

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

1126  

1127  

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

1138  

1139  

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

1151  

1152  

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. 

1159  

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)) 

1170  

1171  

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

1192  

1193  

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

1200  

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

1204  

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 ) 

1213  

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 ) 

1223  

1224  

1225cdef class Graph: 

1226 """An executable graph. 

1227  

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. 

1231  

1232 Graphs must be built using a :obj:`~graph.GraphBuilder` object. 

1233  

1234 """ 

1235  

1236 def __init__(self): 

1237 raise RuntimeError("directly constructing a Graph instance is not supported") 2|c

1238  

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' ; @ ( = ?

1244  

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(

1249  

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

1254  

1255 @property 

1256 def handle(self) -> driver.CUgraphExec: 

1257 """Return the underlying ``CUgraphExec`` object. 

1258  

1259 .. caution:: 

1260  

1261 This handle is a Python object. To get the memory address of the underlying C 

1262 handle, call ``int()`` on the returned object. 

1263  

1264 """ 

1265 return as_py(self._h_graph_exec) 2. 6c

1266  

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: ... 

1281  

1282 def __getitem__(self, GraphNode node not None: GraphNode) -> ExecutableGraphNode: 

1283 """Return a view for updating *node* in this executable graph. 

1284  

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

1294  

1295 def update(self, source: "GraphBuilder | GraphDefinition") -> None: 

1296 """Update the graph using a new graph definition. 

1297  

1298 The topology of the provided source must be identical to this graph. 

1299  

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. 

1305  

1306 """ 

1307 Graph_check_open(self) 2kb4 FbQbP O V W RbVbWbw Z 2b3b' ; @

1308 cdef GraphHandle h_source 

1309  

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@

1322  

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

1331  

1332 def upload(self, Stream stream not None: Stream) -> None: 

1333 """Uploads the graph in a stream. 

1334  

1335 Parameters 

1336 ---------- 

1337 stream : :obj:`~_stream.Stream` 

1338 The stream in which to upload the graph 

1339  

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 %

1347  

1348 def launch(self, Stream stream not None: Stream) -> None: 

1349 """Launches the graph in a stream. 

1350  

1351 Parameters 

1352 ---------- 

1353 stream : :obj:`~_stream.Stream` 

1354 The stream in which to launch the graph. 

1355  

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= ?

1363  

1364  

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' ; @ = ?