Skip to content

Commit 2ce7329

Browse files
Jack-Khuufacebook-github-bot
authored andcommitted
Delegate Integration with SDK Documentation (#643)
Summary: Pull Request resolved: #643 ^^^ Original Doc: https://docs.google.com/document/d/1v_oL_yXGF7UyPPJTe_btt8SeItivV58vaSrazyEQ37I/edit Reviewed By: tarun292 Differential Revision: D49968371 fbshipit-source-id: 1776c4d347f94341731dc902e5c86d805580bdfb
1 parent 144c8c4 commit 2ce7329

File tree

1 file changed

+119
-1
lines changed

1 file changed

+119
-1
lines changed
Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,121 @@
11
# Delegate Integration
22

3-
TBA
3+
[Delegate backends](compiler-delegate-and-partitioner.md) are a prominent component of on-device models due to their flexibility in defining behavior. A side effect of this flexibility is that it operates as an opaque transformation. This obfuscates rich associations and mutations that are valuable in post-processing.
4+
- For example, if two different operator fusions were to occur within a delegate, post processing wouldn’t be able to separate the two transformations.
5+
6+
Specifically, it makes associating runtime information (such as profiling results) through delegated graphs difficult. Delegate Debug Identifiers provides a framework through which delegate authors can propagate this information and utilize it for post run analysis.
7+
8+
The preparation is broken down into two stages:
9+
- **Ahead-of-time (AOT)**: Delegate authors generate a __Debug Handle Map__.
10+
- **Runtime**: Delegate authors log using the __Delegate Debug Identifiers__ registered AOT in the __Debug Handle Map__.
11+
12+
## Ahead-of-Time
13+
Delegate authors propagate what transformations occur in a lowered backend by returning a **Debug Handle Map** from the backend implementation.
14+
15+
### Generating a Debug Handle Map
16+
**Debug Handle Maps** communicate what transformations occurred in a backend by mapping **Delegate Debug Identifiers** to debug handles.
17+
18+
**Delegate Debug Identifiers** are generated or user-provided identifiers for representing points of interest during runtime. Recall that debug handles are unique identifiers to operator instances in the model graph.
19+
20+
For example:
21+
- **{ 0: (10, 11), 1: (11, 12) }:** Identifiers 0 and 1 in the runtime correspond to operators with the debug handles (10, 11) and (11, 12) respectively.
22+
- **{ “Fancy Fusion”: (11, 12, 15) }**: Identifier “Fancy Fusion” in the runtime corresponds to operators with debug handles (11, 12, 15).
23+
24+
```{Note}
25+
Identifiers are a means of connecting runtime results to the model graph; the interpretation of the identifiers is defined by the delegate author.*
26+
```
27+
28+
**Debug Handle Maps** are constructed through the use of **DelegateMappingBuilder** and returned as a part of `PreprocessResult`.
29+
30+
```python
31+
class PreprocessResult:
32+
processed_bytes: bytes = bytes()
33+
34+
debug_handle_map: Optional[
35+
Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]
36+
] = None
37+
```
38+
PreprocessResult is defined [here](https://github.com/pytorch/executorch/blob/main/exir/backend/backend_details.py).
39+
40+
#### DelegateMappingBuilder
41+
`DelegateMappingBuilder` is a helper class for managing and constructing Debug Handle Maps. The result of the builder should be passed in when constructing PreprocessResult.
42+
43+
`DelegateMappingBuilder` is defined [here](https://github.com/pytorch/executorch/blob/main/exir/backend/utils.py)
44+
45+
A `DelegateMappingBuilder` instance can be constructed in one of 2 modes: manual identifiers or generated identifiers.
46+
47+
```python
48+
# Manual Identifiers, Default
49+
builder = DelegateMappingBuilder(generated_identifiers=False)
50+
51+
# Generated Identifiers
52+
builder = DelegateMappingBuilder(generated_identifiers=True)
53+
```
54+
55+
With **manual identifiers**, users pass in a **Delegate Debug Identifier** when creating entries.
56+
With **generated identifiers**, the builder will auto-assign a **Delegate Debug Identifier**.
57+
58+
To add an entry to the **Debug Handle Map**, use `insert_delegate_mapping_entry`. It takes `fx.Node(s)` to associate and an optional **Delegate Debug Identifier** (used for the manual identifiers). The identifier recorded is returned from the call.
59+
60+
```python
61+
def insert_delegate_mapping_entry(
62+
self,
63+
nodes: Union[fx.Node, List[fx.Node]],
64+
identifier: Optional[Union[int, str]] = None,
65+
) -> Union[int, str]:
66+
```
67+
68+
To retrieve the **Debug Handle Map**, use `get_delegate_mapping`.
69+
```python
70+
def get_delegate_mapping(
71+
self,
72+
) -> Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]
73+
```
74+
75+
A demo of the AOT mapping can be found [here](https://github.com/pytorch/executorch/blob/main/exir/backend/test/backend_with_delegate_mapping_demo.py)
76+
77+
78+
## Runtime
79+
Corresponding to the AOT map, the runtime then defines the functionality through which these events are logged.
80+
81+
### Real-Time Logging
82+
83+
ExecuTorch allows you to log in real time. **Real time Logging** is useful when timestamps are available as the execution occurs. It provides minimal overhead and is intuitive for authors to call.
84+
85+
To log events in real-time (for example, explicitly denoting the profiling start and stop), `event_tracer_start_profiling_delegate` is used to create an `EventEntry` and `event_tracer_end_profiling_delegate` is used to conclude the `EventEntry` for the provided `EventTracer`.
86+
87+
To start an `EventTracerEntry` using `event_tracer_start_profiling_delegate`, the **Delegate Debug Identifier** (provided AOT to the `debug_handle_map`) is passed as either the name or `delegate_debug_id` argument depending on the **Delegate Debug Identifier** type (str and int respectively)
88+
89+
```c++
90+
EventTracerEntry event_tracer_start_profiling_delegate(
91+
EventTracer* event_tracer,
92+
const char* name,
93+
DebugHandle delegate_debug_id)
94+
```
95+
96+
To conclude an `EventTracerEntry`, `event_tracer_end_profiling_delegate` is simply provided the original `EventTracerEntry`.
97+
98+
Optionally, additional runtime `metadata` can also be logged at this point.
99+
100+
```c++
101+
void event_tracer_end_profiling_delegate(
102+
EventTracer* event_tracer,
103+
EventTracerEntry event_tracer_entry,
104+
const char* metadata = nullptr)
105+
```
106+
107+
### Post-Time Logging
108+
ExecuTorch also allows you to log in post time. Some runtime settings don't have access to timestamps while it is executing. **Post-Time Logging** enables authors to still be able to log these events.
109+
110+
To log events in post (for example, logging start and end time simultaneously) `event_tracer_log_profiling_delegate` is called with a combination of the arguments used in the real-time logging API’s and timestamps.
111+
112+
```c++
113+
void event_tracer_log_profiling_delegate(
114+
EventTracer* event_tracer,
115+
const char* name,
116+
DebugHandle delegate_debug_id,
117+
et_timestamp_t start_time,
118+
et_timestamp_t end_time,
119+
const char* metadata = nullptr)
120+
```
121+
A demo of the runtime code can be found [here](https://github.com/pytorch/executorch/blob/main/runtime/executor/test/test_backend_with_delegate_mapping.cpp).

0 commit comments

Comments
 (0)