Skip to content

Commit bf5e6f9

Browse files
tarun292facebook-github-bot
authored andcommitted
Add support for delegate profiling in event_tracer
Differential Revision: D49360145 fbshipit-source-id: 1a73170869c459cb6c863721c31df56a5ef32938
1 parent 29db4df commit bf5e6f9

File tree

4 files changed

+294
-3
lines changed

4 files changed

+294
-3
lines changed

runtime/core/event_tracer.h

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ 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 class DelegateDebugIdType {
33+
/// Default value, indicates that it's not a delegate event.
34+
kNone,
35+
/// Indicates a delegate event logged using an integer delegate debug
36+
/// identifier.
37+
kInt,
38+
/// Indicates a delegate event logged using a string delegate debug
39+
/// identifier i.e. the delegate debug id is a pointer to a string table
40+
/// managed by the class implementing EventTracer functionality.
41+
kStr
42+
};
43+
3144
/**
3245
* This is the struct which should be returned when a profiling event is
3346
* started. This is used to uniquely identify that profiling event and will be
@@ -44,8 +57,16 @@ struct EventTracerEntry {
4457
DebugHandle debug_handle;
4558
/// The time at which this event was started to be tracked.
4659
et_timestamp_t start_time;
60+
/// When delegate_event_id_type != DelegateDebugIdType::kNone it indicates
61+
/// that event_id represents a delegate event. If delegate_event_id_type is:
62+
/// 1) kInt then event_id contains an integer delegate debug id.
63+
/// 2) kStr then event_id contains a string table index into a string table
64+
/// maintained by the class implementing EventTracer functionality that will
65+
/// give us the string identifier of this delegate event. For more details
66+
/// refer to the DelegateMappingBuilder library present in
67+
/// executorch/exir/backend/utils.py.
68+
DelegateDebugIdType delegate_event_id_type;
4769
};
48-
4970
/**
5071
* EventTracer is a class that users can inherit and implement to
5172
* log/serialize/stream etc. the profiling and debugging events that are
@@ -79,8 +100,9 @@ class EventTracer {
79100
* around. The string must be copied over into internal memory during this
80101
* call.
81102
* @param[in] chain_id The id of the chain to which this event belongs to. If
82-
* -1 is passed in the chain_id and debug_handle stored in the class
83-
* internally will be used.
103+
* kUnsetChainId is passed in the chain_id and kUnsetDebugHandle for
104+
* debug_handle then the values stored in the class internally for these
105+
* properties will be used.
84106
* @param[in] debug_handle Debug handle generated ahead-of-time during model
85107
* compilation.
86108
*
@@ -92,6 +114,73 @@ class EventTracer {
92114
ChainID chain_id = kUnsetChainId,
93115
DebugHandle debug_handle = kUnsetDebugHandle) = 0;
94116

117+
/**
118+
* Start the profiling of a delegate event. Similar to start_profiling it will
119+
* return an instance of EventTracerEntry that contains the details of this
120+
* event.
121+
*
122+
* @param[in] name Human readable name for the delegate event. This name has
123+
* to be the same name that was passed in during the Debug delegate mapping
124+
* generation in the export/ahead-of-time process. If indices and not names
125+
* are used by this delegate to identify ops executed in the backend then
126+
* nullptr can be passed in. Users calling this interface do not need to keep
127+
* the memory pointed to by this pointer around. The string must be copied
128+
* over into internal memory during this call.
129+
* @param[in] delegate_debug_index The id of the delegate event. If string
130+
* based names are used by this delegate to identify ops executed in the
131+
* backend then kUnsetDebugHandle should be passed in here.
132+
*/
133+
virtual EventTracerEntry start_profiling_delegate(
134+
const char* name,
135+
DebugHandle delegate_debug_index) = 0;
136+
137+
/**
138+
* Signal the end of the delegate profiling event contained in
139+
* event_tracer_entry. Users also have the option to log some some free-from
140+
* string based metadata along with this.
141+
*
142+
* @param[in] event_tracer_entry The EventTracerEntry returned by a call to
143+
* start_profiling_delegate().
144+
* @param[in] metadata Optional free-form metadata associated with the
145+
* delegate event. This should be a null terminated ASCII string. Users
146+
* calling this interface do not need to keep the memory pointed to by this
147+
* pointer around. The string must be copied over into internal memory during
148+
* this call.
149+
*/
150+
virtual void end_profiling_delegate(
151+
EventTracerEntry event_tracer_entry,
152+
const char* metadata = nullptr) = 0;
153+
154+
/**
155+
* Some delegates get access to the profiling details only after the complete
156+
* graph has been executed. This interface is to support such use cases. It
157+
* can be called in a loop etc. to log any number of profiling events that are
158+
* part of this delegate.
159+
*
160+
* @param[in] name Human readable name for the delegate event. This name has
161+
* to be the same name that was passed in during the Debug delegate mapping
162+
* generation in the export/ahead-of-time process. If indices and not names
163+
* are used by this delegate to identify ops executed in the backend then
164+
* nullptr can be passed in. Users calling this interface do not need to keep
165+
* the memory pointed to by this pointer around. The string must be copied
166+
* over into internal memory during this call.
167+
* @param[in] delegate_debug_index The id of the delegate event. If string
168+
* based names are used by this delegate to identify ops executed in the
169+
* backend then kUnsetDebugHandle should be passed in here.
170+
* @param[in] start_time The timestamp when the delegate event started.
171+
* @param[in] end_time The timestamp when the delegate event finished.
172+
* @param[in] metadata Optional data relevant to the execution that the user
173+
* wants to log along with this event. Pointer to metadata doesn't need to be
174+
* valid after the call to this function. This should be a null terminated
175+
* ASCII string.
176+
*/
177+
virtual void log_profiling_delegate(
178+
const char* name,
179+
DebugHandle delegate_debug_index,
180+
et_timestamp_t start_time,
181+
et_timestamp_t end_time,
182+
const char* metadata = nullptr) = 0;
183+
95184
/**
96185
* End the profiling of the event identified by prof_entry
97186
*
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
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. Users calling this interface do not need to keep
44+
* the memory pointed to by this pointer around. The string must be copied over
45+
* into internal memory during this call.
46+
* @param[in] delegate_debug_id The id of the delegate event. If string
47+
* based names are used by this delegate to identify ops executed in the
48+
* backend then kUnsetDebugHandle should be passed in here.
49+
*/
50+
inline EventTracerEntry event_tracer_start_profiling_delegate(
51+
EventTracer* event_tracer,
52+
const char* name,
53+
DebugHandle delegate_debug_id) {
54+
#ifdef ET_EVENT_TRACER_ENABLED
55+
if (event_tracer) {
56+
return event_tracer->start_profiling_delegate(name, delegate_debug_id);
57+
}
58+
#else //! ET_EVENT_TRACER_ENABLED
59+
(void)name;
60+
(void)delegate_debug_id;
61+
#endif
62+
// There is no active tracer; this value will be ignored.
63+
return EventTracerEntry();
64+
}
65+
/**
66+
* Signal the end of the delegate profiling event contained in
67+
* event_tracer_entry. Users also have the option to log some some free-from
68+
* string based metadata along with this. Can be left in production code as
69+
* these hooks compile conditionally.
70+
*
71+
* @param[in] event_tracer The event tracer instance that is doing the logging.
72+
* @param[in] event_tracer_entry The EventTracerEntry returned by a call to
73+
* start_profiling_delegate().
74+
* @param[in] metadata Free-form metadata associated with the delegate event.
75+
* Users calling this interface do not need to keep the memory pointed to by
76+
* this pointer around. The string must be copied over into internal memory
77+
* during this call. The input string must also be null terminated.
78+
*/
79+
inline void event_tracer_end_profiling_delegate(
80+
EventTracer* event_tracer,
81+
EventTracerEntry event_tracer_entry,
82+
const char* metadata = nullptr) {
83+
#ifdef ET_EVENT_TRACER_ENABLED
84+
if (event_tracer) {
85+
event_tracer->end_profiling_delegate(event_tracer_entry, metadata);
86+
}
87+
#else //! ET_EVENT_TRACER_ENABLED
88+
(void)event_tracer_entry;
89+
(void)metadata;
90+
#endif
91+
}
92+
93+
/**
94+
* Some delegates get access to the profiling details only after the complete
95+
* graph has been executed. This interface is to support such use cases. It
96+
* can be called in a loop etc. to log any number of profiling events that are
97+
* part of this delegate. Can be left in production code as these hooks
98+
* compile conditionally.
99+
*
100+
* @param[in] event_tracer The event tracer instance that is doing the logging.
101+
* @param[in] name Human readable name for the delegate event. This name has
102+
* to be the same name that was passed in during the Debug delegate mapping
103+
* generation in the export/ahead-of-time process. If indices and not names
104+
* are used by this delegate to identify ops executed in the backend then
105+
* nullptr can be passed in. Users calling this interface do not need to keep
106+
* the memory pointed to by this pointer around. The string must
107+
* be copied over into internal memory during this call.
108+
* @param[in] delegate_debug_id The id of the delegate event. If string
109+
* based names are used by this delegate to identify ops executed in the
110+
* backend then -1 should be passed in here.
111+
* @param[in] start_time The timestamp when the delegate event started.
112+
* @param[in] end_time The timestamp when the delegate event finished.
113+
* @param[in] metadata Any extra data relevant to the execution that the user
114+
* wants to log along with this event. Pointer to metadata doesn't need to be
115+
* valid after the call to this function. Users calling this interface do not
116+
* need to keep the memory pointed to by this pointer around. The string must
117+
* be copied over into internal memory during this call. The input string must
118+
* also be a null terminated.
119+
*/
120+
inline void event_tracer_log_profiling_delegate(
121+
EventTracer* event_tracer,
122+
const char* name,
123+
DebugHandle delegate_debug_id,
124+
et_timestamp_t start_time,
125+
et_timestamp_t end_time,
126+
const char* metadata = nullptr) {
127+
#ifdef ET_EVENT_TRACER_ENABLED
128+
if (event_tracer) {
129+
event_tracer->log_profiling_delegate(
130+
name, delegate_debug_id, start_time, end_time, metadata);
131+
}
132+
#else //! ET_EVENT_TRACER_ENABLED
133+
(void)name;
134+
(void)delegate_debug_id;
135+
(void)start_time;
136+
(void)end_time;
137+
(void)metadata;
138+
#endif
139+
}
140+
141+
} // namespace executor
142+
} // 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: 59 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,8 +55,39 @@ 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_id) override {
62+
(void)name;
63+
(void)delegate_debug_id;
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_id,
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_id;
82+
(void)start_time;
83+
(void)end_time;
84+
(void)metadata;
85+
}
5786
};
5887

88+
/**
89+
* Exercise all the event_tracer API's for a basic sanity check.
90+
*/
5991
void RunSimpleTracerTest(EventTracer* event_tracer) {
6092
event_tracer_create_event_block(event_tracer, "ExampleEvent");
6193
event_tracer_create_event_block(event_tracer, "ExampleEvent");
@@ -86,6 +118,33 @@ TEST(TestEventTracer, SimpleEventTracerTest) {
86118
}
87119
}
88120

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

0 commit comments

Comments
 (0)