Skip to content

Commit 8a0f135

Browse files
Olivia-liufacebook-github-bot
authored andcommitted
Inspector APIs documentation - inline docstring part (#626)
Summary: As titled Reviewed By: tarun292 Differential Revision: D49893649
1 parent 9e379ea commit 8a0f135

File tree

3 files changed

+73
-32
lines changed

3 files changed

+73
-32
lines changed

docs/source/ir-ops-set-definition.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The key motivation behind the core ATen opset is to reduce the number of operato
2424

2525
## Development of the Core ATen Operator Set
2626

27-
Although Executorch uses the core ATen opset, it is not specific to ExecuTorch. One of the primary design goals of the core ATen opset is that it should be as generic as possible; the vast majority of use-cases will not want to decompose the operators contained within it. By extension, the decompositions implied by the core ATen opset should be useful to the vast majority of use-cases.
27+
Although ExecuTorch uses the core ATen opset, it is not specific to ExecuTorch. One of the primary design goals of the core ATen opset is that it should be as generic as possible; the vast majority of use-cases will not want to decompose the operators contained within it. By extension, the decompositions implied by the core ATen opset should be useful to the vast majority of use-cases.
2828

2929
Another key consideration was to keep the opset as minimal as possible, but not at the expense of imposing decompositions that would have a profound negative impact on performance or developer experience.
3030

sdk/inspector/inspector.py

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -129,28 +129,34 @@ def median(self) -> float:
129129
@dataclass
130130
class Event:
131131
"""
132-
Corresponds to an op instance
132+
An Event corresponds to an operator instance with perf data retrieved from the runtime and other metadata from `ETRecord`.
133+
134+
Args:
135+
name: Name of the profiling/debugging `Event`.
136+
perf_data: Performance data associated with the event retrived from the runtime (available attributes: p50, p90, avg, min, max and median).
137+
op_type: List of op types corresponding to the event.
138+
delegate_debug_identifier: Supplemental identifier used in combination with instruction id.
139+
debug_handles: Debug handles in the model graph to which this event is correlated.
140+
stack_trace: A dictionary mapping the name of each associated op to its stack trace.
141+
module_hierarchy: A dictionary mapping the name of each associated op to its module hierarchy.
142+
is_delegated_op: Whether or not the event was delegated.
143+
delegate_backend_name: Name of the backend this event was delegated to.
144+
debug_data: Intermediate data collected during runtime.
133145
"""
134146

135147
name: str
136148
perf_data: PerfData
137149
op_types: List[str] = dataclasses.field(default_factory=list)
138-
139-
# Instruction Id of the original profiling event
140-
instruction_id: Optional[int] = None
141-
142-
# Supplemental Identifier used in combination with instruction_identifier
143150
delegate_debug_identifier: Optional[Union[int, str]] = None
144-
145-
# Debug Handles in the model graph to which this event is correlated
146151
debug_handles: Optional[Union[int, Sequence[int]]] = None
147-
148152
stack_traces: Dict[str, str] = dataclasses.field(default_factory=dict)
149153
module_hierarchy: Dict[str, Dict] = dataclasses.field(default_factory=dict)
150154
is_delegated_op: Optional[bool] = None
151155
delegate_backend_name: Optional[str] = None
152156
debug_data: List[torch.Tensor] = dataclasses.field(default_factory=list)
153157

158+
_instruction_id: Optional[int] = None
159+
154160
@staticmethod
155161
def _gen_from_profile_events(
156162
signature: ProfileEventSignature,
@@ -183,9 +189,9 @@ def _gen_from_profile_events(
183189
return Event(
184190
name=name,
185191
perf_data=perf_data,
186-
instruction_id=signature.instruction_id,
187192
delegate_debug_identifier=delegate_debug_identifier,
188193
is_delegated_op=is_delegated_op,
194+
_instruction_id=signature.instruction_id,
189195
)
190196

191197
def _associate_with_op_graph_nodes(
@@ -213,11 +219,14 @@ def _associate_with_op_graph_nodes(
213219

214220
@dataclass
215221
class EventBlock:
216-
"""
217-
EventBlock contains a collection of events associated with a particular profiling/debugging block retrieved from the runtime.
218-
Attributes:
219-
name (str): Name of the profiling/debugging block
220-
events (List[Event]): List of events associated with the profiling/debugging block
222+
r"""
223+
An `EventBlock` contains a collection of events associated with a particular profiling/debugging block retrieved from the runtime.
224+
Each `EventBlock` represents a pattern of execution. For example, model initiation and loading lives in a single `EventBlock`.
225+
If there's a control flow, each branch will be represented by a separate `EventBlock`.
226+
227+
Args:
228+
name: Name of the profiling/debugging block.
229+
events: List of `Event`\ s associated with the profiling/debugging block.
221230
"""
222231

223232
name: str
@@ -226,7 +235,14 @@ class EventBlock:
226235
def to_dataframe(self) -> pd.DataFrame:
227236
"""
228237
Converts the EventBlock into a DataFrame with each row being an event instance
238+
239+
Args:
240+
None
241+
242+
Returns:
243+
A Pandas DataFrame containing the data of each Event instance in this EventBlock.
229244
"""
245+
230246
# TODO: push row generation down to Event
231247
data = {
232248
"event_block_name": [self.name] * len(self.events),
@@ -320,11 +336,11 @@ def _gen_resolve_debug_handles(
320336
"""
321337
for event in self.events:
322338
# Check if instruction_id is present in the event
323-
if event.instruction_id is None:
339+
if event._instruction_id is None:
324340
continue
325341

326342
# Check for the instruction_id in handle map
327-
if (instruction_id := str(event.instruction_id)) not in handle_map:
343+
if (instruction_id := str(event._instruction_id)) not in handle_map:
328344
continue
329345

330346
# For non-delegated event, handles are found in handle_map
@@ -339,7 +355,7 @@ def _gen_resolve_debug_handles(
339355
):
340356
event.debug_handles = handle_map[instruction_id]
341357
log.warning(
342-
f" No delegate mapping found for delegate with instruction id {event.instruction_id}"
358+
f" No delegate mapping found for delegate with instruction id {event._instruction_id}"
343359
)
344360
continue
345361

@@ -376,14 +392,18 @@ def __init__(
376392
etrecord_path: Optional[str] = None,
377393
etdump_scale: int = 1000,
378394
) -> None:
379-
"""
380-
Create an inspector instance from the provided ETDump/ETRecord
395+
r"""
396+
Initialize an `Inspector` instance with the underlying `EventBlock`\ s populated with data from the provided ETDump path
397+
and optional ETRecord path.
381398
382399
Args:
383400
etdump_path: Path to the ETDump file.
384-
etrecord_path: Path to the ETRecord file.
401+
etrecord_path: Optional path to the ETRecord file.
385402
etdump_scale: Inverse Scale Factor used to cast the timestamps in ETDump
386403
defaults to milli (1000ms = 1s).
404+
405+
Returns:
406+
None
387407
"""
388408

389409
self._etrecord = (
@@ -422,7 +442,13 @@ def __init__(
422442

423443
def print_data_tabular(self) -> None:
424444
"""
425-
Prints the underlying EventBlocks (essentially all the performance data)
445+
Displays the underlying EventBlocks in a structured tabular format, with each row representing an Event.
446+
447+
Args:
448+
None
449+
450+
Returns:
451+
None
426452
"""
427453

428454
def style_text_size(val, size=12):
@@ -447,7 +473,17 @@ def style_text_size(val, size=12):
447473
print(tabulate(filtered_df, headers="keys", tablefmt="fancy_grid"))
448474

449475
# TODO: write unit test
450-
def find_total_for_module(self, module_name: str):
476+
def find_total_for_module(self, module_name: str) -> float:
477+
"""
478+
Returns the total average compute time of all operators within the specified module.
479+
480+
Args:
481+
module_name: Name of the module to be aggregated against.
482+
483+
Returns:
484+
Sum of the average compute time (in seconds) of all operators within the module with "module_name".
485+
"""
486+
451487
total = 0.0
452488
for block in self.event_blocks:
453489
for event in block.events:
@@ -481,10 +517,13 @@ def get_exported_program(
481517
self, graph: Optional[str] = None
482518
) -> Optional[ExportedProgram]:
483519
"""
484-
Access helper for ETRecord, defaults to returning Edge Dialect Program
520+
Access helper for ETRecord, defaults to returning the Edge Dialect program.
485521
486522
Args:
487-
graph: Name of the graph to access. If None, returns the Edge Dialect Program.
523+
graph: Optional name of the graph to access. If None, returns the Edge Dialect program.
524+
525+
Returns:
526+
The ExportedProgram object of "graph".
488527
"""
489528
if self._etrecord is None:
490529
log.warning(

sdk/inspector/tests/event_blocks_test.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,13 @@ def _test_profile_event_generation(
192192

193193
is_delegated = delegate_debug_id is not None
194194
expected_event = Event(
195-
str(delegate_debug_id) if is_delegated else name,
196-
PerfData([float(duration) / scale_factor for duration in durations]),
197-
instruction_id=signature.instruction_id,
195+
name=str(delegate_debug_id) if is_delegated else name,
196+
perf_data=PerfData(
197+
[float(duration) / scale_factor for duration in durations]
198+
),
198199
delegate_debug_identifier=delegate_debug_id,
199200
is_delegated_op=is_delegated,
201+
_instruction_id=signature.instruction_id,
200202
)
201203
self.assertEqual(event, expected_event)
202204

@@ -283,12 +285,12 @@ def _gen_event_helper(events: List[ProfileEvent]) -> Event:
283285
# Verify Results
284286
for event in event_block.events:
285287
# To satisfy type checker
286-
assert event.instruction_id is not None
288+
assert event._instruction_id is not None
287289
if (
288290
delegate_debug_identifier := event.delegate_debug_identifier
289291
) is not None:
290292
# Delegated
291-
metadata = delegate_map[str(event.instruction_id)]
293+
metadata = delegate_map[str(event._instruction_id)]
292294
self.assertEqual(event.delegate_backend_name, metadata["name"])
293295
self.assertEqual(
294296
event.debug_handles,
@@ -297,5 +299,5 @@ def _gen_event_helper(events: List[ProfileEvent]) -> Event:
297299
else:
298300
# Non Delegated
299301
self.assertEqual(
300-
event.debug_handles, handle_map[str(event.instruction_id)]
302+
event.debug_handles, handle_map[str(event._instruction_id)]
301303
)

0 commit comments

Comments
 (0)