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

458 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-07-29 01:38 +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 GraphCondition, GraphDefinition 

13from cuda.core.graph._host_callback cimport _resolve_host_callback 

14from cuda.core._resource_handles cimport ( 

15 GraphHandle, 

16 OpaqueHandle, 

17 PreparedAttachment, 

18 as_cu, as_py, 

19 create_child_graph_handle, create_graph_exec_handle, create_graph_handle, 

20 graph_clone_attachments, 

21 graph_commit_attachment, 

22 graph_prepare_attachment, 

23 invalidate_child_graph_state, 

24 retry_deferred_cleanup, 

25) 

26from cuda.core._stream cimport Stream 

27from cuda.core._utils.cuda_utils cimport HANDLE_RETURN 

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

29  

30from cuda.core._utils.cuda_utils import ( 

31 CUDAError, 

32 driver, 

33 handle_return, 

34) 

35  

36if TYPE_CHECKING: 

37 from cuda.core.graph._graph_definition import GraphDefinition 

38  

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

40  

41  

42@dataclass 

43class GraphDebugPrintOptions: 

44 """Options for debug_dot_print(). 

45  

46 Attributes 

47 ---------- 

48 verbose : bool 

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

50 runtime_types : bool 

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

52 kernel_node_params : bool 

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

54 memcpy_node_params : bool 

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

56 memset_node_params : bool 

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

58 host_node_params : bool 

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

60 event_node_params : bool 

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

62 ext_semas_signal_node_params : bool 

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

64 ext_semas_wait_node_params : bool 

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

66 kernel_node_attributes : bool 

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

68 handles : bool 

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

70 mem_alloc_node_params : bool 

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

72 mem_free_node_params : bool 

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

74 batch_mem_op_node_params : bool 

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

76 extra_topo_info : bool 

77 Adds edge numbering information (Default to False) 

78 conditional_node_params : bool 

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

80  

81 """ 

82  

83 verbose: bool = False 

84 runtime_types: bool = False 

85 kernel_node_params: bool = False 

86 memcpy_node_params: bool = False 

87 memset_node_params: bool = False 

88 host_node_params: bool = False 

89 event_node_params: bool = False 

90 ext_semas_signal_node_params: bool = False 

91 ext_semas_wait_node_params: bool = False 

92 kernel_node_attributes: bool = False 

93 handles: bool = False 

94 mem_alloc_node_params: bool = False 

95 mem_free_node_params: bool = False 

96 batch_mem_op_node_params: bool = False 

97 extra_topo_info: bool = False 

98 conditional_node_params: bool = False 

99  

100 def _to_flags(self) -> int: 

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

102 flags = 0 2Dba

103 if self.verbose: 2Dba

104 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_VERBOSE 2Dba

105 if self.runtime_types: 2Dba

106 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_RUNTIME_TYPES 1a

107 if self.kernel_node_params: 2Dba

108 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_KERNEL_NODE_PARAMS 1a

109 if self.memcpy_node_params: 2Dba

110 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEMCPY_NODE_PARAMS 1a

111 if self.memset_node_params: 2Dba

112 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEMSET_NODE_PARAMS 1a

113 if self.host_node_params: 2Dba

114 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_HOST_NODE_PARAMS 1a

115 if self.event_node_params: 29 Dba

116 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EVENT_NODE_PARAMS 1a

117 if self.ext_semas_signal_node_params: 2Dba

118 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXT_SEMAS_SIGNAL_NODE_PARAMS 1a

119 if self.ext_semas_wait_node_params: 2Dba

120 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXT_SEMAS_WAIT_NODE_PARAMS 1a

121 if self.kernel_node_attributes: 2Dba

122 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_KERNEL_NODE_ATTRIBUTES 1a

123 if self.handles: 2Dba

124 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_HANDLES 2Dba

125 if self.mem_alloc_node_params: 2Dba

126 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEM_ALLOC_NODE_PARAMS 1a

127 if self.mem_free_node_params: 2Dba

128 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_MEM_FREE_NODE_PARAMS 1a

129 if self.batch_mem_op_node_params: 2Dba

130 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_BATCH_MEM_OP_NODE_PARAMS 1a

131 if self.extra_topo_info: 2Dba

132 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_EXTRA_TOPO_INFO 1a

133 if self.conditional_node_params: 29 Dba

134 flags |= driver.CUgraphDebugDot_flags.CU_GRAPH_DEBUG_DOT_FLAGS_CONDITIONAL_NODE_PARAMS 1a

135 return flags 2Dba

136  

137  

138@dataclass 

139class GraphCompleteOptions: 

140 """Options for graph instantiation. 

141  

142 Attributes 

143 ---------- 

144 auto_free_on_launch : bool, optional 

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

146 upload_stream : Stream, optional 

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

148 device_launch : bool, optional 

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

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

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

152 use_node_priority : bool, optional 

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

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

155  

156 """ 

157  

158 auto_free_on_launch: bool = False 

159 upload_stream: Stream | None = None 

160 device_launch: bool = False 

161 use_node_priority: bool = False 

162  

163  

164def _instantiate_graph(h_graph, options: GraphCompleteOptions | None = None) -> Graph: 

165 params = driver.CUDA_GRAPH_INSTANTIATE_PARAMS() 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

166 if options: 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

167 flags = 0 2| } kb~ ablbbbcbdbmbebfbnbxbybS P Q T

168 if options.auto_free_on_launch: 2| } kb~ ablbbbcbdbmbebfbnbxbybS P Q T

169 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_AUTO_FREE_ON_LAUNCH 2| ~ cbebxbybS P Q T

170 if options.upload_stream: 2| } kb~ ablbbbcbdbmbebfbnbxbybS P Q T

171 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_UPLOAD 2kblbmbnbT

172 params.hUploadStream = options.upload_stream.handle 2kblbmbnbT

173 if options.device_launch: 2| } kb~ ablbbbcbdbmbebfbnbxbybS P Q T

174 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_DEVICE_LAUNCH 2bbT

175 if options.use_node_priority: 2| } kb~ ablbbbcbdbmbebfbnbxbybS P Q T

176 flags |= driver.CUgraphInstantiate_flags.CUDA_GRAPH_INSTANTIATE_FLAG_USE_NODE_PRIORITY 2} abdbfbxbybT

177 params.flags = flags 2| } kb~ ablbbbcbdbmbebfbnbxbybS P Q T

178  

179 py_exec = handle_return(driver.cuGraphInstantiateWithParams(h_graph, params)) 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

180 # Check result_out before wrapping the exec: on a non-SUCCESS result the exec 

181 # may be invalid, and Graph._init's RAII deleter would call cuGraphExecDestroy 

182 # on it during the exception unwind below. 

183 if params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_ERROR: 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

184 raise RuntimeError( 

185 "Instantiation failed for an unexpected reason which is described in the return value of the function." 

186 ) 

187 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_INVALID_STRUCTURE: 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

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

189 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_NODE_OPERATION_NOT_SUPPORTED: 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

190 raise RuntimeError( 

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

192 ) 

193 elif params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_MULTIPLE_CTXS_NOT_SUPPORTED: 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

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

195 elif ( 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

196 cy_binding_version() >= (12, 8, 0) 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

197 and params.result_out == driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_CONDITIONAL_HANDLE_UNUSED 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

198 ): 

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

200 elif params.result_out != driver.CUgraphInstantiateResult.CUDA_GRAPH_INSTANTIATE_SUCCESS: 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

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

202  

203 cdef cydriver.CUgraphExec c_exec = <cydriver.CUgraphExec><intptr_t>int(py_exec) 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

204 return Graph._init(c_exec) 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

205  

206  

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

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

209# Each kind progresses through _CaptureState as follows: 

210# 

211# PRIMARY: NOT_STARTED -> CAPTURING -> ENDED 

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

213# CONDITIONAL_BODY: NOT_STARTED -> CAPTURING -> ENDED 

214# 

215cdef enum _BuilderKind: 

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

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

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

219 PRIMARY = 0 

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

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

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

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

224 # joined first). 

225 FORKED = 1 

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

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

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

229 # capture states like PRIMARY. 

230 CONDITIONAL_BODY = 2 

231  

232  

233# Tracks the capture lifecycle of a GraphBuilder. 

234cdef enum _CaptureState: 

235 CAPTURE_NOT_STARTED = 0 

236 CAPTURING = 1 

237 CAPTURE_ENDED = 2 # Finished, valid handle 

238 CLOSED = 3 # No valid handle 

239  

240  

241cdef class GraphBuilder: 

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

243  

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

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

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

247  

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

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

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

251  

252 .. note:: 

253  

254 Operations recorded during capture reference your memory but do not 

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

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

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

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

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

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

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

262 retains the operands it is given. 

263  

264 """ 

265  

266 def __init__(self): 

267 raise NotImplementedError( 

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

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

270 ) 

271  

272 def __dealloc__(self): 

273 GB_end_capture_if_needed(self, False) 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

274  

275 @staticmethod 

276 def _init(Stream stream): 

277 cdef GraphBuilder self = GraphBuilder.__new__(GraphBuilder) 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

278 # _h_graph set by begin_building 

279 self._h_stream = stream._h_stream 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

280 self._kind = PRIMARY 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

281 self._state = CAPTURE_NOT_STARTED 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

282 self._stream = stream 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

283 return self 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

284  

285 def close(self): 

286 """Destroy the graph builder.""" 

287 GB_end_capture_if_needed(self, True) 1YU?N=EF0Wbcdefghijklmnopqrstuva

288 self._h_graph.reset() 1YU?N=EF0Wbcdefghijklmnopqrstuva

289 self._h_stream.reset() 1YU?N=EF0Wbcdefghijklmnopqrstuva

290 retry_deferred_cleanup() 1YU?N=EF0Wbcdefghijklmnopqrstuva

291 self._state = CLOSED 1YU?N=EF0Wbcdefghijklmnopqrstuva

292 self._stream = None 1YU?N=EF0Wbcdefghijklmnopqrstuva

293  

294 @property 

295 def stream(self) -> Stream: 

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

297 return self._stream 1IYUxy?N@X=E{F!Z0WbcdefghijklmnopqzrstuvABCD:,.;-/#15$26SPQ%37'48wRV()]Ta*

298  

299 @property 

300 def is_join_required(self) -> bool: 

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

302 return self._kind == FORKED 1UNEFbcdefghijklmnopqrstuva

303  

304 @property 

305 def graph_definition(self) -> GraphDefinition: 

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

307  

308 .. versionadded:: 1.1.0 

309  

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

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

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

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

314  

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

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

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

318  

319 Availability: 

320  

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

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

323 :meth:`end_building`. 

324  

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

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

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

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

329 populate it through this view without ever calling 

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

331  

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

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

334 primary instead. 

335  

336 Returns 

337 ------- 

338 GraphDefinition 

339 A view of the graph being built. 

340  

341 Raises 

342 ------ 

343 RuntimeError 

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

345 primary builders) has not started building yet. A 

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

347 keeps working; only fresh access through this property is 

348 rejected once the builder is closed. 

349 """ 

350 GB_check_open(self) 2x G y ? 0b[ N @ X = H

351 if self._kind == FORKED: 2x G y 0b[ N @ X = H

352 raise RuntimeError( 1N

353 "graph_definition is unavailable on forked graph builders; " 

354 "access it through the primary builder instead." 

355 ) 

356 elif self._state == CAPTURING: 2x G y 0b[ @ X = H

357 raise RuntimeError( 1G[

358 "graph_definition is unavailable while capture is in " 

359 "progress; call end_building() first." 

360 ) 

361 elif self._kind == PRIMARY: 2x y 0b@ X = H

362 if self._state == CAPTURE_NOT_STARTED: 20b@ X = H

363 raise RuntimeError( 20b

364 "graph_definition is unavailable before begin_building() on " 

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

366 ) 

367 return GraphDefinition._from_handle(self._h_graph) 1xy@X=H

368  

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

370 """Begins the building process. 

371  

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

373  

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

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

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

377  

378 Parameters 

379 ---------- 

380 mode : str, optional 

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

382 Default set to use relaxed. 

383  

384 """ 

385 GB_check_open(self) 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

386 if self._state != CAPTURE_NOT_STARTED: 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

387 if self._state == CAPTURING: 1^!

388 raise RuntimeError("Graph builder is already building.") 1^

389 else: 

390 raise RuntimeError("Cannot resume building after building has ended.") 1!

391 cdef cydriver.CUstreamCaptureMode c_mode 

392 if mode == "global": 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

393 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_GLOBAL 1:;#$S%']

394 elif mode == "thread_local": 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH,.-/1526PQ3748wRV()]Ta*

395 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_THREAD_LOCAL 1./56Q78]

396 elif mode == "relaxed": 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH,-12P34wRV()]Ta*

397 c_mode = cydriver.CU_STREAM_CAPTURE_MODE_RELAXED 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH,-12P34wRV()]Ta*

398 else: 

399 raise ValueError(f"Unsupported build mode: {mode}") 1]

400  

401 cdef cydriver.CUstream c_stream = as_cu(self._h_stream) 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

402 cdef cydriver.CUgraph c_graph 

403 cdef cydriver.CUstreamCaptureStatus c_status 

404 if self._kind == CONDITIONAL_BODY: 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

405 c_graph = as_cu(self._h_graph) 1xGbcdefghijklmnopqzrstuvABCDwa

406 with nogil: 1xGbcdefghijklmnopqzrstuvABCDwa

407 HANDLE_RETURN(cydriver.cuStreamBeginCaptureToGraph( 1xGbcdefghijklmnopqzrstuvABCDwa

408 c_stream, c_graph, NULL, NULL, 0, c_mode)) 

409 self._state = CAPTURING 1xGbcdefghijklmnopqzrstuvABCDwa

410 else: 

411 with nogil: 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

412 HANDLE_RETURN(cydriver.cuStreamBeginCapture(c_stream, c_mode)) 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

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

414 # failure in _get_capture_info/create_graph_handle still lets 

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

416 self._state = CAPTURING 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

417 with nogil: 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

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

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

420 _get_capture_info(c_stream, &c_status, &c_graph) 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

421 self._h_graph = create_graph_handle(c_graph) 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

422 return self 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

423  

424 @property 

425 def is_building(self) -> bool: 

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

427 GB_check_open(self) 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

428 cdef cydriver.CUstream c_stream = as_cu(self._h_stream) 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

429 cdef cydriver.CUstreamCaptureStatus status 

430 with nogil: 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

431 _get_capture_info(c_stream, &status, NULL) 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

432 if status == cydriver.CU_STREAM_CAPTURE_STATUS_NONE: 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

433 return False 1_

434 elif status == cydriver.CU_STREAM_CAPTURE_STATUS_ACTIVE: 

435 return True 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

436 elif status == cydriver.CU_STREAM_CAPTURE_STATUS_INVALIDATED: 

437 raise RuntimeError( 

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

439 ) 

440 else: 

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

442  

443 def end_building(self) -> GraphBuilder: 

444 """Ends the building process.""" 

445 GB_check_open(self) 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

446 if not self.is_building: 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

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

448 cdef cydriver.CUstream c_stream = as_cu(self._h_stream) 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

449 cdef cydriver.CUgraph c_graph 

450 with nogil: 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

451 HANDLE_RETURN(cydriver.cuStreamEndCapture(c_stream, &c_graph)) 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

452  

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

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

455 self._state = CAPTURE_ENDED 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

456 return self 1O^JKLM+IYxGy?[N@X=`E_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

457  

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

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

460  

461 Parameters 

462 ---------- 

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

464 Customizable dataclass for the graph builder completion options. 

465  

466 Returns 

467 ------- 

468 graph : :obj:`~graph.Graph` 

469 The newly built graph. 

470  

471 """ 

472 GB_check_open(self) 1OJKLM+IYUxyXEF!Z0WbcdefghijklmnopqzrstuvABCD:,.;-/#15$26SPQ%37'48wRV()T*

473 if self._state != CAPTURE_ENDED: 1OJKLM+IYxyXEF!Z0WbcdefghijklmnopqzrstuvABCD:,.;-/#15$26SPQ%37'48wRV()T*

474 raise RuntimeError("Graph has not finished building.") 1+

475  

476 return _instantiate_graph(as_py(self._h_graph), options) 1OJKLM+IYxyXEF!Z0WbcdefghijklmnopqzrstuvABCD:,.;-/#15$26SPQ%37'48wRV()T*

477  

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

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

480  

481 Parameters 

482 ---------- 

483 path : str 

484 File path to use for writting debug DOT output 

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

486 Customizable dataclass for the debug print options. 

487  

488 """ 

489 GB_check_open(self) 1a

490 if self._state != CAPTURE_ENDED: 1a

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

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

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

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

495 cdef const char* c_path = b_path 1a

496 with nogil: 1a

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

498  

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

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

501  

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

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

504  

505 Parameters 

506 ---------- 

507 count : int 

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

509  

510 Returns 

511 ------- 

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

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

514 is always the original graph builder. 

515  

516 """ 

517 if count < 2: 2U N E F 7bb c d e f g h i j k l m n o p q r s t u v a

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

519 GB_check_open(self) 2U N E F 7bb c d e f g h i j k l m n o p q r s t u v a

520 if self._state != CAPTURING: 2U N E F 7bb c d e f g h i j k l m n o p q r s t u v a

521 raise RuntimeError("Graph builder must be building before it can be split.") 27b

522  

523 event = self._stream.record() 1UNEFbcdefghijklmnopqrstuva

524 result = [self] 1UNEFbcdefghijklmnopqrstuva

525 for i in range(count - 1): 1UNEFbcdefghijklmnopqrstuva

526 stream = self._stream.device.create_stream() 1UNEFbcdefghijklmnopqrstuva

527 stream.wait(event) 1UNEFbcdefghijklmnopqrstuva

528 result.append(GB_init_forked(stream, self._h_graph)) 1UNEFbcdefghijklmnopqrstuva

529 event.close() 1UNEFbcdefghijklmnopqrstuva

530 return tuple(result) 1UNEFbcdefghijklmnopqrstuva

531  

532 @staticmethod 

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

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

535  

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

537  

538 Parameters 

539 ---------- 

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

541 The graph builders to join. 

542  

543 Returns 

544 ------- 

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

546 The newly joined graph builder. 

547  

548 """ 

549 if any(not isinstance(builder, GraphBuilder) for builder in graph_builders): 1UNEFbcdefghijklmnopqrstuva

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

551 if len(graph_builders) < 2: 1UNEFbcdefghijklmnopqrstuva

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

553  

554 # Discover the root builder others should join 

555 root_idx = 0 1UNEFbcdefghijklmnopqrstuva

556 for i, builder in enumerate(graph_builders): 1UNEFbcdefghijklmnopqrstuva

557 if not builder.is_join_required: 1UNEFbcdefghijklmnopqrstuva

558 root_idx = i 1UNEFbcdefghijklmnopqrstuva

559 break 1UNEFbcdefghijklmnopqrstuva

560  

561 # Join all onto the root builder 

562 root_bdr = graph_builders[root_idx] 1UNEFbcdefghijklmnopqrstuva

563 for idx, builder in enumerate(graph_builders): 1UNEFbcdefghijklmnopqrstuva

564 if idx == root_idx: 1UNEFbcdefghijklmnopqrstuva

565 continue 1UNEFbcdefghijklmnopqrstuva

566 root_bdr.stream.wait(builder.stream) 1UNEFbcdefghijklmnopqrstuva

567 builder.close() 1UNEFbcdefghijklmnopqrstuva

568  

569 return root_bdr 1UNEFbcdefghijklmnopqrstuva

570  

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

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

573 GB_check_open(self) 

574 return self.stream.__cuda_stream__() 

575  

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

577 return self._stream.context.handle 1xGybcdefghijklmnopqzrstuvABCDwa

578  

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

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

581  

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

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

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

585 ``cudaGraphSetConditional``. 

586  

587 Parameters 

588 ---------- 

589 default_value : int, optional 

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

591 default is assigned. 

592  

593 Returns 

594 ------- 

595 GraphCondition 

596 A condition variable for controlling conditional execution. 

597 """ 

598 GB_check_open(self) 1xGybcdefghijklmnopqzrstuvABCDwa

599 if cy_driver_version() < (12, 3, 0): 1xGybcdefghijklmnopqzrstuvABCDwa

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

601 if cy_binding_version() < (12, 3, 0): 1xGybcdefghijklmnopqzrstuvABCDwa

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

603 if default_value is not None: 1xGybcdefghijklmnopqzrstuvABCDwa

604 flags = driver.CU_GRAPH_COND_ASSIGN_DEFAULT 1xGyABCDw

605 else: 

606 default_value = 0 1bcdefghijklmnopqzrstuva

607 flags = 0 1bcdefghijklmnopqzrstuva

608  

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

610 if status != driver.CUstreamCaptureStatus.CU_STREAM_CAPTURE_STATUS_ACTIVE: 1xGybcdefghijklmnopqzrstuvABCDwa

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

612  

613 raw_handle = handle_return( 1xGybcdefghijklmnopqzrstuvABCDwa

614 driver.cuGraphConditionalHandleCreate(graph, self._get_conditional_context(), default_value, flags) 1xGybcdefghijklmnopqzrstuvABCDwa

615 ) 

616 return GraphCondition._from_handle(<cydriver.CUgraphConditionalHandle><intptr_t>int(raw_handle)) 1xGybcdefghijklmnopqzrstuvABCDwa

617  

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

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

620  

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

622 condition evaluates to true at runtime. 

623  

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

625  

626 Parameters 

627 ---------- 

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

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

630 whether the branch executes. 

631  

632 Returns 

633 ------- 

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

635 The newly created conditional graph builder. 

636  

637 """ 

638 GB_check_open(self) 1xGybcdefghizra

639 if cy_driver_version() < (12, 3, 0): 1xGybcdefghizra

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

641 if cy_binding_version() < (12, 3, 0): 1xGybcdefghizra

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

643 if not isinstance(condition, GraphCondition): 1xGybcdefghizra

644 raise TypeError( 

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

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

647 node_params = driver.CUgraphNodeParams() 1xGybcdefghizra

648 node_params.type = driver.CUgraphNodeType.CU_GRAPH_NODE_TYPE_CONDITIONAL 1xGybcdefghizra

649 node_params.conditional.handle = condition.handle 1xGybcdefghizra

650 node_params.conditional.type = driver.CUgraphConditionalNodeType.CU_GRAPH_COND_TYPE_IF 1xGybcdefghizra

651 node_params.conditional.size = 1 1xGybcdefghizra

652 node_params.conditional.ctx = self._get_conditional_context() 1xGybcdefghizra

653 return GB_cond_with_params(self, node_params)[0] 1xGybcdefghizra

654  

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

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

657  

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

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

660  

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

662  

663 Parameters 

664 ---------- 

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

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

667 which branch executes. 

668  

669 Returns 

670 ------- 

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

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

673  

674 """ 

675 GB_check_open(self) 1jklmnopq

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

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

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

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

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

681 raise TypeError( 

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

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

684 node_params = driver.CUgraphNodeParams() 1jklmnopq

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

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

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

688 node_params.conditional.size = 2 1jklmnopq

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

690 return GB_cond_with_params(self, node_params) 1jklmnopq

691  

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

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

694  

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

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

697 branch will be executed. 

698  

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

700  

701 Parameters 

702 ---------- 

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

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

705 which case executes. 

706 count : int 

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

708  

709 Returns 

710 ------- 

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

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

713  

714 """ 

715 GB_check_open(self) 1stuvw

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

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

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

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

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

721 raise TypeError( 

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

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

724 node_params = driver.CUgraphNodeParams() 1stuvw

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

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

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

728 node_params.conditional.size = count 1stuvw

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

730 return GB_cond_with_params(self, node_params) 1stuvw

731  

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

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

734  

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

736 until the condition evaluates to false. 

737  

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

739  

740 Parameters 

741 ---------- 

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

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

744 loop continuation. 

745  

746 Returns 

747 ------- 

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

749 The newly created while loop graph builder. 

750  

751 """ 

752 GB_check_open(self) 1ABCD

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

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

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

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

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

758 raise TypeError( 

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

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

761 node_params = driver.CUgraphNodeParams() 1ABCD

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

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

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

765 node_params.conditional.size = 1 1ABCD

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

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

768  

769 def embed(self, GraphBuilder child): 

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

771  

772 Parameters 

773 ---------- 

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

775 The child graph builder. Must have finished building. 

776 """ 

777 GB_check_open(self) 1IH

778 if child._state != CAPTURE_ENDED: 1IH

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

780  

781 if not self.is_building: 1IH

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

783  

784 stream_handle = self._stream.handle 1IH

785 _, _, graph_out, *deps_info_out, num_dependencies_out = handle_return( 1IH

786 driver.cuStreamGetCaptureInfo(stream_handle) 1IH

787 ) 

788  

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

790 # for rationale 

791 dependencies_out = deps_info_out[0] 1IH

792 new_node = handle_return( 1IH

793 driver.cuGraphAddChildGraphNode( 1IH

794 graph_out, dependencies_out, 

795 num_dependencies_out, as_py(child._h_graph) 1IH

796 ) 

797 ) 

798 cdef cydriver.CUgraphNode c_new_node = ( 

799 <cydriver.CUgraphNode><intptr_t>int(new_node) 1IH

800 ) 

801 cdef cydriver.CUgraph embedded_graph = NULL 1IH

802 cdef cydriver.CUresult rollback_status 

803 cdef GraphHandle h_embedded 

804 try: 1IH

805 with nogil: 1IH

806 HANDLE_RETURN(cydriver.cuGraphChildGraphNodeGetGraph( 1IH

807 c_new_node, &embedded_graph)) 

808 h_embedded = create_child_graph_handle( 1IH

809 embedded_graph, self._h_graph, c_new_node) 

810 HANDLE_RETURN(graph_clone_attachments( 1IH

811 h_embedded, child._h_graph)) 

812 except: 

813 with nogil: 

814 rollback_status = cydriver.cuGraphDestroyNode(c_new_node) 

815 if rollback_status == cydriver.CUDA_SUCCESS: 

816 invalidate_child_graph_state( 

817 self._h_graph, c_new_node) 

818 raise 

819  

820 deps_info_update = [[new_node]] + [None] * (len(deps_info_out) - 1) 1IH

821 handle_return( 1IH

822 driver.cuStreamUpdateCaptureDependencies( 1IH

823 stream_handle, 1IH

824 *deps_info_update, # dependencies, edgeData 

825 1, 

826 driver.CUstreamUpdateCaptureDependencies_flags.CU_STREAM_SET_CAPTURE_DEPENDENCIES, 1IH

827 ) 

828 ) 

829  

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

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

832  

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

834 in execution. Two modes are supported: 

835  

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

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

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

839 - **ctypes function pointer**: Pass a ``ctypes.CFUNCTYPE`` instance. 

840 The function receives a single ``void*`` argument (the 

841 ``user_data``). The caller must keep the ctypes wrapper alive 

842 for the lifetime of the graph. 

843  

844 .. warning:: 

845  

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

847 deadlock or corrupt driver state. 

848  

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

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

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

852 Use a weak reference to break such cycles. 

853  

854 Parameters 

855 ---------- 

856 fn : callable or ctypes function pointer 

857 The callback function. 

858 user_data : int or bytes-like, optional 

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

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

861 copied and its lifetime is tied to the graph. 

862 """ 

863 GB_callback(self, fn, user_data, False) 1JKLMH

864  

865  

866cdef inline void GB_callback( 

867 GraphBuilder gb, object fn, object user_data, 

868 bint fail_tail_discovery_for_testing) except *: 

869 GB_check_open(gb) 1OJKLMH

870 cdef Stream stream = gb._stream 1OJKLMH

871 cdef cydriver.CUstream c_stream = as_cu(stream._h_stream) 1OJKLMH

872 cdef cydriver.CUstreamCaptureStatus capture_status 

873  

874 with nogil: 1OJKLMH

875 _get_capture_info(c_stream, &capture_status, NULL) 1OJKLMH

876  

877 if capture_status != cydriver.CU_STREAM_CAPTURE_STATUS_ACTIVE: 1OJKLMH

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

879  

880 cdef cydriver.CUhostFn c_fn 

881 cdef void* c_user_data = NULL 1OJKLMH

882 cdef OpaqueHandle fn_owner, data_owner 

883 cdef PreparedAttachment prepared 

884 _resolve_host_callback( 1OJKLMH

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

886 HANDLE_RETURN(graph_prepare_attachment( 1OJKLMH

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

888  

889 with nogil: 1OJKLMH

890 HANDLE_RETURN(cydriver.cuLaunchHostFunc(c_stream, c_fn, c_user_data)) 1OJKLMH

891  

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

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

894 cdef cydriver.CUgraphNode host_node 

895 cdef cydriver.CUresult commit_status 

896 try: 1OJKLMH

897 if fail_tail_discovery_for_testing: 1OJKLMH

898 raise RuntimeError("forced capture tail discovery failure") 1O

899 host_node = _capture_tail_node(c_stream) 1JKLMH

900 except: 1O

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

902 # Retain its owners anonymously to prevent dangling pointers. 

903 commit_status = graph_commit_attachment(prepared, NULL) 1O

904 HANDLE_RETURN(commit_status) 1O

905 raise 1O

906 HANDLE_RETURN(graph_commit_attachment(prepared, host_node)) 1JKLMH

907  

908  

909def _capture_callback_with_tail_failure_for_testing( 

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

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

912 GB_callback(gb, fn, user_data, True) 1O

913  

914  

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

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

917  

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

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

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

921 instead. 

922 """ 

923 if gb._state == CLOSED: 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

924 raise RuntimeError("Graph builder has been closed.") 1U?

925 return 0 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

926  

927  

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

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

930  

931 Only a CAPTURING PRIMARY or CONDITIONAL_BODY builder owns the live 

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

933 requires forked streams to be joined first. 

934  

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

936 (__dealloc__). 

937 """ 

938 cdef cydriver.CUgraph c_graph 

939 cdef cydriver.CUresult err 

940 cdef cydriver.CUstream c_stream 

941 if gb._h_stream and gb._state == CAPTURING and gb._kind != FORKED: 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

942 c_stream = as_cu(gb._h_stream) 1U{

943 with nogil: 1U{

944 err = cydriver.cuStreamEndCapture(c_stream, &c_graph) 1U{

945 if check_status: 1U{

946 HANDLE_RETURN(err) 

947 return 0 2O ^ J K L M + I Y U x G y ? 0b[ N @ X = ` E { _ F ! 7bZ 0 W 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 H : , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 w R V ( ) ] T a *

948  

949  

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

951 cdef GraphBuilder gb = GraphBuilder.__new__(GraphBuilder) 1UNEFbcdefghijklmnopqrstuva

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

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

954 gb._h_graph = h_primary_graph 1UNEFbcdefghijklmnopqrstuva

955 gb._h_stream = stream._h_stream 1UNEFbcdefghijklmnopqrstuva

956 gb._kind = FORKED 1UNEFbcdefghijklmnopqrstuva

957 gb._state = CAPTURING 1UNEFbcdefghijklmnopqrstuva

958 gb._stream = stream 1UNEFbcdefghijklmnopqrstuva

959 return gb 1UNEFbcdefghijklmnopqrstuva

960  

961  

962cdef inline GraphBuilder GB_init_conditional( 

963 Stream stream, cydriver.CUgraph cond_graph, 

964 GraphBuilder parent, cydriver.CUgraphNode owner_node): 

965 cdef GraphBuilder gb = GraphBuilder.__new__(GraphBuilder) 1xGybcdefghijklmnopqzrstuvABCDwa

966 gb._h_graph = create_child_graph_handle( 1xGybcdefghijklmnopqzrstuvABCDwa

967 cond_graph, parent._h_graph, owner_node) 

968 gb._h_stream = stream._h_stream 1xGybcdefghijklmnopqzrstuvABCDwa

969 gb._kind = CONDITIONAL_BODY 1xGybcdefghijklmnopqzrstuvABCDwa

970 gb._state = CAPTURE_NOT_STARTED 1xGybcdefghijklmnopqzrstuvABCDwa

971 gb._stream = stream 1xGybcdefghijklmnopqzrstuvABCDwa

972 return gb 1xGybcdefghijklmnopqzrstuvABCDwa

973  

974  

975cdef inline int _get_capture_info( 

976 cydriver.CUstream stream, 

977 cydriver.CUstreamCaptureStatus* status, 

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

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

980 CUDA 12 vs 13 signature change. 

981  

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

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

984 does not need the graph handle. 

985 """ 

986 IF CUDA_CORE_BUILD_MAJOR >= 13: 

987 return HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 1O^JKLM+IYUxGy?[N@X=`E{_F!Z0WbcdefghijklmnopqzrstuvABCDH:,.;-/#15$26SPQ%37'48wRV()]Ta*

988 stream, status, NULL, graph, NULL, NULL, NULL)) 

989 ELSE: 

990 return HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 

991 stream, status, NULL, graph, NULL, NULL)) 

992  

993  

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

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

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

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

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

999 """ 

1000 cdef cydriver.CUstreamCaptureStatus status 

1001 cdef const cydriver.CUgraphNode* deps = NULL 1JKLMH

1002 cdef size_t num_deps = 0 1JKLMH

1003 with nogil: 1JKLMH

1004 IF CUDA_CORE_BUILD_MAJOR >= 13: 

1005 HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 1JKLMH

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

1007 ELSE: 

1008 HANDLE_RETURN(cydriver.cuStreamGetCaptureInfo( 

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

1010 if num_deps != 1: 1JKLMH

1011 raise RuntimeError( 

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

1013 return <cydriver.CUgraphNode>deps[0] 1JKLMH

1014  

1015  

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

1017 status, _, graph, *deps_info, num_dependencies = handle_return( 1xGybcdefghijklmnopqzrstuvABCDwa

1018 driver.cuStreamGetCaptureInfo(gb._stream.handle) 1xGybcdefghijklmnopqzrstuvABCDwa

1019 ) 

1020 if status != driver.CUstreamCaptureStatus.CU_STREAM_CAPTURE_STATUS_ACTIVE: 1xGybcdefghijklmnopqzrstuvABCDwa

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

1022  

1023 new_node = handle_return( 1xGybcdefghijklmnopqzrstuvABCDwa

1024 driver.cuGraphAddNode(graph, *deps_info, num_dependencies, node_params)) 1xGybcdefghijklmnopqzrstuvABCDwa

1025 deps_info_update = [[new_node]] + [None] * (len(deps_info) - 1) 1xGybcdefghijklmnopqzrstuvABCDwa

1026  

1027 handle_return( 1xGybcdefghijklmnopqzrstuvABCDwa

1028 driver.cuStreamUpdateCaptureDependencies( 1xGybcdefghijklmnopqzrstuvABCDwa

1029 gb._stream.handle, 1xGybcdefghijklmnopqzrstuvABCDwa

1030 *deps_info_update, # dependencies, edgeData 1xGybcdefghijklmnopqzrstuvABCDwa

1031 1, # numDependencies 

1032 driver.CUstreamUpdateCaptureDependencies_flags.CU_STREAM_SET_CAPTURE_DEPENDENCIES, 1xGybcdefghijklmnopqzrstuvABCDwa

1033 ) 

1034 ) 

1035  

1036 return tuple( 1xGybcdefghijklmnopqzrstuvABCDwa

1037 GB_init_conditional( 1xGybcdefghijklmnopqzrstuvABCDwa

1038 gb._stream.device.create_stream(), 1xGybcdefghijklmnopqzrstuvABCDwa

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

1040 gb, 1xGybcdefghijklmnopqzrstuvABCDwa

1041 <cydriver.CUgraphNode><intptr_t>int(new_node), 1xGybcdefghijklmnopqzrstuvABCDwa

1042 ) 

1043 for i in range(node_params.conditional.size) 1xGybcdefghijklmnopqzrstuvABCDwa

1044 ) 

1045  

1046  

1047cdef class Graph: 

1048 """An executable graph. 

1049  

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

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

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

1053  

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

1055  

1056 """ 

1057  

1058 def __init__(self): 

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

1060  

1061 @staticmethod 

1062 cdef Graph _init(cydriver.CUgraphExec graph_exec): 

1063 cdef Graph self = Graph.__new__(Graph) 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

1064 self._h_graph_exec = create_graph_exec_handle(graph_exec) 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

1065 return self 2O J K L M + I Y x y X E F ! Z 0 W 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbxb1b2byb3b4b5bEbFbGbzbAb6bHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb: , . ; - / # 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjbV ( ) T *

1066  

1067 def close(self) -> None: 

1068 """Destroy the graph.""" 

1069 self._h_graph_exec.reset() 2Y 0 CbT

1070 retry_deferred_cleanup() 2Y 0 CbT

1071  

1072 @property 

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

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

1075  

1076 .. caution:: 

1077  

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

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

1080  

1081 """ 

1082 return as_py(self._h_graph_exec) 1Y

1083  

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

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

1086  

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

1088  

1089 Parameters 

1090 ---------- 

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

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

1093 finished building. 

1094  

1095 """ 

1096 from cuda.core.graph import GraphDefinition 2W gbhbw R ibjbV ( )

1097  

1098 cdef cydriver.CUgraph cu_graph 

1099 cdef cydriver.CUgraphExec cu_exec = as_cu(self._h_graph_exec) 2W gbhbw R ibjbV ( )

1100  

1101 if isinstance(source, GraphBuilder): 2W gbhbw R ibjbV ( )

1102 if (<GraphBuilder>source)._state == CLOSED: 1WwRV(

1103 raise ValueError("Source graph builder has been closed.") 1W

1104 if (<GraphBuilder>source)._state != CAPTURE_ENDED: 1wRV(

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

1106 cu_graph = as_cu((<GraphBuilder>source)._h_graph) 1wRV

1107 elif isinstance(source, GraphDefinition): 2gbhbibjb)

1108 cu_graph = <cydriver.CUgraph><intptr_t>int(source.handle) 2gbhbibjb

1109 else: 

1110 raise TypeError( 1)

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

1112  

1113 cdef cydriver.CUgraphExecUpdateResultInfo result_info 

1114 cdef cydriver.CUresult err 

1115 with nogil: 2gbhbw R ibjbV

1116 err = cydriver.cuGraphExecUpdate(cu_exec, cu_graph, &result_info) 2gbhbw R ibjbV

1117 if err == cydriver.CUresult.CUDA_ERROR_GRAPH_EXEC_UPDATE_FAILURE: 2gbhbw R ibjbV

1118 reason = driver.CUgraphExecUpdateResult(result_info.result) 2gbhbV

1119 msg = f"Graph update failed: {reason.__doc__.strip()} ({reason.name})" 2gbhbV

1120 raise CUDAError(msg) 2gbhbV

1121 HANDLE_RETURN(err) 2w R ibjb

1122  

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

1124 """Uploads the graph in a stream. 

1125  

1126 Parameters 

1127 ---------- 

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

1129 The stream in which to upload the graph 

1130  

1131 """ 

1132 cdef cydriver.CUgraphExec c_exec = as_cu(self._h_graph_exec) 2E Z ob| pb} qbrbsbtb~ ubabbbcbvbdbebwbfbzbAbBb# 1 5 $ 2 6 S P Q % 3 7 ' 4 8

1133 cdef cydriver.CUstream c_stream = <cydriver.CUstream><intptr_t>int(stream.handle) 2E Z ob| pb} qbrbsbtb~ ubabbbcbvbdbebwbfbzbAbBb# 1 5 $ 2 6 S P Q % 3 7 ' 4 8

1134 with nogil: 2E Z ob| pb} qbrbsbtb~ ubabbbcbvbdbebwbfbzbAbBb# 1 5 $ 2 6 S P Q % 3 7 ' 4 8

1135 HANDLE_RETURN(cydriver.cuGraphUpload(c_exec, c_stream)) 2E Z ob| pb} qbrbsbtb~ ubabbbcbvbdbebwbfbzbAbBb# 1 5 $ 2 6 S P Q % 3 7 ' 4 8

1136  

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

1138 """Launches the graph in a stream. 

1139  

1140 Parameters 

1141 ---------- 

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

1143 The stream in which to launch the graph. 

1144  

1145 """ 

1146 cdef cydriver.CUgraphExec c_exec = as_cu(self._h_graph_exec) 2O J K L M I x y X E ! Z 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbEbFbGbzbAbHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb# 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjb*

1147 cdef cydriver.CUstream c_stream = <cydriver.CUstream><intptr_t>int(stream.handle) 2O J K L M I x y X E ! Z 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbEbFbGbzbAbHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb# 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjb*

1148 with nogil: 2O J K L M I x y X E ! Z 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbEbFbGbzbAbHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb# 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjb*

1149 HANDLE_RETURN(cydriver.cuGraphLaunch(c_exec, c_stream)) 2O J K L M I x y X E ! Z 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 ob| pb} kbqbrbsbtb~ ubablbbbcbvbdbmbebwbfbnbEbFbGbzbAbHbCbIbJbKbLbMbNbObPbQbRbSbBbTbUbVbWbXbYbZb# 1 5 $ 2 6 S P Q % 3 7 ' 4 8 gbhbw R ibjb*