Skip to content

Commit c52cfa3

Browse files
committed
Update on "support back propagate debug handle to arbitrary ancestor export graph"
Currently propagate_back_debug_handle function can only support propagating debug handle back to the greatest ancestor export graph. This diff update algo to support every possible ancestor export graph on the flow. Differential Revision: [D78464992](https://our.internmc.facebook.com/intern/diff/D78464992/) [ghstack-poisoned]
1 parent 6fa3e3a commit c52cfa3

File tree

1 file changed

+68
-34
lines changed

1 file changed

+68
-34
lines changed

devtools/inspector/_inspector_utils.py

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
from executorch.exir.debug_handle_utils import (
3939
DEBUG_HANDLE_KEY,
4040
FROM_NODE_KEY,
41-
get_greatest_ancestor_node_identifier,
4241
UNSET_DEBUG_HANDLE,
4342
)
4443

@@ -976,32 +975,13 @@ def get_parent_node_identifier(node: Node) -> Optional[str]:
976975
return f"{node_source.name}.{str(node_source.graph_id)}"
977976

978977

979-
def propagate_back_debug_handle(
980-
exported_program: ExportedProgram,
981-
exported_program_graph_id: int,
978+
def _extract_ancestor_debug_handles(
982979
edge_dialect_program: ExportedProgram,
983-
) -> bool:
984-
"""
985-
Propagate debug handle from edge dialect program back to the exported program while maintain the correctness
986-
of operator tracing.
987-
988-
e.g.
989-
export program: op1 -> op2 -> op3
990-
edge dialect program: op1_0 -> op3_0 -> op3_1
991-
where op1_0 is from op1, op3_0 and op3_1 are from op3, op2 is removed by to_edge pipeline (e.g. RemoveNoopPass).
992-
993-
Then debug handle of op1 should be same as op1_0, and debug handle of op3 should be same as op3_0 and op3_1.
994-
The debug handle of op2 will be UNSET_DEBUG_HANDLE for further skipping.
995-
996-
Return: True if every debug handle in the edge dialect program has a corresponding node in the exported program, otherwise, return False.
997-
"""
998-
999-
# 1. set up a mapping from identifier of every possible ancestor node id to debug handle
1000-
# using edge dialect program nodes' debug handles and from_node info
980+
) -> Dict[str, int]:
981+
"""Extract mapping from ancestor node identifiers to debug handles."""
1001982
ancestors_node_id_to_debug_handle: Dict[str, int] = {}
1002983

1003984
def _extract_node_id_to_debug_handle(node: Node) -> None:
1004-
nonlocal ancestors_node_id_to_debug_handle
1005985
if node.op in ("placeholder", "output"):
1006986
return
1007987
for ancestor_node_id in get_ancestor_node_identifiers(node):
@@ -1018,40 +998,55 @@ def _extract_node_id_to_debug_handle(node: Node) -> None:
1018998
bfs_trace_with_node_process(
1019999
edge_dialect_program.graph_module, _extract_node_id_to_debug_handle
10201000
)
1001+
return ancestors_node_id_to_debug_handle
10211002

1022-
# 2. verify if every debug handle in the edge dialect program has a corresponding node in the exported program
1023-
matched_debug_handes: Set[int] = set()
1003+
1004+
def _find_matched_debug_handles(
1005+
exported_program: ExportedProgram,
1006+
exported_program_graph_id: int,
1007+
ancestors_node_id_to_debug_handle: Dict[str, int],
1008+
) -> Set[int]:
1009+
"""Find debug handles that have corresponding nodes in the exported program."""
1010+
matched_debug_handles: Set[int] = set()
10241011

10251012
def _find_n_match_node(node: Node) -> None:
1026-
nonlocal matched_debug_handes
10271013
if node.op in ("output", "placeholder"):
10281014
return
10291015
node_id = f"{node.name}.{exported_program_graph_id}"
10301016
parent_node_id = get_parent_node_identifier(node)
10311017
if node_id in ancestors_node_id_to_debug_handle:
1032-
matched_debug_handes.add(ancestors_node_id_to_debug_handle[node_id])
1018+
matched_debug_handles.add(ancestors_node_id_to_debug_handle[node_id])
10331019
elif parent_node_id and parent_node_id in ancestors_node_id_to_debug_handle:
1034-
matched_debug_handes.add(ancestors_node_id_to_debug_handle[parent_node_id])
1020+
matched_debug_handles.add(ancestors_node_id_to_debug_handle[parent_node_id])
10351021

10361022
bfs_trace_with_node_process(exported_program.graph_module, _find_n_match_node)
1023+
return matched_debug_handles
10371024

1025+
1026+
def _verify_graph_match(
1027+
edge_dialect_program: ExportedProgram, matched_debug_handles: Set[int]
1028+
) -> bool:
1029+
"""Verify if every debug handle in edge dialect program has a corresponding node."""
10381030
graph_matched = True
10391031

10401032
def _check_graph_match(node: Node) -> None:
10411033
nonlocal graph_matched
10421034
if node.op in ("output", "placeholder"):
10431035
return
1044-
1045-
if node.meta[DEBUG_HANDLE_KEY] not in matched_debug_handes:
1036+
if node.meta[DEBUG_HANDLE_KEY] not in matched_debug_handles:
10461037
graph_matched = False
10471038

10481039
bfs_trace_with_node_process(edge_dialect_program.graph_module, _check_graph_match)
1040+
return graph_matched
10491041

1050-
# if any node in the edge dialect program has no corresponding node in the exported program, match failed
1051-
if not graph_matched:
1052-
return False
10531042

1054-
# 3. propagate debug handle from edge dialect program back to the exported program while maintain the correctness of operator tracing
1043+
def _apply_debug_handles(
1044+
exported_program: ExportedProgram,
1045+
exported_program_graph_id: int,
1046+
ancestors_node_id_to_debug_handle: Dict[str, int],
1047+
) -> None:
1048+
"""Apply debug handles to the exported program nodes."""
1049+
10551050
def _equip_debug_handle(node: Node) -> None:
10561051
if node.op in ("output", "placeholder"):
10571052
return
@@ -1067,4 +1062,43 @@ def _equip_debug_handle(node: Node) -> None:
10671062
node.meta[DEBUG_HANDLE_KEY] = UNSET_DEBUG_HANDLE
10681063

10691064
bfs_trace_with_node_process(exported_program.graph_module, _equip_debug_handle)
1065+
1066+
1067+
def propagate_back_debug_handle(
1068+
exported_program: ExportedProgram,
1069+
exported_program_graph_id: int,
1070+
edge_dialect_program: ExportedProgram,
1071+
) -> bool:
1072+
"""
1073+
Propagate debug handle from edge dialect program back to the exported program while maintain the correctness
1074+
of operator tracing.
1075+
1076+
e.g.
1077+
export program: op1 -> op2 -> op3
1078+
edge dialect program: op1_0 -> op3_0 -> op3_1
1079+
where op1_0 is from op1, op3_0 and op3_1 are from op3, op2 is removed by to_edge pipeline (e.g. RemoveNoopPass).
1080+
1081+
Then debug handle of op1 should be same as op1_0, and debug handle of op3 should be same as op3_0 and op3_1.
1082+
The debug handle of op2 will be UNSET_DEBUG_HANDLE for further skipping.
1083+
1084+
Return: True if every debug handle in the edge dialect program has a corresponding node in the exported program, otherwise, return False.
1085+
"""
1086+
# 1. Extract mapping from ancestor node identifiers to debug handles
1087+
ancestors_node_id_to_debug_handle = _extract_ancestor_debug_handles(
1088+
edge_dialect_program
1089+
)
1090+
1091+
# 2. Find debug handles that have corresponding nodes in the exported program
1092+
matched_debug_handles = _find_matched_debug_handles(
1093+
exported_program, exported_program_graph_id, ancestors_node_id_to_debug_handle
1094+
)
1095+
1096+
# 3. Verify if every debug handle in edge dialect program has a corresponding node
1097+
if not _verify_graph_match(edge_dialect_program, matched_debug_handles):
1098+
return False
1099+
1100+
# 4. Apply debug handles to the exported program
1101+
_apply_debug_handles(
1102+
exported_program, exported_program_graph_id, ancestors_node_id_to_debug_handle
1103+
)
10701104
return True

0 commit comments

Comments
 (0)