Skip to content

Commit cbce03c

Browse files
tarun292facebook-github-bot
authored andcommitted
Add support for delegate profiling in event_tracer
Summary: This diff should most probably be the final event_tracer diff that adds the user-facing API's for delegate profiling. `event_tracer_hooks_delegate.h` can be included by delegate authors in their backend runtime code to get access to these interfaces that will enable them to do profiling logging currently and debugging logging in the future. - Made changes to `event_tracer.h` to add the hooks to the `EventTracer` class. - Added `event_tracer_hooks_delegate.h` that contains the public interfaces that delegate authors can call into. Differential Revision: D49360145 fbshipit-source-id: 708dc81b369a56d2c990651963af93e473df6f42
1 parent aec81ab commit cbce03c

File tree

4 files changed

+257
-1
lines changed

4 files changed

+257
-1
lines changed

runtime/core/event_tracer.h

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ typedef uint32_t DebugHandle;
2828
constexpr ChainID kUnsetChainId = -1;
2929
constexpr DebugHandle kUnsetDebugHandle = 0;
3030

31+
/// Different types of delegate debug identifiers that are supported currently.
32+
enum DelegateDebugIdType {
33+
IDENTIFIER_NONE = 0,
34+
IDENTIFIER_INT = 1,
35+
IDENTIFIER_STR = 2
36+
};
37+
3138
/**
3239
* This is the struct which should be returned when a profiling event is
3340
* started. This is used to uniquely identify that profiling event and will be
@@ -44,8 +51,12 @@ struct EventTracerEntry {
4451
DebugHandle debug_handle;
4552
/// The time at which this event was started to be tracked.
4653
et_timestamp_t start_time;
54+
/// If this event doesn't represent a delegated event then this should be
55+
/// IDENTIFIER_NONE else it should be one of the other values in
56+
/// DelegateDebugIdType. The actual delegate debug id value will be stored in
57+
/// event_id.
58+
DelegateDebugIdType delegate_debug_id_type;
4759
};
48-
4960
/**
5061
* EventTracer is a class that users can inherit and implement to
5162
* log/serialize/stream etc. the profiling and debugging events that are
@@ -92,6 +103,65 @@ class EventTracer {
92103
ChainID chain_id = kUnsetChainId,
93104
DebugHandle debug_handle = kUnsetDebugHandle) = 0;
94105

106+
/**
107+
* Start the profiling of a delegate event. Similar to start_profiling it will
108+
* return an instance of EventTracerEntry that contains the details of this
109+
* event.
110+
*
111+
* @param[in] name Human readable name for the delegate event. This name has
112+
* to be the same name that was passed in during the Debug delegate mapping
113+
* generation in the export/ahead-of-time process. If indices and not names
114+
* are used by this delegate to identify ops executed in the backend then
115+
* nullptr can be passed in.
116+
* @param[in] delegate_debug_index The id of the delegate event. If string
117+
* based names are used by this delegate to identify ops executed in the
118+
* backend then -1 should be passed in here.
119+
*/
120+
virtual EventTracerEntry start_profiling_delegate(
121+
const char* name,
122+
DebugHandle delegate_debug_index) = 0;
123+
124+
/**
125+
* Signal the end of the delegate profiling event contained in
126+
* event_tracer_entry. Users also have the option to log some some free-from
127+
* string based metadata along with this.
128+
*
129+
* @param[in] event_tracer_entry The EventTracerEntry returned by a call to
130+
* start_profiling_delegate().
131+
* @param[in] metadata Optional free-form metadata associated with the
132+
* delegate event.
133+
*/
134+
virtual void end_profiling_delegate(
135+
EventTracerEntry event_tracer_entry,
136+
const char* metadata = nullptr) = 0;
137+
138+
/**
139+
* Some delegates get access to the profiling details only after the complete
140+
* graph has been executed. This interface is to support such use cases. It
141+
* can be called in a loop etc. to log any number of profiling events that are
142+
* part of this delegate.
143+
*
144+
* @param[in] name Human readable name for the delegate event. This name has
145+
* to be the same name that was passed in during the Debug delegate mapping
146+
* generation in the export/ahead-of-time process. If indices and not names
147+
* are used by this delegate to identify ops executed in the backend then
148+
* nullptr can be passed in.
149+
* @param[in] delegate_debug_index The id of the delegate event. If string
150+
* based names are used by this delegate to identify ops executed in the
151+
* backend then -1 should be passed in here.
152+
* @param[in] start_time The timestamp when the delegate event started.
153+
* @param[in] end_time The timestamp when the delegate event finished.
154+
* @param[in] metadata Optional data relevant to the execution that the user
155+
* wants to log along with this event. Pointer to metadata doesn't need to be
156+
* valid after the call to this function.
157+
*/
158+
virtual void log_profiling_delegate(
159+
const char* name,
160+
DebugHandle delegate_debug_index,
161+
et_timestamp_t start_time,
162+
et_timestamp_t end_time,
163+
const char* metadata = nullptr) = 0;
164+
95165
/**
96166
* End the profiling of the event identified by prof_entry
97167
*
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#pragma once
10+
11+
#include <executorch/runtime/core/event_tracer.h>
12+
13+
/**
14+
* @file
15+
*
16+
* This file contains the hooks that can be used by runtime delegate backend
17+
* authors to log profiling and debugging events from backend code. In order to
18+
* use these hooks delegate authors would have needed to generate a delegate
19+
* debug identifier mapping using the DelegateMappingBuilder library present in
20+
* executorch/exir/backend/utils.py. The delegate debug identifiers generated by
21+
* that library are the ones that need to be passed to these hooks to log
22+
* events. Using any other identifiers will cause post-processing of the events
23+
* data to not properly link back to the nodes in the original lowered graph.
24+
*
25+
* The benefit of defining these hooks is that we can easily control whether or
26+
* not we want to compile in the EventTracer code based on the status of the
27+
* ET_EVENT_TRACER_ENABLED flag.
28+
*/
29+
30+
namespace torch {
31+
namespace executor {
32+
33+
/**
34+
* Start the profiling of a delegate event. Similar to start_profiling it will
35+
* return an instance of EventTracerEntry that contains the details of this
36+
* event. Can be left in production code as these hooks compile conditionally.
37+
*
38+
* @param[in] event_tracer The event tracer instance that is doing the logging.
39+
* @param[in] name Human readable name for the delegate event. This name has
40+
* to be the same name that was passed in during the Debug delegate mapping
41+
* generation in the export/ahead-of-time process. If indices and not names
42+
* are used by this delegate to identify ops executed in the backend then
43+
* nullptr can be passed in.
44+
* @param[in] delegate_debug_index The id of the delegate event. If string
45+
* based names are used by this delegate to identify ops executed in the
46+
* backend then -1 should be passed in here.
47+
*/
48+
inline EventTracerEntry event_tracer_start_profiling_delegate(
49+
EventTracer* event_tracer,
50+
const char* name,
51+
DebugHandle delegate_debug_index) {
52+
#ifdef ET_EVENT_TRACER_ENABLED
53+
if (event_tracer) {
54+
return event_tracer->start_profiling_delegate(name, delegate_debug_index);
55+
}
56+
#else //! ET_EVENT_TRACER_ENABLED
57+
(void)name;
58+
(void)delegate_debug_index;
59+
#endif
60+
// There is no active tracer; this value will be ignored.
61+
return EventTracerEntry();
62+
}
63+
/**
64+
* Signal the end of the delegate profiling event contained in
65+
* event_tracer_entry. Users also have the option to log some some free-from
66+
* string based metadata along with this. Can be left in production code as
67+
* these hooks compile conditionally.
68+
*
69+
* @param[in] event_tracer The event tracer instance that is doing the logging.
70+
* @param[in] event_tracer_entry The EventTracerEntry returned by a call to
71+
* start_profiling_delegate().
72+
* @param[in] metadata Free-form metadata associated with the delegate event.
73+
*/
74+
inline void event_tracer_end_profiling_delegate(
75+
EventTracer* event_tracer,
76+
EventTracerEntry event_tracer_entry,
77+
const char* metadata = nullptr) {
78+
#ifdef ET_EVENT_TRACER_ENABLED
79+
if (event_tracer) {
80+
event_tracer->end_profiling_delegate(event_tracer_entry, metadata);
81+
}
82+
#else //! ET_EVENT_TRACER_ENABLED
83+
(void)event_tracer_entry;
84+
(void)metadata;
85+
#endif
86+
}
87+
88+
/**
89+
* Some delegates get access to the profiling details only after the complete
90+
* graph has been executed. This interface is to support such use cases. It
91+
* can be called in a loop etc. to log any number of profiling events that are
92+
* part of this delegate. Can be left in production code as these hooks
93+
* compile conditionally.
94+
*
95+
* @param[in] event_tracer The event tracer instance that is doing the logging.
96+
* @param[in] name Human readable name for the delegate event. This name has
97+
* to be the same name that was passed in during the Debug delegate mapping
98+
* generation in the export/ahead-of-time process. If indices and not names
99+
* are used by this delegate to identify ops executed in the backend then
100+
* nullptr can be passed in.
101+
* @param[in] delegate_debug_index The id of the delegate event. If string
102+
* based names are used by this delegate to identify ops executed in the
103+
* backend then -1 should be passed in here.
104+
* @param[in] start_time The timestamp when the delegate event started.
105+
* @param[in] end_time The timestamp when the delegate event finished.
106+
* @param[in] metadata Any extra data relevant to the execution that the user
107+
* wants to log along with this event. Pointer to metadata doesn't need to be
108+
* valid after the call to this function.
109+
*/
110+
inline void event_tracer_log_profiling_delegate(
111+
EventTracer* event_tracer,
112+
const char* name,
113+
DebugHandle delegate_debug_index,
114+
et_timestamp_t start_time,
115+
et_timestamp_t end_time,
116+
const char* metadata = nullptr) {
117+
#ifdef ET_EVENT_TRACER_ENABLED
118+
if (event_tracer) {
119+
event_tracer->log_profiling_delegate(
120+
name, delegate_debug_index, start_time, end_time, metadata);
121+
}
122+
#else //! ET_EVENT_TRACER_ENABLED
123+
(void)name;
124+
(void)delegate_debug_index;
125+
(void)start_time;
126+
(void)end_time;
127+
(void)metadata;
128+
#endif
129+
}
130+
131+
} // namespace executor
132+
} // namespace torch

runtime/core/targets.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def define_common_targets():
2424
"error.h",
2525
"event_tracer.h",
2626
"event_tracer_hooks.h",
27+
"event_tracer_hooks_delegate.h",
2728
"freeable_buffer.h",
2829
"function_ref.h",
2930
"result.h",

runtime/core/test/event_tracer_test.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// Enable flag for test
1313
#define ET_EVENT_TRACER_ENABLED
1414
#include <executorch/runtime/core/event_tracer_hooks.h>
15+
#include <executorch/runtime/core/event_tracer_hooks_delegate.h>
1516

1617
namespace torch {
1718
namespace executor {
@@ -54,6 +55,34 @@ class DummyEventTracer : public EventTracer {
5455
(void)name;
5556
return 0;
5657
}
58+
59+
EventTracerEntry start_profiling_delegate(
60+
const char* name,
61+
DebugHandle delegate_debug_index) override {
62+
(void)name;
63+
(void)delegate_debug_index;
64+
return EventTracerEntry();
65+
}
66+
67+
void end_profiling_delegate(
68+
EventTracerEntry event_tracer_entry,
69+
const char* metadata) override {
70+
(void)event_tracer_entry;
71+
(void)metadata;
72+
}
73+
74+
void log_profiling_delegate(
75+
const char* name,
76+
DebugHandle delegate_debug_index,
77+
et_timestamp_t start_time,
78+
et_timestamp_t end_time,
79+
const char* metadata = nullptr) override {
80+
(void)name;
81+
(void)delegate_debug_index;
82+
(void)start_time;
83+
(void)end_time;
84+
(void)metadata;
85+
}
5786
};
5887

5988
void RunSimpleTracerTest(EventTracer* event_tracer) {
@@ -86,6 +115,30 @@ TEST(TestEventTracer, SimpleEventTracerTest) {
86115
}
87116
}
88117

118+
void RunSimpleTracerTestDelegate(EventTracer* event_tracer) {
119+
EventTracerEntry event_tracer_entry =
120+
event_tracer_start_profiling_delegate(event_tracer, "test_event", -1);
121+
event_tracer_end_profiling_delegate(
122+
event_tracer, event_tracer_entry, nullptr);
123+
event_tracer_start_profiling_delegate(event_tracer, nullptr, 1);
124+
event_tracer_end_profiling_delegate(
125+
event_tracer, event_tracer_entry, "test_metadata");
126+
event_tracer_log_profiling_delegate(
127+
event_tracer, "test_event", -1, 0, 1, nullptr);
128+
event_tracer_log_profiling_delegate(event_tracer, nullptr, 1, 0, 1, nullptr);
129+
}
130+
131+
TEST(TestEventTracer, SimpleEventTracerTestDelegate) {
132+
// Call all the EventTracer macro's with a valid pointer to an event tracer
133+
// and also with a null pointer (to test that the null case works).
134+
DummyEventTracer dummy;
135+
std::vector<DummyEventTracer*> dummy_event_tracer_arr = {&dummy, nullptr};
136+
for (size_t i = 0; i < dummy_event_tracer_arr.size(); i++) {
137+
RunSimpleTracerTestDelegate(&dummy);
138+
RunSimpleTracerTestDelegate(nullptr);
139+
}
140+
}
141+
89142
} // namespace executor
90143
} // namespace torch
91144
// TODO : (T163645377) Add more test coverage to log and verify events passed

0 commit comments

Comments
 (0)