Skip to content

Commit bf55707

Browse files
Olivia-liufacebook-github-bot
authored andcommitted
Add a default delegate time scale converter (#5076)
Summary: Pull Request resolved: #5076 By default, the non-delegated events have a time scale converter, but delegated events do not, and this has caused confusion for users: [post](https://fb.workplace.com/groups/pytorch.edge.users/permalink/1562687731268181/), [Issue #4504](#4504). This diff gives a quick solution for the problem to unblock ET Beta. When no `delegate_time_scale_converter` is provided by the user, just use the same converting ratio as the non-delegated events. The proper solution to write the convertion in etdump is tracked by T198369344 and T198369419 Reviewed By: dbort Differential Revision: D62160650
1 parent eca9ed5 commit bf55707

File tree

4 files changed

+70
-9
lines changed

4 files changed

+70
-9
lines changed

devtools/inspector/_inspector.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
)
4040
from executorch.devtools.etrecord import ETRecord, parse_etrecord
4141
from executorch.devtools.inspector._inspector_utils import (
42+
calculate_time_scale_factor,
4243
create_debug_handle_to_op_node_mapping,
4344
EDGE_DIALECT_GRAPH_KEY,
4445
EXCLUDED_COLUMNS_WHEN_PRINTING,
@@ -52,7 +53,6 @@
5253
is_inference_output_equal,
5354
ProgramOutput,
5455
RESERVED_FRAMEWORK_EVENT_NAMES,
55-
TIME_SCALE_DICT,
5656
TimeScale,
5757
verify_debug_data_equivalence,
5858
)
@@ -799,9 +799,7 @@ class GroupedRunInstances:
799799

800800
# Construct the EventBlocks
801801
event_blocks = []
802-
scale_factor = (
803-
TIME_SCALE_DICT[source_time_scale] / TIME_SCALE_DICT[target_time_scale]
804-
)
802+
scale_factor = calculate_time_scale_factor(source_time_scale, target_time_scale)
805803
for run_signature, grouped_run_instance in run_groups.items():
806804
run_group: OrderedDict[EventSignature, List[InstructionEvent]] = (
807805
grouped_run_instance.events
@@ -966,6 +964,9 @@ def __init__(
966964
debug_buffer_path: Debug buffer file path that contains the debug data referenced by ETDump for intermediate and program outputs.
967965
delegate_metadata_parser: Optional function to parse delegate metadata from an Profiling Event. Expected signature of the function is:
968966
(delegate_metadata_list: List[bytes]) -> Union[List[str], Dict[str, Any]]
967+
delegate_time_scale_converter: Optional function to convert the time scale of delegate profiling data. If not given, use the conversion ratio of
968+
target_time_scale/source_time_scale.
969+
enable_module_hierarchy: Enable submodules in the operator graph. Defaults to False.
969970
970971
Returns:
971972
None
@@ -980,6 +981,14 @@ def __init__(
980981
self._source_time_scale = source_time_scale
981982
self._target_time_scale = target_time_scale
982983

984+
if delegate_time_scale_converter is None:
985+
scale_factor = calculate_time_scale_factor(
986+
source_time_scale, target_time_scale
987+
)
988+
delegate_time_scale_converter = (
989+
lambda event_name, input_time: input_time / scale_factor
990+
)
991+
983992
if etrecord is None:
984993
self._etrecord = None
985994
elif isinstance(etrecord, ETRecord):
@@ -1002,10 +1011,10 @@ def __init__(
10021011
)
10031012

10041013
self.event_blocks = EventBlock._gen_from_etdump(
1005-
etdump,
1006-
self._source_time_scale,
1007-
self._target_time_scale,
1008-
output_buffer,
1014+
etdump=etdump,
1015+
source_time_scale=self._source_time_scale,
1016+
target_time_scale=self._target_time_scale,
1017+
output_buffer=output_buffer,
10091018
delegate_metadata_parser=delegate_metadata_parser,
10101019
delegate_time_scale_converter=delegate_time_scale_converter,
10111020
)

devtools/inspector/_inspector_utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ class TimeScale(Enum):
6363
}
6464

6565

66+
def calculate_time_scale_factor(
67+
source_time_scale: TimeScale, target_time_scale: TimeScale
68+
) -> float:
69+
"""
70+
Calculate the factor (source divided by target) between two time scales
71+
"""
72+
return TIME_SCALE_DICT[source_time_scale] / TIME_SCALE_DICT[target_time_scale]
73+
74+
6675
# Model Debug Output
6776
InferenceOutput: TypeAlias = Union[
6877
torch.Tensor, List[torch.Tensor], int, float, str, bool, None

devtools/inspector/tests/inspector_test.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import unittest
1111
from contextlib import redirect_stdout
1212

13-
from typing import List
13+
from typing import Callable, List
1414

1515
from unittest.mock import patch
1616

@@ -32,6 +32,7 @@
3232
InstructionEvent,
3333
InstructionEventSignature,
3434
ProfileEventSignature,
35+
TimeScale,
3536
)
3637

3738
from executorch.exir import ExportedProgram
@@ -88,6 +89,33 @@ def test_inspector_constructor(self):
8889
# Because we mocked parse_etrecord() to return None, this method shouldn't be called
8990
mock_gen_graphs_from_etrecord.assert_not_called()
9091

92+
def test_default_delegate_time_scale_converter(self):
93+
# Create a context manager to patch functions called by Inspector.__init__
94+
with patch.object(
95+
_inspector, "parse_etrecord", return_value=None
96+
), patch.object(
97+
_inspector, "gen_etdump_object", return_value=None
98+
), patch.object(
99+
EventBlock, "_gen_from_etdump"
100+
) as mock_gen_from_etdump, patch.object(
101+
_inspector, "gen_graphs_from_etrecord"
102+
), patch.object(
103+
_inspector, "create_debug_handle_to_op_node_mapping"
104+
):
105+
# Call the constructor of Inspector
106+
Inspector(
107+
etdump_path=ETDUMP_PATH,
108+
etrecord=ETRECORD_PATH,
109+
source_time_scale=TimeScale.US,
110+
target_time_scale=TimeScale.S,
111+
)
112+
113+
# Verify delegate_time_scale_converter is set to be a callable
114+
self.assertIsInstance(
115+
mock_gen_from_etdump.call_args.get("delegate_time_scale_converter"),
116+
Callable,
117+
)
118+
91119
def test_inspector_print_data_tabular(self):
92120
# Create a context manager to patch functions called by Inspector.__init__
93121
with patch.object(

devtools/inspector/tests/inspector_utils_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323

2424
from executorch.devtools.etrecord.tests.etrecord_test import TestETRecord
2525
from executorch.devtools.inspector._inspector_utils import (
26+
calculate_time_scale_factor,
2627
create_debug_handle_to_op_node_mapping,
2728
EDGE_DIALECT_GRAPH_KEY,
2829
find_populated_event,
2930
gen_graphs_from_etrecord,
3031
is_inference_output_equal,
32+
TimeScale,
3133
)
3234

3335

@@ -170,6 +172,19 @@ def test_is_inference_output_equal_returns_true_for_same_strs(self):
170172
)
171173
)
172174

175+
def test_calculate_time_scale_factor_second_based(self):
176+
self.assertEqual(
177+
calculate_time_scale_factor(TimeScale.NS, TimeScale.MS), 1000000
178+
)
179+
self.assertEqual(
180+
calculate_time_scale_factor(TimeScale.MS, TimeScale.NS), 1 / 1000000
181+
)
182+
183+
def test_calculate_time_scale_factor_cycles(self):
184+
self.assertEqual(
185+
calculate_time_scale_factor(TimeScale.CYCLES, TimeScale.CYCLES), 1
186+
)
187+
173188

174189
def gen_mock_operator_graph_with_expected_map() -> (
175190
Tuple[OperatorGraph, Dict[int, OperatorNode]]

0 commit comments

Comments
 (0)