Skip to content

Commit 1bf2ff4

Browse files
tarun292facebook-github-bot
authored andcommitted
Add macros and helper classes in event_tracer needed for profiling (#294)
Summary: Pull Request resolved: #294 All the internal invocations (inside ExecuTorch codebase) of event_tracer will be controlled through the macros added in this diff. The benefit of this is that we can leave these hooks in the hot path and when the flag is disabled they essentially compile to a no-op in prod releases. It's also ensured that in all these macros if we pass in a `nullptr` as event_tracer (default case if user doesn't pass in one when method is created) we just return immediately. The specific macros added here are only meant to be used inside the ExecuTorch codebase as the header explains. Reviewed By: dbort Differential Revision: D49204729 fbshipit-source-id: 9bd2945ad94a5064aab6076210346b14ed9bcf11
1 parent 31aaa12 commit 1bf2ff4

File tree

4 files changed

+289
-1
lines changed

4 files changed

+289
-1
lines changed

runtime/core/event_tracer_hooks.h

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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 are inserted across various parts of the
17+
* core runtime code to call into the EventTracer class for logging of profiling
18+
* and debugging events. Any calls made to the EventTracer from the runtime must
19+
* be made via these hooks.
20+
* Users shouldn't directly add these hooks in their code and it's meant only
21+
* for usage in ExecuTorch internal code.
22+
*
23+
* The benefit of defining these hooks is that we can easily control whether or
24+
* not we want to compile in the EventTracer code based on the status of the
25+
* ET_EVENT_TRACER_ENABLED flag.
26+
*/
27+
28+
namespace torch {
29+
namespace executor {
30+
namespace internal {
31+
32+
/**
33+
* This class enables scope based profiling where needed using RAII.
34+
* Profiling will be started when the object is created and will end
35+
* when the object goes out of scope.
36+
*/
37+
class EventTracerProfileScope final {
38+
public:
39+
EventTracerProfileScope(EventTracer* event_tracer, const char* name) {
40+
event_tracer_ = event_tracer;
41+
if (event_tracer_ == nullptr) {
42+
return;
43+
}
44+
event_entry_ = event_tracer->start_profiling(name);
45+
}
46+
47+
~EventTracerProfileScope() {
48+
if (event_tracer_ == nullptr) {
49+
return;
50+
}
51+
event_tracer_->end_profiling(event_entry_);
52+
}
53+
54+
private:
55+
EventTracer* event_tracer_;
56+
EventTracerEntry event_entry_;
57+
};
58+
59+
/**
60+
* This class helps us set and then clear out the chain id and debug handle
61+
* values stored in the event tracer class using RAII. This is typically called
62+
* in the executor loop before entering the codegen layer to configure the chain
63+
* id and debug handle of the current instruction being executed.
64+
* After we return from the kernel execution we can then reset the chain id and
65+
* debug handle to defaults when this object goes out of scope.
66+
*/
67+
class EventTracerProfileInstructionScope final {
68+
public:
69+
EventTracerProfileInstructionScope(
70+
EventTracer* event_tracer,
71+
ChainID chain_idx,
72+
DebugHandle debug_handle) {
73+
event_tracer_ = event_tracer;
74+
if (event_tracer_ == nullptr) {
75+
return;
76+
}
77+
event_tracer_->set_chain_debug_handle(chain_idx, debug_handle);
78+
}
79+
80+
~EventTracerProfileInstructionScope() {
81+
if (event_tracer_ == nullptr) {
82+
return;
83+
}
84+
event_tracer_->set_chain_debug_handle(kUnsetChainId, kUnsetDebugHandle);
85+
}
86+
87+
private:
88+
EventTracer* event_tracer_;
89+
};
90+
91+
/**
92+
* Create a new event block with the specified name. Any events logged
93+
* after this will be associated with this new event block.
94+
*/
95+
inline void event_tracer_create_event_block(
96+
EventTracer* event_tracer,
97+
char const* name) {
98+
#ifdef ET_EVENT_TRACER_ENABLED
99+
if (event_tracer) {
100+
event_tracer->create_event_block(name);
101+
}
102+
#else //! ET_EVENT_TRACER_ENABLED
103+
(void)event_tracer;
104+
(void)name;
105+
#endif
106+
}
107+
108+
/**
109+
* Explicitly mark the beginning of a new profiling event. This returns
110+
* an instance of an EventTracerEntry object that the user needs to keep
111+
* around and pass into the corresponding event_tracer_end_profiling_event
112+
* call.
113+
*/
114+
inline EventTracerEntry event_tracer_begin_profiling_event(
115+
EventTracer* event_tracer,
116+
char const* name) {
117+
EventTracerEntry event_tracer_entry;
118+
#ifdef ET_EVENT_TRACER_ENABLED
119+
if (event_tracer) {
120+
event_tracer_entry = event_tracer->start_profiling(name);
121+
}
122+
#else //! ET_EVENT_TRACER_ENABLED
123+
(void)event_tracer;
124+
(void)name;
125+
#endif
126+
// There is no active tracer; this value will be ignored.
127+
return event_tracer_entry;
128+
}
129+
130+
/**
131+
* Mark the end of a profiling event passing in the entry token
132+
* returned by a previous call to ET_EVENT_TRACER_BEGIN_PROFILING_EVENT.
133+
*/
134+
inline void event_tracer_end_profiling_event(
135+
EventTracer* event_tracer,
136+
EventTracerEntry event) {
137+
#ifdef ET_EVENT_TRACER_ENABLED
138+
if (event_tracer) {
139+
event_tracer->end_profiling(event);
140+
}
141+
#else //! ET_EVENT_TRACER_ENABLED
142+
(void)event_tracer;
143+
(void)event;
144+
#endif
145+
}
146+
147+
/**
148+
* Start the tracking of the allocator represented by this name and returns
149+
* an AllocatorID that will be used to track all subsequent allocations done by
150+
* this allocator.
151+
*/
152+
inline AllocatorID event_tracer_track_allocator(
153+
EventTracer* event_tracer,
154+
const char* name) {
155+
#ifdef ET_EVENT_TRACER_ENABLED
156+
if (event_tracer) {
157+
return event_tracer->track_allocator(name);
158+
}
159+
#else //! ET_EVENT_TRACER_ENABLED
160+
(void)event_tracer;
161+
(void)name;
162+
#endif
163+
// There is no active tracer; this value will be ignored.
164+
return 0;
165+
}
166+
167+
/// Log the allocation event done via the allocator represented by id.
168+
inline void event_tracer_track_allocation(
169+
EventTracer* event_tracer,
170+
AllocatorID id,
171+
size_t size) {
172+
#ifdef ET_EVENT_TRACER_ENABLED
173+
if (event_tracer) {
174+
event_tracer->track_allocation(id, size);
175+
}
176+
#else //! ET_EVENT_TRACER_ENABLED
177+
(void)event_tracer;
178+
(void)id;
179+
(void)size;
180+
#endif
181+
}
182+
183+
} // namespace internal
184+
} // namespace executor
185+
} // namespace torch

runtime/core/targets.bzl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def event_tracer_enabled():
66
def get_event_tracer_flags():
77
event_tracer_flags = []
88
if event_tracer_enabled():
9-
event_tracer_flags += ["-DEVENT_TRACER_ENABLED"]
9+
event_tracer_flags += ["-DET_EVENT_TRACER_ENABLED"]
1010
return event_tracer_flags
1111

1212
def define_common_targets():
@@ -23,6 +23,7 @@ def define_common_targets():
2323
"data_loader.h",
2424
"error.h",
2525
"event_tracer.h",
26+
"event_tracer_hooks.h",
2627
"freeable_buffer.h",
2728
"function_ref.h",
2829
"result.h",
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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+
#include <gtest/gtest.h>
10+
11+
#include <executorch/runtime/core/event_tracer.h>
12+
// Enable flag for test
13+
#define ET_EVENT_TRACER_ENABLED
14+
#include <executorch/runtime/core/event_tracer_hooks.h>
15+
16+
namespace torch {
17+
namespace executor {
18+
19+
using namespace internal;
20+
21+
class DummyEventTracer : public EventTracer {
22+
public:
23+
DummyEventTracer() {}
24+
25+
~DummyEventTracer() override {}
26+
27+
void create_event_block(const char* name) override {
28+
(void)name;
29+
return;
30+
}
31+
32+
EventTracerEntry start_profiling(
33+
const char* name,
34+
ChainID chain_id = kUnsetChainId,
35+
DebugHandle debug_handle = kUnsetDebugHandle) override {
36+
(void)name;
37+
(void)chain_id;
38+
(void)debug_handle;
39+
return EventTracerEntry();
40+
}
41+
42+
void end_profiling(EventTracerEntry prof_entry) override {
43+
(void)prof_entry;
44+
return;
45+
}
46+
47+
void track_allocation(AllocatorID id, size_t size) override {
48+
(void)id;
49+
(void)size;
50+
return;
51+
}
52+
53+
AllocatorID track_allocator(const char* name) override {
54+
(void)name;
55+
return 0;
56+
}
57+
};
58+
59+
void RunSimpleTracerTest(EventTracer* event_tracer) {
60+
event_tracer_create_event_block(event_tracer, "ExampleEvent");
61+
event_tracer_create_event_block(event_tracer, "ExampleEvent");
62+
EventTracerEntry event_entry =
63+
event_tracer_begin_profiling_event(event_tracer, "ExampleEvent");
64+
event_tracer_end_profiling_event(event_tracer, event_entry);
65+
{
66+
EventTracerProfileScope event_tracer_profile_scope(
67+
event_tracer, "ExampleScope");
68+
}
69+
{
70+
EventTracerProfileInstructionScope event_tracer_profile_instruction_scope(
71+
event_tracer, 0, 1);
72+
}
73+
AllocatorID allocator_id =
74+
event_tracer_track_allocator(event_tracer, "AllocatorName");
75+
event_tracer_track_allocation(event_tracer, allocator_id, 64);
76+
}
77+
78+
TEST(TestEventTracer, SimpleEventTracerTest) {
79+
// Call all the EventTracer macro's with a valid pointer to an event tracer
80+
// and also with a null pointer (to test that the null case works).
81+
DummyEventTracer dummy;
82+
std::vector<DummyEventTracer*> dummy_event_tracer_arr = {&dummy, nullptr};
83+
for (size_t i = 0; i < dummy_event_tracer_arr.size(); i++) {
84+
RunSimpleTracerTest(&dummy);
85+
RunSimpleTracerTest(nullptr);
86+
}
87+
}
88+
89+
} // namespace executor
90+
} // namespace torch
91+
// TODO : (T163645377) Add more test coverage to log and verify events passed
92+
// into DummyTracer.

runtime/core/test/targets.bzl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ def define_common_targets():
3535
],
3636
)
3737

38+
runtime.cxx_test(
39+
name = "event_tracer_test",
40+
srcs = [
41+
"event_tracer_test.cpp",
42+
],
43+
deps = [
44+
"//executorch/runtime/core:core",
45+
],
46+
)
47+
3848
runtime.cxx_test(
3949
name = "freeable_buffer_test",
4050
srcs = [

0 commit comments

Comments
 (0)