@@ -80,11 +80,13 @@ def construct_default_graph_passes(
8080 flex_compile_config = FlexAttention .inductor_configs ,
8181 ),
8282 regional_inductor_pass ,
83+ # insert_kernel_annotations must run before cudagraph: it inserts
84+ # mark_kernels enter/exit calls that execute during CUDA graph
85+ # capture. It is a no-op when cuda-python or cuda-compat >= 13.1
86+ # is not available.
87+ insert_kernel_annotations_pass ,
8388 ]
8489
85- # Insert kernel annotation markers before cudagraph capture.
86- passes .append (insert_kernel_annotations_pass )
87-
8890 # cudagraph should be the last pass.
8991 from torchtitan .experiments .graph_trainer .cudagraph import is_cudagraph_compatible
9092
@@ -263,67 +265,77 @@ def _get_fake_mode_from_gm(gm: torch.fx.GraphModule):
263265 return gm
264266
265267
266- def _mark_kernels_enter (annotation : dict ) -> object :
267- """Helper called from FX graph to enter a mark_kernels scope."""
268- from torch .cuda ._graph_annotations import mark_kernels
269-
270- ctx = mark_kernels (annotation )
271- ctx .__enter__ ()
272- return ctx
273-
274-
275- def _mark_kernels_exit (ctx : object ) -> None :
276- """Helper called from FX graph to exit a mark_kernels scope."""
277- ctx .__exit__ (None , None , None ) # type: ignore[union-attr]
278-
279-
280268def insert_kernel_annotations_pass (
281269 gm : torch .fx .GraphModule ,
282270 example_inputs : tuple | None = None ,
283271) -> torch .fx .GraphModule :
284- """Insert mark_kernels() calls at component boundaries in the FX graph.
272+ """Insert mark_kernels() calls at module boundaries in the FX graph.
285273
286- Reads ``node.meta["custom"]["component "]`` (set via
287- ``torch.fx.traceback.annotate ``) and inserts enter/exit calls so that
274+ Reads ``node.meta["custom"]["module_fqn "]`` (set via
275+ ``annotate_module_fqns ``) and inserts enter/exit calls so that
288276 CUDA graph capture records the annotations.
277+
278+ Requires ``cuda-python`` package and CUDA toolkit/driver >= 13.1
279+ (or cuda-compat >= 13.1). Returns the graph unchanged when unavailable.
280+
281+ Also enables annotation capture on :class:`CUDAGraphWrapper` so that
282+ ``enable_annotations=True`` is passed to ``torch.cuda.graph()``.
289283 """
284+ from torch .cuda ._graph_annotations import _is_tools_id_unavailable
285+
286+ from torchtitan .experiments .graph_trainer .common_utils import _MODULE_FQN
287+ from torchtitan .experiments .graph_trainer .cudagraph import (
288+ enable_cudagraph_annotations ,
289+ )
290+
291+ def _enter (annotation : dict ) -> object :
292+ from torch .cuda ._graph_annotations import mark_kernels
293+
294+ ctx = mark_kernels (annotation )
295+ ctx .__enter__ ()
296+ return ctx
297+
298+ def _exit (ctx : object ) -> None :
299+ ctx .__exit__ (None , None , None ) # type: ignore[union-attr]
300+
301+ if _is_tools_id_unavailable ():
302+ return gm
303+
304+ enable_cudagraph_annotations ()
305+
290306 graph = gm .graph
291- current_component : str | None = None
307+ current_fqn : str | None = None
292308 current_ctx_node = None
293309
294310 for node in list (graph .nodes ):
295- component = (node .meta .get ("custom" ) or {}).get ("component" )
311+ fqn = (node .meta .get ("custom" ) or {}).get (_MODULE_FQN )
296312
297- if component != current_component :
313+ if fqn != current_fqn :
298314 # Close previous scope
299315 if current_ctx_node is not None :
300316 with graph .inserting_before (node ):
301- exit_node = graph .call_function (
302- _mark_kernels_exit , (current_ctx_node ,)
303- )
317+ exit_node = graph .call_function (_exit , (current_ctx_node ,))
304318 exit_node .meta ["custom" ] = {}
305319 current_ctx_node = None
306320
307321 # Open new scope
308- if component is not None :
322+ if fqn is not None :
309323 with graph .inserting_before (node ):
310324 enter_node = graph .call_function (
311- _mark_kernels_enter ,
312- ({"component" : component },),
325+ _enter ,
326+ ({_MODULE_FQN : fqn },),
313327 )
314328 enter_node .meta ["custom" ] = {}
315329 current_ctx_node = enter_node
316330
317- current_component = component
331+ current_fqn = fqn
318332
319333 # Close any trailing scope (before output/return)
320334 if current_ctx_node is not None :
321335 output_nodes = [n for n in graph .nodes if n .op == "output" ]
322336 if output_nodes :
323337 with graph .inserting_before (output_nodes [0 ]):
324- exit_node = graph .call_function (
325- _mark_kernels_exit , (current_ctx_node ,)
326- )
338+ exit_node = graph .call_function (_exit , (current_ctx_node ,))
327339 exit_node .meta ["custom" ] = {}
328340
329341 graph .lint ()
@@ -751,7 +763,6 @@ def tlparse_log_graph_pass(
751763 "auto_bucketing" : autobucketing_reordering_pass ,
752764 "transformer_block_bucketing" : transformer_block_bucketing_reordering_pass ,
753765 "regional_inductor" : regional_inductor_pass ,
754- "insert_kernel_annotations" : insert_kernel_annotations_pass ,
755766 "cudagraph" : cudagraph_pass ,
756767 "full_inductor_compilation" : full_inductor_compilation_pass ,
757768}
0 commit comments