Skip to content

Commit 7b29899

Browse files
Jack-Khuufacebook-github-bot
authored andcommitted
Add helper to resolve debug handles of Event (#368)
Summary: Pull Request resolved: #368 Add a linking function in the form of `_gen_resolve_debug_handles` It takes the derived EventBlocks (profiling info, etc.) and links it to ETRecord ("Debug Symbols") via the provided debug_handles --- Note: this function only resolves the link (updates the debug_handles field), but does not join the components themselves Reviewed By: tarun292 Differential Revision: D49117148 fbshipit-source-id: f71a8a7d3b8dcb4e559b733946f0df171147309e
1 parent e60110a commit 7b29899

File tree

2 files changed

+155
-5
lines changed

2 files changed

+155
-5
lines changed

sdk/etdb/inspector.py

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,20 @@
55
# LICENSE file in the root directory of this source tree.
66

77
import dataclasses
8+
import logging
89
from collections import defaultdict, OrderedDict
910
from dataclasses import dataclass
10-
from typing import Dict, List, Mapping, NewType, Optional, Tuple, Union
11+
from typing import (
12+
Dict,
13+
List,
14+
Mapping,
15+
Optional,
16+
Sequence,
17+
Tuple,
18+
TypeAlias,
19+
TypedDict,
20+
Union,
21+
)
1122

1223
import numpy as np
1324
import pandas as pd
@@ -20,6 +31,7 @@
2031
from executorch.sdk.etrecord import parse_etrecord
2132
from tabulate import tabulate
2233

34+
log: logging.Logger = logging.getLogger(__name__)
2335

2436
# Signature of a ProfileEvent
2537
@dataclass(frozen=True, order=True)
@@ -46,7 +58,19 @@ def _gen_from_event(event: ProfileEvent) -> "ProfileEventSignature":
4658

4759

4860
# Signature of a RunData as defined by its ProfileEvents
49-
RunSignature = NewType("RunSignature", Tuple[ProfileEventSignature])
61+
RunSignature: TypeAlias = Tuple[ProfileEventSignature]
62+
63+
64+
# Typing for mapping Event.delegate_debug_identifiers to debug_handle(s)
65+
DelegateIdentifierDebugHandleMap: TypeAlias = Union[
66+
Mapping[int, Tuple[int, ...]], Mapping[str, Tuple[int, ...]]
67+
]
68+
69+
# Typing for Dict containig delegate metadata
70+
DelegateMetadata = TypedDict(
71+
"DelegateMetadata",
72+
{"name": str, "delegate_map": DelegateIdentifierDebugHandleMap},
73+
)
5074

5175

5276
@dataclass
@@ -97,7 +121,7 @@ class Event:
97121
delegate_debug_identifier: Optional[Union[int, str]] = None
98122

99123
# Debug Handles in the model graph to which this event is correlated
100-
debug_handles: Optional[Union[int, List[int]]] = None
124+
debug_handles: Optional[Union[int, Sequence[int]]] = None
101125

102126
stack_trace: Dict[str, str] = dataclasses.field(default_factory=dict)
103127
module_hierarchy: Dict[str, Dict] = dataclasses.field(default_factory=dict)
@@ -203,7 +227,7 @@ def _gen_from_etdump(etdump: ETDumpFlatCC) -> List["EventBlock"]:
203227
profile_events[signature] = profile_event
204228

205229
# Create a RunSignature from the ProfileEventSignature found
206-
run_signature: RunSignature = RunSignature(tuple(profile_events.keys()))
230+
run_signature: RunSignature = tuple(profile_events.keys())
207231

208232
# Update the Profile Run Groups, indexed on the RunSignature
209233
run_signature_events: OrderedDict[
@@ -224,6 +248,47 @@ def _gen_from_etdump(etdump: ETDumpFlatCC) -> List["EventBlock"]:
224248
for index, profile_events in enumerate(profile_run_groups.values())
225249
]
226250

251+
def _gen_resolve_debug_handles(
252+
self,
253+
handle_map: Dict[int, List[int]],
254+
delegate_map: Optional[Dict[int, DelegateMetadata]] = None,
255+
):
256+
"""
257+
Given mappings from instruction id to debug handles, populate the
258+
debug_handles field of all underlying events
259+
260+
If the event is delegated, index with the instruction_id and delegate_debug_identifier
261+
to obtain the debug_handle via the delegate map
262+
"""
263+
for event in self.events:
264+
# Check for the instruction_id in handle map
265+
if (
266+
instruction_id := event.instruction_id
267+
) is None or instruction_id not in handle_map:
268+
continue
269+
270+
# For non-delegated event, handles are found in handle_map
271+
if (delegate_debug_id := event.delegate_debug_identifier) is None:
272+
event.debug_handles = handle_map[instruction_id]
273+
continue
274+
275+
# Check that the delegated event has a corresponding mapping
276+
if (
277+
delegate_map is None
278+
or (delegate_metadata := delegate_map.get(instruction_id)) is None
279+
):
280+
event.debug_handles = handle_map[instruction_id]
281+
log.warning(
282+
f" No delegate mapping found for delegate with instruction id {event.instruction_id}"
283+
)
284+
continue
285+
286+
# For delegated events, handles are found via delegateMetadata
287+
event.delegate_backend_name = delegate_metadata.get("name", "")
288+
event.debug_handles = delegate_metadata.get("delegate_map", {}).get(
289+
delegate_debug_id # pyre-ignore
290+
)
291+
227292

228293
class Inspector:
229294
"""

sdk/etdb/tests/event_blocks_test.py

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010

1111
import executorch.sdk.etdump.schema_flatcc as flatcc
1212
from executorch.sdk.etdb.inspector import (
13+
DelegateMetadata,
1314
Event,
1415
EventBlock,
1516
PerfData,
1617
ProfileEventSignature,
1718
)
18-
from executorch.sdk.etdump.schema_flatcc import ETDumpFlatCC
19+
from executorch.sdk.etdump.schema_flatcc import ETDumpFlatCC, ProfileEvent
1920

2021

2122
class TestEventBlock(unittest.TestCase):
@@ -203,3 +204,87 @@ def _test_profile_event_generation(
203204

204205
# Delegate with String Debug ID
205206
_test_profile_event_generation("delegate", 1, None, "identifier")
207+
208+
def test_gen_resolve_debug_handles(self) -> None:
209+
"""
210+
Test that gen_resolve_debug_handles() correctly populates the EventBlock
211+
"""
212+
213+
def _gen_event_helper(events: List[ProfileEvent]) -> Event:
214+
"""
215+
Helper function to generate an Event given a set of ProfileEvents
216+
"""
217+
signature = ProfileEventSignature._gen_from_event(events[0])
218+
return Event._gen_from_profile_events(signature, events)
219+
220+
# Create Test Data
221+
222+
# Non-Delegated
223+
non_delegated_profile_events_1 = [
224+
TestEventBlock._gen_sample_profile_event("non_del_1", 0, (0, 1)),
225+
TestEventBlock._gen_sample_profile_event("non_del_1", 0, (0, 1)),
226+
]
227+
non_delegated_profile_events_2 = [
228+
TestEventBlock._gen_sample_profile_event("non_del_2", 1, (0, 1)),
229+
]
230+
non_delegated_event_1 = _gen_event_helper(non_delegated_profile_events_1)
231+
non_delegated_event_2 = _gen_event_helper(non_delegated_profile_events_2)
232+
233+
# Delegated
234+
delegated_profile_events_1 = [
235+
TestEventBlock._gen_sample_profile_event("del_1", 0, (0, 1), 10),
236+
TestEventBlock._gen_sample_profile_event("del_1", 0, (0, 1), 10),
237+
TestEventBlock._gen_sample_profile_event("del_1", 0, (0, 1), 10),
238+
]
239+
delegated_profile_events_2 = [
240+
TestEventBlock._gen_sample_profile_event("del_2", 2, (0, 1), 20),
241+
]
242+
delegated_event_1 = _gen_event_helper(delegated_profile_events_1)
243+
delegated_event_2 = _gen_event_helper(delegated_profile_events_2)
244+
245+
# Create Test EventBlock
246+
event_block = EventBlock(
247+
name="test_name_1",
248+
events=[
249+
non_delegated_event_1,
250+
non_delegated_event_2,
251+
delegated_event_1,
252+
delegated_event_2,
253+
],
254+
)
255+
256+
# Create Test Maps
257+
handle_map = {0: [100], 1: [110], 2: [120]}
258+
delegate_map = {
259+
0: DelegateMetadata(
260+
{
261+
"name": "delegate",
262+
"delegate_map": {10: (100, 1000)},
263+
}
264+
),
265+
2: DelegateMetadata(
266+
{
267+
"name": "delegate_2",
268+
"delegate_map": {20: (200,)},
269+
}
270+
),
271+
}
272+
event_block._gen_resolve_debug_handles(handle_map, delegate_map)
273+
274+
# Verify Results
275+
for event in event_block.events:
276+
# To satisfy type checker
277+
assert event.instruction_id is not None
278+
if (
279+
delegate_debug_identifier := event.delegate_debug_identifier
280+
) is not None:
281+
# Delegated
282+
metadata = delegate_map[event.instruction_id]
283+
self.assertEqual(event.delegate_backend_name, metadata["name"])
284+
self.assertEqual(
285+
event.debug_handles,
286+
metadata["delegate_map"][delegate_debug_identifier], # pyre-ignore
287+
)
288+
else:
289+
# Non Delegated
290+
self.assertEqual(event.debug_handles, handle_map[event.instruction_id])

0 commit comments

Comments
 (0)