Coverage for cuda/core/graph/_graph_builder.pyx: 88.39%

491 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-03 02:41 +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 ExecutableGraphNode, 

21 create_executable_node_view, 

22) 

23from cuda.core._resource_handles cimport ( 

24 GraphExecHandle, 

25 GraphHandle, 

26 OpaqueHandle, 

27 PreparedAttachment, 

28 as_cu, as_py, 

29 create_child_graph_handle, create_graph_exec_handle, create_graph_handle, 

30 get_last_error, 

31 graph_clone_attachments, 

32 graph_commit_attachment, 

33 graph_exec_update, 

34 graph_prepare_attachment, 

35 invalidate_child_graph_state, 

36 retry_deferred_cleanup, 

37) 

38from cuda.core._stream cimport Stream, Stream_accept 

39from cuda.core._utils.cuda_utils cimport HANDLE_RETURN 

40from cuda.core._utils.version cimport cy_binding_version, cy_driver_version 

41  

42from cuda.core._utils.cuda_utils import ( 

43 CUDAError, 

44 driver, 

45 handle_return, 

46) 

47  

48if TYPE_CHECKING: 

49 from cuda.core.graph._graph_definition import GraphDefinition 

50  

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

52  

53  

54@dataclass 

55class GraphDebugPrintOptions: 

56 """Options for debug_dot_print(). 

57  

58 Attributes 

59 ---------- 

60 verbose : bool 

61 Output all debug data as if every debug flag is enabled (Default to False) 

62 runtime_types : bool 

63 Use CUDA Runtime structures for output (Default to False) 

64 kernel_node_params : bool 

65 Adds kernel parameter values to output (Default to False) 

66 memcpy_node_params : bool 

67 Adds memcpy parameter values to output (Default to False) 

68 memset_node_params : bool 

69 Adds memset parameter values to output (Default to False) 

70 host_node_params : bool 

71 Adds host parameter values to output (Default to False) 

72 event_node_params : bool 

73 Adds event parameter values to output (Default to False) 

74 ext_semas_signal_node_params : bool 

75 Adds external semaphore signal parameter values to output (Default to False) 

76 ext_semas_wait_node_params : bool 

77 Adds external semaphore wait parameter values to output (Default to False) 

78 kernel_node_attributes : bool 

79 Adds kernel node attributes to output (Default to False) 

80 handles : bool 

81 Adds node handles and every kernel function handle to output (Default to False) 

82 mem_alloc_node_params : bool 

83 Adds memory alloc parameter values to output (Default to False) 

84 mem_free_node_params : bool 

85 Adds memory free parameter values to output (Default to False) 

86 batch_mem_op_node_params : bool 

87 Adds batch mem op parameter values to output (Default to False) 

88 extra_topo_info : bool 

89 Adds edge numbering information (Default to False) 

90 conditional_node_params : bool 

91 Adds conditional node parameter values to output (Default to False) 

92  

93 """ 

94  

95 verbose: bool = False 

96 runtime_types: bool = False 

97 kernel_node_params: bool = False 

98 memcpy_node_params: bool = False 

99 memset_node_params: bool = False 

100 host_node_params: bool = False 

101 event_node_params: bool = False 

102 ext_semas_signal_node_params: bool = False 

103 ext_semas_wait_node_params: bool = False 

104 kernel_node_attributes: bool = False 

105 handles: bool = False 

106 mem_alloc_node_params: bool = False 

107 mem_free_node_params: bool = False 

108 batch_mem_op_node_params: bool = False 

109 extra_topo_info: bool = False 

110 conditional_node_params: bool = False 

111  

112 def _to_flags(self) -> int: 

113 """Convert options to CUDA driver API flags (internal use).""" 

114 flags = 0 2Jca

115 if self.verbose: 2. Jca

116 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_VERBOSE 2Jca

117 if self.runtime_types: 2Jca

118 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_RUNTIME_TYPES 1a

119 if self.kernel_node_params: 2Jca

120 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_KERNEL_NODE_PARAMS 1a

121 if self.memcpy_node_params: 2Jca

122 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEMCPY_NODE_PARAMS 1a

123 if self.memset_node_params: 2Jca

124 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEMSET_NODE_PARAMS 1a

125 if self.host_node_params: 2Jca

126 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_HOST_NODE_PARAMS 1a

127 if self.event_node_params: 2Jca

128 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EVENT_NODE_PARAMS 1a

129 if self.ext_semas_signal_node_params: 2Jca

130 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXT_SEMAS_SIGNAL_NODE_PARAMS 1a

131 if self.ext_semas_wait_node_params: 2Jca

132 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXT_SEMAS_WAIT_NODE_PARAMS 1a

133 if self.kernel_node_attributes: 2. Jca

134 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_KERNEL_NODE_ATTRIBUTES 1a

135 if self.handles: 2Jca

136 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_HANDLES 2Jca

137 if self.mem_alloc_node_params: 2Jca

138 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEM_ALLOC_NODE_PARAMS 1a

139 if self.mem_free_node_params: 2Jca

140 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEM_FREE_NODE_PARAMS 1a

141 if self.batch_mem_op_node_params: 2Jca

142 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_BATCH_MEM_OP_NODE_PARAMS 1a

143 if self.extra_topo_info: 2Jca

144 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXTRA_TOPO_INFO 1a

145 if self.conditional_node_params: 2Jca

146 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_CONDITIONAL_NODE_PARAMS 1a

147 return flags 2Jca

148  

149  

150@dataclass 

151class GraphCompleteOptions: 

152 """Options for graph instantiation. 

153  

154 Attributes 

155 ---------- 

156 auto_free_on_launch : bool, optional 

157 Automatically free memory allocated in a graph before relaunching. (Default to False) 

158 upload_stream : Stream, optional 

159 Stream to use to automatically upload the graph after completion. (Default to None) 

160 device_launch : bool, optional 

161 Configure the graph to be launchable from the device. This flag can only 

162 be used on platforms which support unified addressing. This flag cannot be 

163 used in conjunction with auto_free_on_launch. (Default to False) 

164 use_node_priority : bool, optional 

165 Run the graph using the per-node priority attributes rather than the 

166 priority of the stream it is launched into. (Default to False) 

167  

168 """ 

169  

170 auto_free_on_launch: bool = False 

171 upload_stream: Stream | None = None 

172 device_launch: bool = False 

173 use_node_priority: bool = False 

174  

175  

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

177 cdef GraphHandle h_graph 

178 cdef GraphExecHandle h_exec 

179 cdef cydriver.CUresult status 

180  

181 if isinstance(source, GraphBuilder): 2M [ H I J K / G $ x y T E NcF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

182 GB_check_open(<GraphBuilder>source) 1MHIJK/G$xyTEF#U%5VbcdefghijklmnopqzrstuvABCD=,:?-;6W07X1QOP8Y29Z3wS!*+@4'(

183 h_graph = (<GraphBuilder>source)._h_graph 1MHIJK/G$xyTEF#U%5VbcdefghijklmnopqzrstuvABCD=,:?-;6W07X1QOP8Y29Z3wS!*+@4'(

184 elif isinstance(source, GraphDefinition): 2[ NcAbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{bQbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbxbyb

185 GD_check_valid(<GraphDefinition>source) 2[ NcAbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{bQbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbxbyb

186 h_graph = (<GraphDefinition>source)._h_graph 2[ NcAbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{bQbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbxbyb

187 else: 

188 raise TypeError( 

189 f"expected GraphBuilder or GraphDefinition, got {type(source).__name__}") 

190  

191 cdef cydriver.CUDA_GRAPH_INSTANTIATE_PARAMS params = cydriver.CUDA_GRAPH_INSTANTIATE_PARAMS( 2M [ H I J K / G $ x y T E NcF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

192 flags=0, 

193 hUploadStream=<cydriver.CUstream>NULL, 2M [ H I J K / G $ x y T E NcF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

194 hErrNode_out=<cydriver.CUgraphNode>NULL, 2M [ H I J K / G $ x y T E NcF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

195 result_out=cydriver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_SUCCESS, 2M [ H I J K / G $ x y T E NcF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

196 ) 

197 if options: 2M [ H I J K / G $ x y T E NcF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

198 flags = 0 2Ncbbcbtbdbebubfbgbhbvbibjbwb!b#bQ O P @ 4

199 if options.auto_free_on_launch: 2Ncbbcbtbdbebubfbgbhbvbibjbwb!b#bQ O P @ 4

200 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_AUTO_FREE_ON_LAUNCH 2bbdbgbib!b#bQ O P @ 4

201 if options.upload_stream is not None: 2Ncbbcbtbdbebubfbgbhbvbibjbwb!b#bQ O P @ 4

202 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_UPLOAD 2Nctbubvbwb4

203 params.hUploadStream = as_cu(Stream_accept(options.upload_stream)._h_stream) 2Nctbubvbwb4

204 if options.device_launch: 2bbcbtbdbebubfbgbhbvbibjbwb!b#bQ O P @ 4

205 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_DEVICE_LAUNCH 2fb@ 4

206 if options.use_node_priority: 2bbcbtbdbebubfbgbhbvbibjbwb!b#bQ O P @ 4

207 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_USE_NODE_PRIORITY 2cbebhbjb!b#b4

208 params.flags = flags 2bbcbtbdbebubfbgbhbvbibjbwb!b#bQ O P @ 4

209  

210 # The exec is adopted only when result_out reports success, so the 

211 # diagnostics below run before the handle is checked. 

212 h_exec = create_graph_exec_handle(h_graph, &params) 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

213 status = get_last_error() 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

214 if params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_ERROR: 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + @ 4 ' (

215 # HANDLE_RETURN raises CUDAError with the CUresult name and message (e.g. CUDA_ERROR_INVALID_VALUE) 

216 # when status is not CUDA_SUCCESS. 

217 HANDLE_RETURN(status) 1@

218 raise RuntimeError( 

219 "CUDA graph instantiation failed, but cuGraphInstantiateWithParams " 

220 "returned CUDA_SUCCESS; no driver error details are available." 

221 ) 

222 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_INVALID_STRUCTURE: 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

223 raise RuntimeError("Instantiation failed due to invalid structure, such as cycles.") 

224 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_NODE_OPERATION_NOT_SUPPORTED: 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

225 raise RuntimeError( 

226 "Instantiation for device launch failed because the graph contained an unsupported operation." 

227 ) 

228 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_MULTIPLE_CTXS_NOT_SUPPORTED: 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

229 raise RuntimeError("Instantiation for device launch failed due to the nodes belonging to different contexts.") 

230 elif ( 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

231 cy_binding_version() >= (12, 8, 0) 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

232 and params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_CONDITIONAL_HANDLE_UNUSED 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

233 ): 

234 raise RuntimeError("One or more conditional handles are not associated with conditional builders.") 

235 elif params.result_out != driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_SUCCESS: 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

236 raise RuntimeError(f"Graph instantiation failed with unexpected error code: {params.result_out}") 

237  

238 if as_cu(h_exec) == NULL: 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

239 HANDLE_RETURN(status) 

240 return Graph._init(h_exec) 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

241  

242  

243# Distinguishes the three kinds of GraphBuilder, which differ in how they 

244# begin/end stream capture and whether they own the resulting CUgraph. 

245# Each kind progresses through _CaptureState as follows: 

246# 

247# PRIMARY: NOT_STARTED -> CAPTURING -> ENDED 

248# FORKED: CAPTURING (never transitions; joined and closed) 

249# CONDITIONAL_BODY: NOT_STARTED -> CAPTURING -> ENDED 

250# 

251cdef enum _BuilderKind: 

252 # PRIMARY: The top-level builder created by Device or Stream. Owns the 

253 # captured CUgraph via an owning GraphHandle. Progresses through all three 

254 # capture states; responsible for ending capture if destroyed early. 

255 PRIMARY = 0 

256 # FORKED: Created by split(). Captures on a private stream forked from the 

257 # primary. Starts in CAPTURING state and never transitions; the user joins 

258 # it back to the primary via join(), which closes the builder. Must NOT 

259 # call cuStreamEndCapture (the driver requires all forked streams to be 

260 # joined first). 

261 FORKED = 1 

262 # CONDITIONAL_BODY: Created by if_then/if_else/switch/while_loop. Captures 

263 # into a non-owned body graph via cuStreamBeginCaptureToGraph. The body 

264 # graph's lifetime is tied to a parent graph. Progresses through all three 

265 # capture states like PRIMARY. 

266 CONDITIONAL_BODY = 2 

267  

268  

269# Tracks the capture lifecycle of a GraphBuilder. 

270cdef enum _CaptureState: 

271 CAPTURE_NOT_STARTED = 0 

272 CAPTURING = 1 

273 CAPTURE_ENDED = 2 # Finished, valid handle 

274 CLOSED = 3 # No valid handle 

275  

276  

277cdef class GraphBuilder: 

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

279  

280 A graph groups a set of CUDA kernels and other CUDA operations together and executes 

281 them with a specified dependency tree. It speeds up the workflow by combining the 

282 driver activities associated with CUDA kernel launches and CUDA API calls. 

283  

284 Directly creating a :obj:`~graph.GraphBuilder` is not supported due 

285 to ambiguity. New graph builders should instead be created through a 

286 :obj:`~_device.Device`, or a :obj:`~_stream.stream` object. 

287  

288 .. note:: 

289  

290 Operations recorded during capture reference your memory but do not 

291 take ownership of it. As with ordinary stream work, you must keep the 

292 operands alive for as long as the completed graph may execute -- for 

293 example, the :obj:`~_memory.Buffer` objects passed to :func:`~launch` 

294 or :meth:`~_memory.Buffer.copy_to`. Host callbacks added with 

295 :meth:`callback` are the exception: the callable (and any copied 

296 ``user_data``) are retained for the graph's lifetime. This differs from 

297 building a graph explicitly with :class:`~graph.GraphDefinition`, which 

298 retains the operands it is given. 

299  

300 """ 

301  

302 def __init__(self): 

303 raise NotImplementedError( 

304 "directly creating a GraphBuilder object can be ambiguous. Please either " 

305 "call Device.create_graph_builder() or stream.create_graph_builder()" 

306 ) 

307  

308 def __dealloc__(self): 

309 GB_end_capture_if_needed(self, False) 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N rb= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

310  

311 @staticmethod 

312 def _init(Stream stream): 

313 cdef GraphBuilder self = GraphBuilder.__new__(GraphBuilder) 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

314 # _h_graph set by begin_building 

315 self._h_stream = stream._h_stream 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

316 self._kind = PRIMARY 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

317 self._state = CAPTURE_NOT_STARTED 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

318 self._stream = stream 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

319 return self 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

320  

321 def close(self): 

322 """Destroy the graph builder.""" 

323 GB_end_capture_if_needed(self, True) 2[ $ ) ^ R ] E F % 5 b c d e f g h i j k l m n o p q r s t u v a { ab| } Kc

324 self._h_graph.reset() 2[ $ ) ^ R ] E F % 5 b c d e f g h i j k l m n o p q r s t u v a { ab| } Kc

325 self._h_stream.reset() 2[ $ ) ^ R ] E F % 5 b c d e f g h i j k l m n o p q r s t u v a { ab| } Kc

326 retry_deferred_cleanup() 2[ $ ) ^ R ] E F % 5 b c d e f g h i j k l m n o p q r s t u v a { ab| } Kc

327 self._state = CLOSED 2[ $ ) ^ R ] E F % 5 b c d e f g h i j k l m n o p q r s t u v a { ab| } Kc

328 self._stream = None 2[ $ ) ^ R ] E F % 5 b c d e f g h i j k l m n o p q r s t u v a { ab| } Kc

329  

330 @property 

331 def is_closed(self) -> bool: 

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

333 return self._state == CLOSED 2[ Kc

334  

335 @property 

336 def stream(self) -> Stream: 

337 """Returns the stream associated with the graph builder.""" 

338 GB_check_open(self) 2G $ ) x y ^ R ` T ] E 9bF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { | } ' Kc(

339 return self._stream 2G $ ) x y ^ R ` T ] E 9bF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { | } ' (

340  

341 @property 

342 def is_join_required(self) -> bool: 

343 """Returns True if this graph builder must be joined before building is ended.""" 

344 return self._kind == FORKED 1)REFbcdefghijklmnopqrstuva

345  

346 @property 

347 def graph_definition(self) -> GraphDefinition: 

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

349  

350 .. versionadded:: 1.1.0 

351  

352 The returned :class:`~graph.GraphDefinition` is a view of the same 

353 graph this builder is producing: nodes added through it appear in 

354 subsequent :meth:`complete` and :meth:`debug_dot_print` calls, and 

355 the view stays valid even after the builder is closed. 

356  

357 This lets you mix the capture and explicit APIs on a single graph, 

358 for example to inspect what was captured, augment it with extra 

359 nodes, or build a conditional body entirely with the explicit API. 

360  

361 Availability: 

362  

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

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

365 :meth:`end_building`. 

366  

367 - **Conditional-body builders** (returned by :meth:`if_then`, 

368 :meth:`if_else`, :meth:`while_loop`, :meth:`switch`): both before 

369 :meth:`begin_building` and after :meth:`end_building`. The body 

370 graph already exists when the conditional is created, so you may 

371 populate it through this view without ever calling 

372 :meth:`begin_building` on the body builder. 

373  

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

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

376 primary instead. 

377  

378 Returns 

379 ------- 

380 GraphDefinition 

381 A view of the graph being built. 

382  

383 Raises 

384 ------ 

385 RuntimeError 

386 If the builder is closed, forked, currently building, or (for 

387 primary builders) has not started building yet. A 

388 :class:`~graph.GraphDefinition` obtained before :meth:`close` 

389 keeps working; only fresh access through this property is 

390 rejected once the builder is closed. 

391 """ 

392 GB_check_open(self) 2x L y ^ LcnbR ` T ] V N

393 if self._kind == FORKED: 2x L y LcnbR ` T ] V N

394 raise RuntimeError( 1R

395 "graph_definition is unavailable on forked graph builders; " 

396 "access it through the primary builder instead." 

397 ) 

398 elif self._state == CAPTURING: 2x L y Lcnb` T ] V N

399 raise RuntimeError( 2L nb

400 "graph_definition is unavailable while capture is in " 

401 "progress; call end_building() first." 

402 ) 

403 elif self._kind == PRIMARY: 2x y Lc` T ] V N

404 if self._state == CAPTURE_NOT_STARTED: 2Lc` T ] V N

405 raise RuntimeError( 2Lc

406 "graph_definition is unavailable before begin_building() on " 

407 "a primary builder; no graph has been created yet." 

408 ) 

409 return GraphDefinition._from_handle(self._h_graph) 1xy`T]VN

410  

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

412 """Begins the building process. 

413  

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

415  

416 - `global` : Prohibit potentially unsafe operations across all streams in the process. 

417 - `thread_local` : Prohibit potentially unsafe operations in streams created by the current thread. 

418 - `relaxed` : The local thread is not prohibited from potentially unsafe operations. 

419  

420 Parameters 

421 ---------- 

422 mode : str, optional 

423 Build mode to control the interaction with other API calls that are porentially unsafe. 

424 Default set to use relaxed. 

425  

426 """ 

427 GB_check_open(self) 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

428 if self._state != CAPTURE_NOT_STARTED: 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

429 if self._state == CAPTURING: 2qb#

430 raise RuntimeError("Graph builder is already building.") 2qb

431 else: 

432 raise RuntimeError("Cannot resume building after building has ended.") 1#

433 cdef cydriver.CUstreamCaptureMode c_mode 

434 if mode == "global": 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

435 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_GLOBAL 2= ? 6 7 Q 8 9 kb

436 elif mode == "thread_local": 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N , : - ; W 0 X 1 O P Y 2 Z 3 w S ! * + kb@ 4 a { ab| } ' (

437 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_THREAD_LOCAL 2: ; 0 1 P 2 3 kb

438 elif mode == "relaxed": 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N , - W X O Y Z w S ! * + kb@ 4 a { ab| } ' (

439 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_RELAXED 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N , - W X O Y Z w S ! * + kb@ 4 a { ab| } ' (

440 else: 

441 raise ValueError(f"Unsupported build mode: {mode}") 2kb

442  

443 cdef cydriver.CUstream c_stream = as_cu(self._h_stream) 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

444 cdef cydriver.CUgraph c_graph 

445 cdef cydriver.CUstreamCaptureStatus c_status 

446 if self._kind == CONDITIONAL_BODY: 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

447 c_graph = as_cu(self._h_graph) 1xLbcdefghijklmnopqzrstuvABCDwa

448 with nogil: 1xLbcdefghijklmnopqzrstuvABCDwa

449 HANDLE_RETURN(cydriver.cuStreamBeginCaptureToGraph( 1xLbcdefghijklmnopqzrstuvABCDwa

450 c_stream, c_graph, NULL, NULL, 0, c_mode)) 

451 self._state = CAPTURING 1xLbcdefghijklmnopqzrstuvABCDwa

452 else: 

453 with nogil: 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

454 HANDLE_RETURN(cydriver.cuStreamBeginCapture(c_stream, c_mode)) 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

455 # Capture is active now; set CAPTURING before the calls below so a 

456 # failure in _get_capture_info/create_graph_handle still lets 

457 # cleanup end the capture rather than leaving the stream poisoned. 

458 self._state = CAPTURING 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

459 with nogil: 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

460 # The driver rejects a NULL captureStatus_out, so pass a 

461 # stack-local even though we only want the graph handle. 

462 _get_capture_info(c_stream, &c_status, &c_graph) 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

463 self._h_graph = create_graph_handle(c_graph) 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

464 return self 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

465  

466 @property 

467 def is_building(self) -> bool: 

468 """Returns True if the graph builder is currently building.""" 

469 GB_check_open(self) 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

470 cdef cydriver.CUstream c_stream = as_cu(self._h_stream) 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

471 cdef cydriver.CUstreamCaptureStatus status 

472 with nogil: 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

473 _get_capture_info(c_stream, &status, NULL) 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

474 if status == cydriver.CU_STREAM_CAPTURE_STATUS_NONE: 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

475 return False 2sb

476 elif status == cydriver.CU_STREAM_CAPTURE_STATUS_ACTIVE: 

477 return True 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

478 elif status == cydriver.CU_STREAM_CAPTURE_STATUS_INVALIDATED: 

479 raise RuntimeError( 

480 "Build process encountered an error and has been invalidated. Build process must now be ended." 

481 ) 

482 else: 

483 raise NotImplementedError(f"Unsupported capture status type received: {status}") 

484  

485 def end_building(self) -> GraphBuilder: 

486 """Ends the building process.""" 

487 GB_check_open(self) 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

488 if not self.is_building: 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

489 raise RuntimeError("Graph builder is not building.") 

490 cdef cydriver.CUstream c_stream = as_cu(self._h_stream) 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

491 cdef cydriver.CUgraph c_graph 

492 with nogil: 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

493 HANDLE_RETURN(cydriver.cuStreamEndCapture(c_stream, &c_graph)) 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

494  

495 # TODO: Resolving https://github.com/NVIDIA/cuda-python/issues/617 would allow us to 

496 # resume the build process after the first call to end_building() 

497 self._state = CAPTURE_ENDED 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

498 return self 2M qb_ H I J K / G $ x L y ^ nbR ` T ] zbE sbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

499  

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

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

502  

503 Parameters 

504 ---------- 

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

506 Customizable dataclass for the graph builder completion options. 

507  

508 Returns 

509 ------- 

510 graph : :obj:`~graph.Graph` 

511 The newly built graph. 

512  

513 """ 

514 GB_check_open(self) 1MHIJK/G$)xyTEF#U%5VbcdefghijklmnopqzrstuvABCD=,:?-;6W07X1QOP8Y29Z3wS!*+@4'(

515 if self._state != CAPTURE_ENDED: 1MHIJK/G$xyTEF#U%5VbcdefghijklmnopqzrstuvABCD=,:?-;6W07X1QOP8Y29Z3wS!*+@4'(

516 raise RuntimeError("Graph has not finished building.") 1/

517  

518 return _instantiate_graph(self, options) 1MHIJK/G$xyTEF#U%5VbcdefghijklmnopqzrstuvABCD=,:?-;6W07X1QOP8Y29Z3wS!*+@4'(

519  

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

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

522  

523 Parameters 

524 ---------- 

525 path : str 

526 File path to use for writting debug DOT output 

527 options : :obj:`~graph.GraphDebugPrintOptions`, optional 

528 Customizable dataclass for the debug print options. 

529  

530 """ 

531 GB_check_open(self) 1a

532 if self._state != CAPTURE_ENDED: 1a

533 raise RuntimeError("Graph has not finished building.") 

534 cdef unsigned int c_flags = options._to_flags() if options else 0 1a

535 cdef cydriver.CUgraph c_graph = as_cu(self._h_graph) 1a

536 cdef bytes b_path = path.encode('utf-8') 1a

537 cdef const char* c_path = b_path 1a

538 with nogil: 1a

539 HANDLE_RETURN(cydriver.cuGraphDebugDotPrint(c_graph, c_path, c_flags)) 1a

540  

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

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

543  

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

545 The original builder is reused for the split and is returned first in the tuple. 

546  

547 Parameters 

548 ---------- 

549 count : int 

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

551  

552 Returns 

553 ------- 

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

555 A tuple of split graph builders. The first graph builder in the tuple 

556 is always the original graph builder. 

557  

558 """ 

559 if count < 2: 2) R E F Mcb c d e f g h i j k l m n o p q r s t u v a

560 raise ValueError(f"Invalid split count: expecting >= 2, got {count}") 1E

561 GB_check_open(self) 2) R E F Mcb c d e f g h i j k l m n o p q r s t u v a

562 if self._state != CAPTURING: 2) R E F Mcb c d e f g h i j k l m n o p q r s t u v a

563 raise RuntimeError("Graph builder must be building before it can be split.") 2Mc

564  

565 event = self._stream.record() 1)REFbcdefghijklmnopqrstuva

566 result = [self] 1)REFbcdefghijklmnopqrstuva

567 for i in range(count - 1): 1)REFbcdefghijklmnopqrstuva

568 stream = self._stream.device.create_stream() 1)REFbcdefghijklmnopqrstuva

569 stream.wait(event) 1)REFbcdefghijklmnopqrstuva

570 result.append(GB_init_forked(stream, self._h_graph)) 1)REFbcdefghijklmnopqrstuva

571 event.close() 1)REFbcdefghijklmnopqrstuva

572 return tuple(result) 1)REFbcdefghijklmnopqrstuva

573  

574 @staticmethod 

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

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

577  

578 The returned builder inherits work dependencies from the provided builders. 

579  

580 Parameters 

581 ---------- 

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

583 The graph builders to join. 

584  

585 Returns 

586 ------- 

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

588 The newly joined graph builder. 

589  

590 """ 

591 if any(not isinstance(builder, GraphBuilder) for builder in graph_builders): 1[)REFbcdefghijklmnopqrstuva

592 raise TypeError("All arguments must be GraphBuilder instances") 

593 if len(graph_builders) < 2: 1[)REFbcdefghijklmnopqrstuva

594 raise ValueError("Must join with at least two graph builders") 1E

595 for builder in graph_builders: 1[)REFbcdefghijklmnopqrstuva

596 GB_check_open(builder) 1[)REFbcdefghijklmnopqrstuva

597  

598 # Discover the root builder others should join 

599 root_idx = 0 1)REFbcdefghijklmnopqrstuva

600 for i, builder in enumerate(graph_builders): 1)REFbcdefghijklmnopqrstuva

601 if not builder.is_join_required: 1)REFbcdefghijklmnopqrstuva

602 root_idx = i 1)REFbcdefghijklmnopqrstuva

603 break 1)REFbcdefghijklmnopqrstuva

604  

605 # Join all onto the root builder 

606 root_bdr = graph_builders[root_idx] 1)REFbcdefghijklmnopqrstuva

607 for idx, builder in enumerate(graph_builders): 1)REFbcdefghijklmnopqrstuva

608 if idx == root_idx: 1)REFbcdefghijklmnopqrstuva

609 continue 1)REFbcdefghijklmnopqrstuva

610 root_bdr.stream.wait(builder.stream) 1)REFbcdefghijklmnopqrstuva

611 builder.close() 1)REFbcdefghijklmnopqrstuva

612  

613 return root_bdr 1)REFbcdefghijklmnopqrstuva

614  

615 def __cuda_stream__(self) -> tuple[int, int]: 

616 """Return an instance of a __cuda_stream__ protocol.""" 

617 GB_check_open(self) 

618 return self.stream.__cuda_stream__() 

619  

620 def _get_conditional_context(self) -> driver.CUcontext: 

621 return self._stream.context.handle 1xLybcdefghijklmnopqzrstuvABCDwa

622  

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

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

625  

626 The returned :class:`GraphCondition` object is passed to conditional-node 

627 builder methods (:meth:`if_then`, :meth:`if_else`, :meth:`while_loop`, 

628 :meth:`switch`). Its value is controlled at runtime by device code via 

629 ``cudaGraphSetConditional``. 

630  

631 Parameters 

632 ---------- 

633 default_value : int, optional 

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

635 default is assigned. 

636  

637 Returns 

638 ------- 

639 GraphCondition 

640 A condition variable for controlling conditional execution. 

641 """ 

642 GB_check_open(self) 1xLybcdefghijklmnopqzrstuvABCDwa

643 if cy_driver_version() < (12, 3, 0): 1xLybcdefghijklmnopqzrstuvABCDwa

644 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional handles") 

645 if cy_binding_version() < (12, 3, 0): 1xLybcdefghijklmnopqzrstuvABCDwa

646 raise RuntimeError(f"Binding version {'.'.join(map(str, cy_binding_version()))} does not support conditional handles") 

647 if default_value is not None: 1xLybcdefghijklmnopqzrstuvABCDwa

648 flags = driver.CU_GRAPH_COND_ASSIGN_DEFAULT 1xLyABCDw

649 else: 

650 default_value = 0 1bcdefghijklmnopqzrstuva

651 flags = 0 1bcdefghijklmnopqzrstuva

652  

653 status, _, graph, *_, _ = handle_return(driver.cuStreamGetCaptureInfo(self._stream.handle)) 1xLybcdefghijklmnopqzrstuvABCDwa

654 if status != driver.CUstreamCaptureStatus.CU_STREAM_CAPTURE_STATUS_ACTIVE: 1xLybcdefghijklmnopqzrstuvABCDwa

655 raise RuntimeError("Cannot create a condition when graph is not being built") 

656  

657 raw_handle = handle_return( 1xLybcdefghijklmnopqzrstuvABCDwa

658 driver.cuGraphConditionalHandleCreate(graph, self._get_conditional_context(), default_value, flags) 1xLybcdefghijklmnopqzrstuvABCDwa

659 ) 

660 return GraphCondition._from_handle(<cydriver.CUgraphConditionalHandle><intptr_t>int(raw_handle)) 1xLybcdefghijklmnopqzrstuvABCDwa

661  

662 def if_then(self, condition: GraphCondition) -> GraphBuilder: 

663 """Adds an if condition branch and returns a new graph builder for it. 

664  

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

666 condition evaluates to true at runtime. 

667  

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

669  

670 Parameters 

671 ---------- 

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

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

674 whether the branch executes. 

675  

676 Returns 

677 ------- 

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

679 The newly created conditional graph builder. 

680  

681 """ 

682 GB_check_open(self) 1xLybcdefghizra

683 if cy_driver_version() < (12, 3, 0): 1xLybcdefghizra

684 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional if") 

685 if cy_binding_version() < (12, 3, 0): 1xLybcdefghizra

686 raise RuntimeError(f"Binding version {'.'.join(map(str, cy_binding_version()))} does not support conditional if") 

687 if not isinstance(condition, GraphCondition): 1xLybcdefghizra

688 raise TypeError( 

689 f"condition must be a GraphCondition object (from " 

690 f"GraphBuilder.create_condition()), got {type(condition).__name__}") 

691 node_params = driver.CUgraphNodeParams() 1xLybcdefghizra

692 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 1xLybcdefghizra

693 node_params.conditional.handle = condition.handle 1xLybcdefghizra

694 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_IF 1xLybcdefghizra

695 node_params.conditional.size = 1 1xLybcdefghizra

696 node_params.conditional.ctx = self._get_conditional_context() 1xLybcdefghizra

697 return GB_cond_with_params(self, node_params)[0] 1xLybcdefghizra

698  

699 def if_else(self, condition: GraphCondition) -> tuple[GraphBuilder, GraphBuilder]: 

700 """Adds an if-else condition branch and returns new graph builders for both branches. 

701  

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

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

704  

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

706  

707 Parameters 

708 ---------- 

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

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

711 which branch executes. 

712  

713 Returns 

714 ------- 

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

716 A tuple of two new graph builders, one for the if branch and one for the else branch. 

717  

718 """ 

719 GB_check_open(self) 1jklmnopq

720 if cy_driver_version() < (12, 8, 0): 1jklmnopq

721 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional if-else") 

722 if cy_binding_version() < (12, 8, 0): 1jklmnopq

723 raise RuntimeError(f"Binding version {'.'.join(map(str, cy_binding_version()))} does not support conditional if-else") 

724 if not isinstance(condition, GraphCondition): 1jklmnopq

725 raise TypeError( 

726 f"condition must be a GraphCondition object (from " 

727 f"GraphBuilder.create_condition()), got {type(condition).__name__}") 

728 node_params = driver.CUgraphNodeParams() 1jklmnopq

729 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 1jklmnopq

730 node_params.conditional.handle = condition.handle 1jklmnopq

731 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_IF 1jklmnopq

732 node_params.conditional.size = 2 1jklmnopq

733 node_params.conditional.ctx = self._get_conditional_context() 1jklmnopq

734 return GB_cond_with_params(self, node_params) 1jklmnopq

735  

736 def switch(self, condition: GraphCondition, count: int) -> tuple[GraphBuilder, ...]: 

737 """Adds a switch condition branch and returns new graph builders for all cases. 

738  

739 The resulting switch graph will execute the branch whose case index 

740 matches the value of the condition at runtime. If no match is found, no 

741 branch will be executed. 

742  

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

744  

745 Parameters 

746 ---------- 

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

748 The condition variable from :meth:`create_condition` selecting 

749 which case executes. 

750 count : int 

751 The number of cases to add to the switch conditional. 

752  

753 Returns 

754 ------- 

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

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

757  

758 """ 

759 GB_check_open(self) 1stuvw

760 if cy_driver_version() < (12, 8, 0): 1stuvw

761 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional switch") 

762 if cy_binding_version() < (12, 8, 0): 1stuvw

763 raise RuntimeError(f"Binding version {'.'.join(map(str, cy_binding_version()))} does not support conditional switch") 

764 if not isinstance(condition, GraphCondition): 1stuvw

765 raise TypeError( 

766 f"condition must be a GraphCondition object (from " 

767 f"GraphBuilder.create_condition()), got {type(condition).__name__}") 

768 node_params = driver.CUgraphNodeParams() 1stuvw

769 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 1stuvw

770 node_params.conditional.handle = condition.handle 1stuvw

771 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_SWITCH 1stuvw

772 node_params.conditional.size = count 1stuvw

773 node_params.conditional.ctx = self._get_conditional_context() 1stuvw

774 return GB_cond_with_params(self, node_params) 1stuvw

775  

776 def while_loop(self, condition: GraphCondition) -> GraphBuilder: 

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

778  

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

780 until the condition evaluates to false. 

781  

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

783  

784 Parameters 

785 ---------- 

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

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

788 loop continuation. 

789  

790 Returns 

791 ------- 

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

793 The newly created while loop graph builder. 

794  

795 """ 

796 GB_check_open(self) 1ABCD

797 if cy_driver_version() < (12, 3, 0): 1ABCD

798 raise RuntimeError(f"Driver version {'.'.join(map(str, cy_driver_version()))} does not support conditional while loop") 

799 if cy_binding_version() < (12, 3, 0): 1ABCD

800 raise RuntimeError(f"Binding version {'.'.join(map(str, cy_binding_version()))} does not support conditional while loop") 

801 if not isinstance(condition, GraphCondition): 1ABCD

802 raise TypeError( 

803 f"condition must be a GraphCondition object (from " 

804 f"GraphBuilder.create_condition()), got {type(condition).__name__}") 

805 node_params = driver.CUgraphNodeParams() 1ABCD

806 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 1ABCD

807 node_params.conditional.handle = condition.handle 1ABCD

808 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_WHILE 1ABCD

809 node_params.conditional.size = 1 1ABCD

810 node_params.conditional.ctx = self._get_conditional_context() 1ABCD

811 return GB_cond_with_params(self, node_params)[0] 1ABCD

812  

813 def embed(self, GraphBuilder child): 

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

815  

816 Parameters 

817 ---------- 

818 child : :obj:`~graph.GraphBuilder` 

819 The child graph builder. Must have finished building. 

820 """ 

821 GB_check_open(self) 1GN

822 GB_check_open(child) 1GN

823 if child._state != CAPTURE_ENDED: 1GN

824 raise ValueError("Child graph has not finished building.") 

825  

826 if not self.is_building: 1GN

827 raise ValueError("Parent graph is not being built.") 

828  

829 stream_handle = self._stream.handle 1GN

830 _, _, graph_out, *deps_info_out, num_dependencies_out = handle_return( 1GN

831 driver.cuStreamGetCaptureInfo(stream_handle) 1GN

832 ) 

833  

834 # See https://github.com/NVIDIA/cuda-python/pull/879#issuecomment-3211054159 

835 # for rationale 

836 dependencies_out = deps_info_out[0] 1GN

837 new_node = handle_return( 1GN

838 driver.cuGraphAddChildGraphNode( 1GN

839 graph_out, dependencies_out, 

840 num_dependencies_out, as_py(child._h_graph) 1GN

841 ) 

842 ) 

843 cdef cydriver.CUgraphNode c_new_node = ( 

844 <cydriver.CUgraphNode><intptr_t>int(new_node) 1GN

845 ) 

846 cdef cydriver.CUgraph embedded_graph = NULL 1GN

847 cdef cydriver.CUresult rollback_status 

848 cdef GraphHandle h_embedded 

849 try: 1GN

850 with nogil: 1GN

851 HANDLE_RETURN(cydriver.cuGraphChildGraphNodeGetGraph( 1GN

852 c_new_node, &embedded_graph)) 

853 h_embedded = create_child_graph_handle( 1GN

854 embedded_graph, self._h_graph, c_new_node) 

855 HANDLE_RETURN(graph_clone_attachments( 1GN

856 h_embedded, child._h_graph)) 

857 except: 

858 with nogil: 

859 rollback_status = cydriver.cuGraphDestroyNode(c_new_node) 

860 if rollback_status == cydriver.CUDA_SUCCESS: 

861 invalidate_child_graph_state( 

862 self._h_graph, c_new_node) 

863 raise 

864  

865 deps_info_update = [[new_node]] + [None] * (len(deps_info_out) - 1) 1GN

866 handle_return( 1GN

867 driver.cuStreamUpdateCaptureDependencies( 1GN

868 stream_handle, 1GN

869 *deps_info_update, # dependencies, edgeData 

870 1, 

871 driver.CUstreamUpdateCaptureDependencies_flags.CU_STREAM_SET_CAPTURE_DEPENDENCIES, 1GN

872 ) 

873 ) 

874  

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

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

877  

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

879 in execution. Two modes are supported: 

880  

881 - **Python callable**: Pass any callable. The GIL is acquired 

882 automatically. The callable must take no arguments; use closures 

883 or ``functools.partial`` to bind state. 

884 - **ctypes function pointer**: The function receives a single 

885 ``void*`` argument (the ``user_data``), and the caller must keep 

886 the ctypes wrapper alive for the lifetime of the graph. Its 

887 declared prototype must match the driver's ``CUhostFn`` 

888 (``void (*)(void*)``): ``ctypes.CFUNCTYPE(None, ctypes.c_void_p)``, 

889 or ``ctypes.WINFUNCTYPE(None, ctypes.c_void_p)`` on Windows. 

890  

891 .. warning:: 

892  

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

894 deadlock or corrupt driver state. 

895  

896 Use caution when a Python callback retains an object that owns a 

897 graph. Any reference cycle involving the callback and a graph that 

898 retains it cannot be broken by Python's cyclic garbage collector. 

899 Use a weak reference to break such cycles. 

900  

901 Parameters 

902 ---------- 

903 fn : callable or ctypes function pointer 

904 The callback function. 

905 user_data : int or bytes-like, optional 

906 Only for ctypes function pointers. If ``int``, passed as a raw 

907 pointer (caller manages lifetime). If bytes-like, the data is 

908 copied and its lifetime is tied to the graph. 

909  

910 Raises 

911 ------ 

912 TypeError 

913 If ``fn`` is a ctypes function pointer whose declared prototype 

914 does not match ``CUhostFn``. 

915 ValueError 

916 If ``user_data`` is given for a Python callable. 

917 """ 

918 GB_callback(self, fn, user_data, False) 1_HIJKN

919  

920  

921cdef inline void GB_callback( 

922 GraphBuilder gb, object fn, object user_data, 

923 bint fail_tail_discovery_for_testing) except *: 

924 GB_check_open(gb) 1M_HIJKN

925 cdef Stream stream = gb._stream 1M_HIJKN

926 cdef cydriver.CUstream c_stream = as_cu(stream._h_stream) 1M_HIJKN

927 cdef cydriver.CUstreamCaptureStatus capture_status 

928  

929 with nogil: 1M_HIJKN

930 _get_capture_info(c_stream, &capture_status, NULL) 1M_HIJKN

931  

932 if capture_status != cydriver.CU_STREAM_CAPTURE_STATUS_ACTIVE: 1M_HIJKN

933 raise RuntimeError("Cannot add callback when graph is not being built") 

934  

935 cdef cydriver.CUhostFn c_fn 

936 cdef void* c_user_data = NULL 1M_HIJKN

937 cdef OpaqueHandle fn_owner, data_owner 

938 cdef PreparedAttachment prepared 

939 _resolve_host_callback( 1M_HIJKN

940 fn, user_data, &c_fn, &c_user_data, &fn_owner, &data_owner) 

941 HANDLE_RETURN(graph_prepare_attachment( 1MHIJKN

942 gb._h_graph, fn_owner, data_owner, &prepared)) 

943  

944 with nogil: 1MHIJKN

945 HANDLE_RETURN(cydriver.cuLaunchHostFunc(c_stream, c_fn, c_user_data)) 1MHIJKN

946  

947 # Capturing the host function added a node to the graph; it is now the 

948 # stream's sole capture dependency. Attach the callback's owners to it. 

949 cdef cydriver.CUgraphNode host_node 

950 cdef cydriver.CUresult commit_status 

951 try: 1MHIJKN

952 if fail_tail_discovery_for_testing: 1MHIJKN

953 raise RuntimeError("forced capture tail discovery failure") 1M

954 host_node = _capture_tail_node(c_stream) 1HIJKN

955 except BaseException as orig_exc: 1M

956 # CUDA added the callback, but its node cannot be identified. 

957 # Retain its owners anonymously to prevent dangling pointers. 

958 commit_status = graph_commit_attachment(prepared, NULL) 1M

959 try: 1M

960 HANDLE_RETURN(commit_status) 1M

961 except Exception as commit_exc: 

962 raise commit_exc from orig_exc 

963 raise 1M

964 HANDLE_RETURN(graph_commit_attachment(prepared, host_node)) 1HIJKN

965  

966  

967def _capture_callback_with_tail_failure_for_testing( 

968 GraphBuilder gb, fn, *, user_data=None): 

969 """Exercise anonymous attachment retention after node discovery fails.""" 

970 GB_callback(gb, fn, user_data, True) 1M

971  

972  

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

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

975  

976 A CLOSED builder has reset its stream and graph handles, so any method 

977 that dereferences them would read a null handle (or, for the cached 

978 Stream, a None typed as cdef Stream). Guarding here yields a clear error 

979 instead. 

980 """ 

981 if gb._state == CLOSED: 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

982 raise RuntimeError("GraphBuilder has been closed") 2[ ) ^ 5 Kc

983 return 0 2M qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

984  

985  

986cdef inline int GB_end_capture_if_needed(GraphBuilder gb, bint check_status) except -1 nogil: 

987 """End an in-progress capture if this builder owns it. 

988  

989 Only a CAPTURING PRIMARY or CONDITIONAL_BODY builder owns the live 

990 capture. A FORKED builder must not call cuStreamEndCapture: the driver 

991 requires forked streams to be joined first. 

992  

993 check_status=True checks the driver return (close()); False ignores it 

994 (__dealloc__). 

995 """ 

996 cdef cydriver.CUgraph c_graph 

997 cdef cydriver.CUresult err 

998 cdef cydriver.CUstream c_stream 

999 if gb._h_stream and gb._state == CAPTURING and gb._kind != FORKED: 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N rb= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

1000 c_stream = as_cu(gb._h_stream) 2) 9b

1001 with nogil: 2) 9b

1002 err = cydriver.cuStreamEndCapture(c_stream, &c_graph) 2) 9b

1003 if check_status: 2) 9b

1004 HANDLE_RETURN(err) 

1005 return 0 2M [ qb_ H I J K / G $ ) x L y ^ LcnbR ` T ] zbE 9bsbF # McU % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N rb= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' Kc(

1006  

1007  

1008cdef inline GraphBuilder GB_init_forked(Stream stream, GraphHandle h_primary_graph): 

1009 cdef GraphBuilder gb = GraphBuilder.__new__(GraphBuilder) 1)REFbcdefghijklmnopqrstuva

1010 # A FORKED builder captures into the primary's CUgraph. It holds the 

1011 # primary's GraphHandle so conditional bodies share its graph hierarchy. 

1012 gb._h_graph = h_primary_graph 1)REFbcdefghijklmnopqrstuva

1013 gb._h_stream = stream._h_stream 1)REFbcdefghijklmnopqrstuva

1014 gb._kind = FORKED 1)REFbcdefghijklmnopqrstuva

1015 gb._state = CAPTURING 1)REFbcdefghijklmnopqrstuva

1016 gb._stream = stream 1)REFbcdefghijklmnopqrstuva

1017 return gb 1)REFbcdefghijklmnopqrstuva

1018  

1019  

1020cdef inline GraphBuilder GB_init_conditional( 

1021 Stream stream, cydriver.CUgraph cond_graph, 

1022 GraphBuilder parent, cydriver.CUgraphNode owner_node): 

1023 cdef GraphBuilder gb = GraphBuilder.__new__(GraphBuilder) 1xLybcdefghijklmnopqzrstuvABCDwa

1024 gb._h_graph = create_child_graph_handle( 1xLybcdefghijklmnopqzrstuvABCDwa

1025 cond_graph, parent._h_graph, owner_node) 

1026 gb._h_stream = stream._h_stream 1xLybcdefghijklmnopqzrstuvABCDwa

1027 gb._kind = CONDITIONAL_BODY 1xLybcdefghijklmnopqzrstuvABCDwa

1028 gb._state = CAPTURE_NOT_STARTED 1xLybcdefghijklmnopqzrstuvABCDwa

1029 gb._stream = stream 1xLybcdefghijklmnopqzrstuvABCDwa

1030 return gb 1xLybcdefghijklmnopqzrstuvABCDwa

1031  

1032  

1033cdef inline int _get_capture_info( 

1034 cydriver.CUstream stream, 

1035 cydriver.CUstreamCaptureStatus* status, 

1036 cydriver.CUgraph* graph) except?-1 nogil: 

1037 """Thin wrapper around ``cuStreamGetCaptureInfo`` that papers over the 

1038 CUDA 12 vs 13 signature change. 

1039  

1040 ``status`` must be non-NULL: the driver rejects ``captureStatus_out=NULL`` 

1041 with ``CUDA_ERROR_INVALID_VALUE``. ``graph`` may be NULL when the caller 

1042 does not need the graph handle. 

1043 """ 

1044 IF CUDA_CORE_BUILD_MAJOR >= 13: 

1045 return HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 2M qb_ H I J K / G $ ) x L y ^ nbR ` T ] zbE 9bsbF # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D N = , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 w S ! * + kb@ 4 a { ab| } ' (

1046 stream, status, NULL, graph, NULL, NULL, NULL)) 

1047 ELSE: 

1048 return HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 

1049 stream, status, NULL, graph, NULL, NULL)) 

1050  

1051  

1052cdef inline cydriver.CUgraphNode _capture_tail_node(cydriver.CUstream stream) except *: 

1053 """Return the node a freshly-captured single-node operation left as the 

1054 stream's sole capture dependency (e.g. the host node added by 

1055 ``cuLaunchHostFunc``). The driver advances the stream's dependency set to 

1056 the new node, so the next captured op would depend on it. 

1057 """ 

1058 cdef cydriver.CUstreamCaptureStatus status 

1059 cdef const cydriver.CUgraphNode* deps = NULL 1HIJKN

1060 cdef size_t num_deps = 0 1HIJKN

1061 with nogil: 1HIJKN

1062 IF CUDA_CORE_BUILD_MAJOR >= 13: 

1063 HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 1HIJKN

1064 stream, &status, NULL, NULL, &deps, NULL, &num_deps)) 

1065 ELSE: 

1066 HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 

1067 stream, &status, NULL, NULL, &deps, &num_deps)) 

1068 if num_deps != 1: 1HIJKN

1069 raise RuntimeError( 

1070 f"expected exactly one capture dependency after a host callback, got {num_deps}") 

1071 return <cydriver.CUgraphNode>deps[0] 1HIJKN

1072  

1073  

1074cdef inline tuple GB_cond_with_params(GraphBuilder gb, node_params): 

1075 status, _, graph, *deps_info, num_dependencies = handle_return( 1xLybcdefghijklmnopqzrstuvABCDwa

1076 driver.cuStreamGetCaptureInfo(gb._stream.handle) 1xLybcdefghijklmnopqzrstuvABCDwa

1077 ) 

1078 if status != driver.CUstreamCaptureStatus.CU_STREAM_CAPTURE_STATUS_ACTIVE: 1xLybcdefghijklmnopqzrstuvABCDwa

1079 raise RuntimeError("Cannot add conditional node when not actively capturing") 

1080  

1081 new_node = handle_return( 1xLybcdefghijklmnopqzrstuvABCDwa

1082 driver.cuGraphAddNode(graph, *deps_info, num_dependencies, node_params)) 1xLybcdefghijklmnopqzrstuvABCDwa

1083 deps_info_update = [[new_node]] + [None] * (len(deps_info) - 1) 1xLybcdefghijklmnopqzrstuvABCDwa

1084  

1085 handle_return( 1xLybcdefghijklmnopqzrstuvABCDwa

1086 driver.cuStreamUpdateCaptureDependencies( 1xLybcdefghijklmnopqzrstuvABCDwa

1087 gb._stream.handle, 1xLybcdefghijklmnopqzrstuvABCDwa

1088 *deps_info_update, # dependencies, edgeData 1xLybcdefghijklmnopqzrstuvABCDwa

1089 1, # numDependencies 

1090 driver.CUstreamUpdateCaptureDependencies_flags.CU_STREAM_SET_CAPTURE_DEPENDENCIES, 1xLybcdefghijklmnopqzrstuvABCDwa

1091 ) 

1092 ) 

1093  

1094 return tuple( 1xLybcdefghijklmnopqzrstuvABCDwa

1095 GB_init_conditional( 1xLybcdefghijklmnopqzrstuvABCDwa

1096 gb._stream.device.create_stream(), 1xLybcdefghijklmnopqzrstuvABCDwa

1097 <cydriver.CUgraph><intptr_t>int(node_params.conditional.phGraph_out[i]), 1xLybcdefghijklmnopqzrstuvABCDwa

1098 gb, 1xLybcdefghijklmnopqzrstuvABCDwa

1099 <cydriver.CUgraphNode><intptr_t>int(new_node), 1xLybcdefghijklmnopqzrstuvABCDwa

1100 ) 

1101 for i in range(node_params.conditional.size) 1xLybcdefghijklmnopqzrstuvABCDwa

1102 ) 

1103  

1104  

1105cdef class Graph: 

1106 """An executable graph. 

1107  

1108 A graph groups a set of CUDA kernels and other CUDA operations together and executes 

1109 them with a specified dependency tree. It speeds up the workflow by combining the 

1110 driver activities associated with CUDA kernel launches and CUDA API calls. 

1111  

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

1113  

1114 """ 

1115  

1116 def __init__(self): 

1117 raise RuntimeError("directly constructing a Graph instance is not supported") 

1118  

1119 @staticmethod 

1120 cdef Graph _init(GraphExecHandle h_graph_exec): 

1121 cdef Graph self = Graph.__new__(Graph) 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

1122 self._h_graph_exec = h_graph_exec 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

1123 return self 2M [ H I J K / G $ x y T E F # U % 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb!bDcEc#bFcGcHc$b%b'brbNbIc(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b= , : ? - ; 6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + 4 ' (

1124  

1125 def close(self) -> None: 

1126 """Destroy the graph.""" 

1127 self._h_graph_exec.reset() 2[ $ % 8bPb4

1128 retry_deferred_cleanup() 2[ $ % 8bPb4

1129  

1130 @property 

1131 def is_closed(self) -> bool: 

1132 """Whether this executable graph has been closed.""" 

1133 return self._h_graph_exec.get() == NULL 1[

1134  

1135 @property 

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

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

1138  

1139 .. caution:: 

1140  

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

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

1143  

1144 """ 

1145 return as_py(self._h_graph_exec) 1$

1146  

1147 def __getitem__(self, node: GraphNode) -> ExecutableGraphNode: 

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

1149  

1150 *node* is a definition node from the graph used to instantiate this 

1151 executable. Call ``update()`` on the returned view to replace that 

1152 node's parameters for future launches. Kernel, memcpy, and memset 

1153 views also support enabling and disabling the node. 

1154 """ 

1155 Graph_check_open(self) 2[ QbPbRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5b~ lb6b7bmb

1156 GN_check_valid(node) 2QbPbRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5b~ lb6b7bmb

1157 return create_executable_node_view( 2QbPbRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5b~ lb6b7bmb

1158 self._h_graph_exec, node) 2QbPbRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5b~ lb6b7bmb

1159  

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

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

1162  

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

1164  

1165 Parameters 

1166 ---------- 

1167 source : :obj:`~graph.GraphBuilder` or :obj:`~graph.GraphDefinition` 

1168 The graph definition to update from. A GraphBuilder must have 

1169 finished building. 

1170  

1171 """ 

1172 Graph_check_open(self) 2[ 5 ~ lbmbobpbw S xbyb! * +

1173 cdef GraphHandle h_source 

1174  

1175 if isinstance(source, GraphBuilder): 25 ~ lbmbobpbw S xbyb! * +

1176 GB_check_open(<GraphBuilder>source) 15wS!*

1177 if (<GraphBuilder>source)._state != CAPTURE_ENDED: 1wS!*

1178 raise ValueError("Graph has not finished building.") 1*

1179 h_source = (<GraphBuilder>source)._h_graph 1wS!

1180 elif isinstance(source, GraphDefinition): 2~ lbmbobpbxbyb+

1181 GD_check_valid(<GraphDefinition>source) 2~ lbmbobpbxbyb

1182 h_source = (<GraphDefinition>source)._h_graph 2~ lbmbobpbxbyb

1183 else: 

1184 raise TypeError( 1+

1185 f"expected GraphBuilder or GraphDefinition, got {type(source).__name__}") 1+

1186  

1187 cdef cydriver.CUgraphExecUpdateResultInfo result_info 

1188 cdef cydriver.CUresult err = graph_exec_update( 2~ lbmbobpbw S xbyb!

1189 self._h_graph_exec, h_source, &result_info) 

1190 if err == cydriver.CUresult.CUDA_ERROR_GRAPH_EXEC_UPDATE_FAILURE: 2~ lbmbobpbw S xbyb!

1191 reason = driver.CUgraphExecUpdateResult(result_info.result) 2~ obpb!

1192 msg = f"Graph update failed: {reason.__doc__.strip()} ({reason.name})" 2~ obpb!

1193 raise CUDAError(msg) 2~ obpb!

1194 HANDLE_RETURN(err) 2lbmbw S xbyb

1195  

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

1197 """Uploads the graph in a stream. 

1198  

1199 Parameters 

1200 ---------- 

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

1202 The stream in which to upload the graph 

1203  

1204 """ 

1205 Graph_check_open(self) 2[ E U AbBbCbDbEbbbFbcbGbHbIbJbdbKbebfbgbLbhbibMbjbrbNbOb6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3

1206 cdef Stream s = Stream_accept(stream) 2E U AbBbCbDbEbbbFbcbGbHbIbJbdbKbebfbgbLbhbibMbjbrbNbOb6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3

1207 cdef cydriver.CUgraphExec c_exec = as_cu(self._h_graph_exec) 2E U AbBbCbDbEbbbFbcbGbHbIbJbdbKbebfbgbLbhbibMbjbrbNbOb6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3

1208 cdef cydriver.CUstream c_stream = as_cu(s._h_stream) 2E U AbBbCbDbEbbbFbcbGbHbIbJbdbKbebfbgbLbhbibMbjbrbNbOb6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3

1209 with nogil: 2E U AbBbCbDbEbbbFbcbGbHbIbJbdbKbebfbgbLbhbibMbjbrbNbOb6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3

1210 HANDLE_RETURN(cydriver.cuGraphUpload(c_exec, c_stream)) 2E U AbBbCbDbEbbbFbcbGbHbIbJbdbKbebfbgbLbhbibMbjbrbNbOb6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3

1211  

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

1213 """Launches the graph in a stream. 

1214  

1215 Parameters 

1216 ---------- 

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

1218 The stream in which to launch the graph. 

1219  

1220 """ 

1221 Graph_check_open(self) 2M [ H I J K G x y T E # U V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb$b%b'brbNb(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbSbTbUbVbWbXbYbZb0b1b2b3b4b5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb' (

1222 cdef Stream s = Stream_accept(stream) 2M H I J K G x y T E # U V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb$b%b'brbNb(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbSbTbUbVbWbXbYbZb0b1b2b3b4b5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb' (

1223 cdef cydriver.CUgraphExec c_exec = as_cu(self._h_graph_exec) 2M H I J K G x y T E # U V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb$b%b'brbNb(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbSbTbUbVbWbXbYbZb0b1b2b3b4b5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb' (

1224 cdef cydriver.CUstream c_stream = as_cu(s._h_stream) 2M H I J K G x y T E # U V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb$b%b'brbNb(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbSbTbUbVbWbXbYbZb0b1b2b3b4b5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb' (

1225 with nogil: 2M H I J K G x y T E # U V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb$b%b'brbNb(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbSbTbUbVbWbXbYbZb0b1b2b3b4b5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb' (

1226 HANDLE_RETURN(cydriver.cuGraphLaunch(c_exec, c_stream)) 2M H I J K G x y T E # U V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb$b%b'brbNb(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbSbTbUbVbWbXbYbZb0b1b2b3b4b5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb' (

1227  

1228  

1229cdef inline int Graph_check_open(Graph self) except -1: 

1230 if not self._h_graph_exec: 2M [ H I J K G x y T E # U 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb$b%b'brbNb(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + ' (

1231 raise RuntimeError("Graph has been closed") 1[

1232 return 0 2M H I J K G x y T E # U 5 V b c d e f g h i j k l m n o p q z r s t u v A B C D AbBbCbDbEbbbFbcbtbGbHbIbJbdbKbebubfbgbLbhbvbibMbjbwb$b%b'brbNb(b8b)b*b+b,b-b.b/b:b;b=b?bOb@b[b]b^b_b`b{b6 W 0 7 X 1 Q O P 8 Y 2 9 Z 3 QbPb|b}b~bacbcccdcecfcgchcicjcRbzcAcBcSbTbUbVbWbXbYbZb0b1b2b3b4bCc5bkclcmcncocpcqcrcsctcucvcwc~ lbxcyc6b7bmbobpbw S xbyb! * + ' (