Skip to content

Commit d7c4ccf

Browse files
tarun292facebook-github-bot
authored andcommitted
Adding EventTracer in runtime and support for it in Method (#232)
Summary: Pull Request resolved: #232 EventTracer is a class that users can inherit and implement to log/serialize/stream etc. the profiling and debugging events that are generated at runtime for a model. An example of this is the ETDump implementation in the SDK codebase that serializes these events to a flatbuffer. `ETDump` in the SDK folder will essentially be an implementation of this class serializing all this data to a flatbuffer. Reviewed By: dbort Differential Revision: D48743191 fbshipit-source-id: 290cd572c15286f3989bb22a2a1c45e3d5e99fb0
1 parent 9d134cb commit d7c4ccf

8 files changed

Lines changed: 215 additions & 10 deletions

File tree

runtime/core/event_tracer.h

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
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 <executorch/runtime/platform/platform.h>
10+
#include <stdlib.h>
11+
#include <cstdint>
12+
13+
#pragma once
14+
15+
namespace torch {
16+
namespace executor {
17+
18+
/// Represents an allocator id returned by track_allocator.
19+
typedef uint32_t AllocatorID;
20+
/// Represents the chain id that will be passed in by the user during
21+
/// event logging.
22+
typedef int32_t ChainID;
23+
/// Represents the debug handle that is generally associated with each
24+
/// op executed in the runtime.
25+
typedef uint32_t DebugHandle;
26+
27+
/// Default id's for chain id and debug handle.
28+
constexpr ChainID kUnsetChainId = -1;
29+
constexpr DebugHandle kUnsetDebugHandle = 0;
30+
31+
/**
32+
* This is the struct which should be returned when a profiling event is
33+
* started. This is used to uniquely identify that profiling event and will be
34+
* required to be passed into the end_profiling call to signal that the event
35+
* identified by this struct has completed.
36+
**/
37+
struct EventTracerEntry {
38+
/// An event id to uniquely identify this event that was generated during a
39+
/// call to start the tracking of an event.
40+
int64_t event_id;
41+
/// The chain to which this event belongs to.
42+
ChainID chain_id;
43+
/// The debug handle corresponding to this event.
44+
DebugHandle debug_handle;
45+
/// The time at which this event was started to be tracked.
46+
et_timestamp_t start_time;
47+
};
48+
49+
/**
50+
* EventTracer is a class that users can inherit and implement to
51+
* log/serialize/stream etc. the profiling and debugging events that are
52+
* generated at runtime for a model. An example of this is the ETDump
53+
* implementation in the SDK codebase that serializes these events to a
54+
* flatbuffer.
55+
*/
56+
class EventTracer {
57+
public:
58+
/**
59+
* Start a new event block (can consist of profiling and/or debugging events.)
60+
* identified by this name. A block is conceptually a set of events that we
61+
* want to group together. e.g. all the events that occur during the call to
62+
* execute() (i.e. model inference) could be categorized as a block.
63+
*
64+
* @param[in] name A human readable identifier for the event block. Users
65+
* calling this interface do not need to keep the memory pointed to by this
66+
* pointer around. The string must be copied over into internal memory during
67+
* this call.
68+
*/
69+
virtual void create_event_block(const char* name) = 0;
70+
71+
/**
72+
* Start the profiling of the event identified by name and debug_handle.
73+
* The user can pass in a chain_id and debug_handle to this call, or leave
74+
* them empty (default values) which would then result in the chain_id and
75+
* debug handle stored within (set by set_chain_debug_handle) this class to be
76+
* used.
77+
* @param[in] name Human readable name for the profiling event. Users calling
78+
* this interface do not need to keep the memory pointed to by this pointer
79+
* around. The string must be copied over into internal memory during this
80+
* call.
81+
* @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.
84+
* @param[in] debug_handle Debug handle generated ahead-of-time during model
85+
* compilation.
86+
*
87+
* @return Returns an instance of EventTracerEntry which should be passed back
88+
* into the end_profiling() call.
89+
*/
90+
virtual EventTracerEntry start_profiling(
91+
const char* name,
92+
ChainID chain_id = kUnsetChainId,
93+
DebugHandle debug_handle = kUnsetDebugHandle) = 0;
94+
95+
/**
96+
* End the profiling of the event identified by prof_entry
97+
*
98+
* @param[in] prof_entry Value returned by a call to start_profiling
99+
*/
100+
virtual void end_profiling(EventTracerEntry prof_entry) = 0;
101+
102+
/**
103+
* Track this allocation done via a MemoryAllocator which had profiling
104+
* enabled on it.
105+
*
106+
* @param[in] id Allocator id generated by a call to track_allocator.
107+
* @param[in] size The size of the allocation done, in bytes.
108+
*/
109+
virtual void track_allocation(AllocatorID id, size_t size) = 0;
110+
111+
/**
112+
* Generate an allocator id for this memory allocator that will be used in the
113+
* future to identify all the allocations done by this allocator.
114+
*
115+
* @param[in] name Human readable name for the allocator. Users calling
116+
* this interface do not need to keep the memory pointed to by this pointer
117+
* around. The string should be copied over into internal memory during this
118+
* call.
119+
*
120+
* @return Identifier to uniquely identify this allocator.
121+
*/
122+
virtual AllocatorID track_allocator(const char* name) = 0;
123+
124+
/**
125+
* Helper function to set the chain id ands debug handle. Users have two
126+
* options, the first is that they can directly pass in the chain id and debug
127+
* handle to start_profiling or they can explicitly set them through this
128+
* helper before calling start_profiling.
129+
*
130+
* The reason this helper exists is to
131+
* solve a specific problem. We want to do profiling logging inside the
132+
* codegen layer which calls the kernels. The problem though is that the
133+
* codegen layer doesn't have access to these ids when calling
134+
* start_profiling.
135+
*
136+
* Users should ideally use these within a RAII scope interface to make sure
137+
* that these values are unset after the end_profiling call. If non-default
138+
* values are passed into the start_profiling call they will always be given
139+
* precedence over the values set by this interface.
140+
*
141+
* So what we do is call this helper in method.cpp before
142+
* we hit the codegen layer and in the codegen layer we do a start_profiling
143+
* call without passing in a chain_id or debug_handle. This ensures that the
144+
* values set via this helper are the ones associated with that call.
145+
*
146+
* @param[in] chain_id Chain id of the current instruction being exectuted.
147+
* @param[in] debug_handle Debug handle of the current instruction being
148+
* executed. In this context debug handle and instruction id are the same
149+
* thing.
150+
*/
151+
void set_chain_debug_handle(ChainID chain_id, DebugHandle debug_handle) {
152+
chain_id_ = chain_id;
153+
debug_handle_ = debug_handle;
154+
}
155+
156+
ChainID get_current_chain_id() {
157+
return chain_id_;
158+
}
159+
160+
DebugHandle get_current_debug_handle() {
161+
return debug_handle_;
162+
}
163+
164+
virtual ~EventTracer() {}
165+
166+
protected:
167+
ChainID chain_id_ = kUnsetChainId;
168+
DebugHandle debug_handle_ = kUnsetDebugHandle;
169+
};
170+
171+
} // namespace executor
172+
} // namespace torch

runtime/core/targets.bzl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")
22

3+
def event_tracer_enabled():
4+
return native.read_config("executorch", "event_tracer_enabled", "false") == "true"
5+
6+
def get_event_tracer_flags():
7+
event_tracer_flags = []
8+
if event_tracer_enabled():
9+
event_tracer_flags += ["-DEVENT_TRACER_ENABLED"]
10+
return event_tracer_flags
11+
312
def define_common_targets():
413
"""Defines targets that should be shared between fbcode and xplat.
514
@@ -13,6 +22,7 @@ def define_common_targets():
1322
"array_ref.h", # TODO(T157717874): Migrate all users to span and then move this to portable_type
1423
"data_loader.h",
1524
"error.h",
25+
"event_tracer.h",
1626
"freeable_buffer.h",
1727
"function_ref.h",
1828
"result.h",
@@ -22,6 +32,7 @@ def define_common_targets():
2232
"//executorch/...",
2333
"@EXECUTORCH_CLIENTS",
2434
],
35+
exported_preprocessor_flags = get_event_tracer_flags(),
2536
exported_deps = [
2637
"//executorch/runtime/platform:platform",
2738
],

runtime/executor/executor.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
namespace torch {
2121
namespace executor {
2222

23-
Executor::Executor(const Program* program, MemoryManager* memory_manager)
24-
: program_(program), plan_(program, memory_manager) {}
23+
Executor::Executor(
24+
const Program* program,
25+
MemoryManager* memory_manager,
26+
EventTracer* event_tracer)
27+
: program_(program), plan_(program, memory_manager, event_tracer) {}
2528

2629
Error Executor::init_execution_plan(size_t index) {
2730
EXECUTORCH_SCOPE_PROF("ExecPlan::init_execution_plan");

runtime/executor/executor.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#pragma once
1010

11+
#include <executorch/runtime/core/event_tracer.h>
1112
#include <executorch/runtime/executor/memory_manager.h>
1213
#include <executorch/runtime/executor/method.h>
1314
#include <executorch/runtime/executor/program.h>
@@ -26,7 +27,10 @@ using ExecutionPlan __ET_DEPRECATED = Method;
2627
class __ET_DEPRECATED Executor {
2728
public:
2829
// Executes a PyTorch executor program.
29-
Executor(const Program* program, MemoryManager* memory_manager);
30+
Executor(
31+
const Program* program,
32+
MemoryManager* memory_manager,
33+
EventTracer* event_tracer = nullptr);
3034

3135
/**
3236
* DEPRECATED: Use `Program::load_method()` instead.

runtime/executor/method.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,9 @@ Error Method::resolve_operator(
487487
Result<Method> Method::load(
488488
executorch_flatbuffer::ExecutionPlan* s_plan,
489489
const Program* program,
490-
MemoryManager* memory_manager) {
491-
Method method(program, memory_manager);
490+
MemoryManager* memory_manager,
491+
EventTracer* event_tracer) {
492+
Method method(program, memory_manager, event_tracer);
492493
Error err = method.init(s_plan);
493494
if (err != Error::Ok) {
494495
return err;

runtime/executor/method.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#pragma once
1010

1111
#include <executorch/runtime/core/evalue.h>
12+
#include <executorch/runtime/core/event_tracer.h>
1213
#include <executorch/runtime/core/exec_aten/exec_aten.h>
1314
#include <executorch/runtime/executor/memory_manager.h>
1415
#include <executorch/runtime/platform/compiler.h>
@@ -46,11 +47,15 @@ using InstructionArgs = Span<EValue*>;
4647
*/
4748
class Method final {
4849
public:
49-
Method(const Program* program, MemoryManager* memory_manager)
50+
Method(
51+
const Program* program,
52+
MemoryManager* memory_manager,
53+
EventTracer* event_tracer)
5054
: step_state_(),
5155
program_(program),
5256
memory_manager_(memory_manager),
5357
serialization_plan_(nullptr),
58+
event_tracer_(event_tracer),
5459
n_value_(0),
5560
values_(nullptr),
5661
n_delegate_(0),
@@ -69,6 +74,7 @@ class Method final {
6974
program_(rhs.program_),
7075
memory_manager_(rhs.memory_manager_),
7176
serialization_plan_(rhs.serialization_plan_),
77+
event_tracer_(rhs.event_tracer_),
7278
n_value_(rhs.n_value_),
7379
values_(rhs.values_),
7480
n_delegate_(rhs.n_delegate_),
@@ -94,6 +100,7 @@ class Method final {
94100
rhs.n_chains_ = 0;
95101
rhs.chains_ = nullptr;
96102
rhs.pre_allocated_input_ = false;
103+
rhs.event_tracer_ = nullptr;
97104
}
98105

99106
/**
@@ -228,7 +235,8 @@ class Method final {
228235
__ET_NODISCARD static Result<Method> load(
229236
executorch_flatbuffer::ExecutionPlan* s_plan,
230237
const Program* program,
231-
MemoryManager* memory_manager);
238+
MemoryManager* memory_manager,
239+
EventTracer* event_tracer);
232240

233241
/// Returns true if the Method was successfully initialized.
234242
inline bool initialized() const {
@@ -242,6 +250,7 @@ class Method final {
242250
const Program* program_;
243251
MemoryManager* memory_manager_;
244252
executorch_flatbuffer::ExecutionPlan* serialization_plan_;
253+
EventTracer* event_tracer_;
245254

246255
size_t n_value_;
247256
EValue* values_;

runtime/executor/program.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,14 @@ Result<const char*> Program::get_method_name(size_t plan_index) const {
167167

168168
Result<Method> Program::load_method(
169169
const char* method_name,
170-
MemoryManager* memory_manager) const {
170+
MemoryManager* memory_manager,
171+
EventTracer* event_tracer) const {
171172
EXECUTORCH_SCOPE_PROF("Program::load_method");
172173
auto plan = get_execution_plan(internal_program_, method_name);
173174
if (!plan.ok()) {
174175
return plan.error();
175176
}
176-
return Method::load(plan.get(), this, memory_manager);
177+
return Method::load(plan.get(), this, memory_manager, event_tracer);
177178
}
178179

179180
Result<MethodMeta> Program::method_meta(const char* method_name) const {

runtime/executor/program.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <executorch/runtime/core/data_loader.h>
1515
#include <executorch/runtime/core/error.h>
16+
#include <executorch/runtime/core/event_tracer.h>
1617
#include <executorch/runtime/core/freeable_buffer.h>
1718
#include <executorch/runtime/core/result.h>
1819
#include <executorch/runtime/executor/memory_manager.h>
@@ -109,11 +110,14 @@ class Program final {
109110
* @param[in] method_name The name of the method to load.
110111
* @param[in] memory_manager The allocators to use during initialization and
111112
* execution of the loaded method.
113+
* @param[in] event_tracer The event tracer to use for this method run.
114+
*
112115
* @returns The loaded method on success, or an error on failure.
113116
*/
114117
Result<Method> load_method(
115118
const char* method_name,
116-
MemoryManager* memory_manager) const;
119+
MemoryManager* memory_manager,
120+
EventTracer* event_tracer = nullptr) const;
117121

118122
/**
119123
* Gathers metadata for the named method.

0 commit comments

Comments
 (0)