Skip to content

Commit 5aaf289

Browse files
tarun292facebook-github-bot
authored andcommitted
Add support for delegate profiling in event_tracer
Differential Revision: D49360145 fbshipit-source-id: 47b04ac17bce6d5171c3bd00e9deaf7374678190
1 parent 68bcfab commit 5aaf289

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)