Skip to content

Commit 14fb389

Browse files
tarun292facebook-github-bot
authored andcommitted
Add option to disable operator profiling (#5720)
Summary: X-link: pytorch/pytorch#136838 For smaller models the overhead of profiling ops might be prohibitively large (distorting the inference execution time significantly) so we provide users an option to disable op profiling and essentially only profile the important events such as inference execution time. To disable operator profiling users need to do: ``` etdump_gen.set_event_tracer_profiling_level(executorch::runtime::EventTracerProfilingLevel::kNoOperatorProfiling); ``` Differential Revision: D61883224
1 parent 3aa6b14 commit 14fb389

File tree

5 files changed

+150
-26
lines changed

5 files changed

+150
-26
lines changed

runtime/core/event_tracer.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,19 @@ enum class EventTracerDebugLogLevel {
6767
kIntermediateOutputs,
6868
};
6969

70+
/**
71+
* Indicates the level of profiling that should be enabled. Profiling
72+
* events will be logged in increasing order of verbosity as we go down the
73+
* enum list. Thus it is important to keep the enum values in the right order.
74+
*/
75+
76+
enum class EventTracerProfilingLevel {
77+
/// No operator profiling.
78+
kProfileMethodOnly,
79+
/// All profiling events enabled.
80+
kProfileAllEvents,
81+
};
82+
7083
/**
7184
* This is the struct which should be returned when a profiling event is
7285
* started. This is used to uniquely identify that profiling event and will be
@@ -423,6 +436,21 @@ class EventTracer {
423436
return event_tracer_debug_level_;
424437
}
425438

439+
/**
440+
* Set the level of event tracer profiling that is desired.
441+
*/
442+
void set_event_tracer_profiling_level(
443+
EventTracerProfilingLevel profiling_level) {
444+
event_tracer_profiling_level_ = profiling_level;
445+
}
446+
447+
/**
448+
* Return the current level of event tracer profiling.
449+
*/
450+
EventTracerProfilingLevel event_tracer_profiling_level() {
451+
return event_tracer_profiling_level_;
452+
}
453+
426454
/**
427455
* Return the current status of intermediate outputs logging mode.
428456
*/
@@ -458,6 +486,8 @@ class EventTracer {
458486
int bundled_input_index_ = kUnsetBundledInputIndex;
459487
EventTracerDebugLogLevel event_tracer_debug_level_ =
460488
EventTracerDebugLogLevel::kNoLogging;
489+
EventTracerProfilingLevel event_tracer_profiling_level_ =
490+
EventTracerProfilingLevel::kProfileAllEvents;
461491
};
462492

463493
} // namespace runtime

runtime/core/event_tracer_hooks.h

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,56 @@ namespace executorch {
3333
namespace runtime {
3434
namespace internal {
3535

36+
/**
37+
* This class enables scope based profiling where needed using RAII for
38+
* operators only. If operator profiling is disabled then this class is a no-op.
39+
*/
40+
class EventTracerProfileOpScope final {
41+
public:
42+
EventTracerProfileOpScope(EventTracer* event_tracer, const char* name) {
43+
#ifdef ET_EVENT_TRACER_ENABLED
44+
event_tracer_ = event_tracer;
45+
if (event_tracer_ == nullptr) {
46+
return;
47+
}
48+
if (event_tracer_->event_tracer_profiling_level() >
49+
executorch::runtime::EventTracerProfilingLevel::kProfileMethodOnly) {
50+
event_entry_ = event_tracer->start_profiling(name);
51+
}
52+
#else //! ET_EVENT_TRACER_ENABLED
53+
(void)event_tracer;
54+
(void)name;
55+
#endif
56+
}
57+
58+
~EventTracerProfileOpScope() {
59+
#ifdef ET_EVENT_TRACER_ENABLED
60+
if (event_tracer_ == nullptr) {
61+
return;
62+
}
63+
if (event_tracer_->event_tracer_profiling_level() >
64+
executorch::runtime::EventTracerProfilingLevel::kProfileMethodOnly) {
65+
event_tracer_->end_profiling(event_entry_);
66+
}
67+
#endif
68+
}
69+
70+
private:
71+
#ifdef ET_EVENT_TRACER_ENABLED
72+
EventTracer* event_tracer_;
73+
EventTracerEntry event_entry_;
74+
#endif
75+
};
76+
3677
/**
3778
* This class enables scope based profiling where needed using RAII.
3879
* Profiling will be started when the object is created and will end
39-
* when the object goes out of scope.
80+
* when the object goes out of scope. This is specifically intended to
81+
* be used for profiling methods in the runtime.
4082
*/
41-
class EventTracerProfileScope final {
83+
class EventTracerProfileMethodScope final {
4284
public:
43-
EventTracerProfileScope(EventTracer* event_tracer, const char* name) {
85+
EventTracerProfileMethodScope(EventTracer* event_tracer, const char* name) {
4486
#ifdef ET_EVENT_TRACER_ENABLED
4587
event_tracer_ = event_tracer;
4688
if (event_tracer_ == nullptr) {
@@ -53,7 +95,7 @@ class EventTracerProfileScope final {
5395
#endif
5496
}
5597

56-
~EventTracerProfileScope() {
98+
~EventTracerProfileMethodScope() {
5799
#ifdef ET_EVENT_TRACER_ENABLED
58100
if (event_tracer_ == nullptr) {
59101
return;
@@ -111,6 +153,13 @@ class EventTracerProfileInstructionScope final {
111153
#endif
112154
};
113155

156+
inline bool event_tracer_enabled() {
157+
#ifdef ET_EVENT_TRACER_ENABLED
158+
return true;
159+
#else //! ET_EVENT_TRACER_ENABLED
160+
return false;
161+
#endif
162+
}
114163
/**
115164
* Create a new event block with the specified name. Any events logged
116165
* after this will be associated with this new event block.
@@ -271,7 +320,8 @@ using ::executorch::runtime::internal::event_tracer_set_bundled_input_index;
271320
using ::executorch::runtime::internal::event_tracer_track_allocation;
272321
using ::executorch::runtime::internal::event_tracer_track_allocator;
273322
using ::executorch::runtime::internal::EventTracerProfileInstructionScope;
274-
using ::executorch::runtime::internal::EventTracerProfileScope;
323+
using ::executorch::runtime::internal::EventTracerProfileMethodScope;
324+
using ::executorch::runtime::internal::EventTracerProfileOpScope;
275325
} // namespace internal
276326
} // namespace executor
277327
} // namespace torch

runtime/core/test/event_tracer_test.cpp

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,16 @@ class DummyEventTracer : public EventTracer {
4444
const char* name,
4545
ChainID chain_id = kUnsetChainId,
4646
DebugHandle debug_handle = kUnsetDebugHandle) override {
47-
(void)name;
4847
(void)chain_id;
4948
(void)debug_handle;
49+
ASSERT_TRUE(strlen(name) + 1 < sizeof(event_name_));
50+
memcpy(event_name_, name, strlen(name) + 1);
5051
return EventTracerEntry();
5152
}
5253

5354
void end_profiling(EventTracerEntry prof_entry) override {
5455
(void)prof_entry;
56+
memset(event_name_, 0, sizeof(event_name_));
5557
return;
5658
}
5759

@@ -156,13 +158,18 @@ class DummyEventTracer : public EventTracer {
156158
return logged_evalue_type_;
157159
}
158160

161+
char* get_event_name() {
162+
return event_name_;
163+
}
164+
159165
void reset_logged_value() {
160166
logged_evalue_ = EValue(false);
161167
}
162168

163169
private:
164170
EValue logged_evalue_ = EValue(false);
165171
LoggedEValueType logged_evalue_type_;
172+
char event_name_[1024];
166173
};
167174

168175
/**
@@ -175,15 +182,15 @@ void RunSimpleTracerTest(EventTracer* event_tracer) {
175182
using executorch::runtime::internal::event_tracer_track_allocation;
176183
using executorch::runtime::internal::event_tracer_track_allocator;
177184
using executorch::runtime::internal::EventTracerProfileInstructionScope;
178-
using executorch::runtime::internal::EventTracerProfileScope;
185+
using executorch::runtime::internal::EventTracerProfileMethodScope;
179186

180187
event_tracer_create_event_block(event_tracer, "ExampleEvent");
181188
event_tracer_create_event_block(event_tracer, "ExampleEvent");
182189
EventTracerEntry event_entry =
183190
event_tracer_begin_profiling_event(event_tracer, "ExampleEvent");
184191
event_tracer_end_profiling_event(event_tracer, event_entry);
185192
{
186-
EventTracerProfileScope event_tracer_profile_scope(
193+
EventTracerProfileMethodScope event_tracer_profile_scope(
187194
event_tracer, "ExampleScope");
188195
}
189196
{
@@ -282,3 +289,39 @@ TEST(TestEventTracer, SimpleEventTracerTestLogging) {
282289

283290
// TODO(T163645377): Add more test coverage to log and verify events passed into
284291
// DummyTracer.
292+
TEST(TestEventTracer, EventTracerProfileOpControl) {
293+
DummyEventTracer dummy;
294+
// Op profiling is enabled by default. Test that it works.
295+
{
296+
{
297+
executorch::runtime::internal::EventTracerProfileOpScope
298+
event_tracer_op_scope(&dummy, "ExampleOpScope");
299+
EXPECT_EQ(strcmp(dummy.get_event_name(), "ExampleOpScope"), 0);
300+
}
301+
EXPECT_EQ(strcmp(dummy.get_event_name(), ""), 0);
302+
303+
// Normal profiling should still work.
304+
{
305+
executorch::runtime::internal::EventTracerProfileMethodScope
306+
event_tracer_profiler_scope(&dummy, "ExampleProfilerScope");
307+
EXPECT_EQ(strcmp(dummy.get_event_name(), "ExampleProfilerScope"), 0);
308+
}
309+
310+
dummy.set_event_tracer_profiling_level(
311+
executorch::runtime::EventTracerProfilingLevel::kProfileMethodOnly);
312+
313+
// Op profiling should be disabled now.
314+
{
315+
executorch::runtime::internal::EventTracerProfileOpScope
316+
event_tracer_op_scope(&dummy, "ExampleOpScope");
317+
EXPECT_EQ(strcmp(dummy.get_event_name(), ""), 0);
318+
}
319+
320+
// Normal profiling should still work.
321+
{
322+
executorch::runtime::internal::EventTracerProfileMethodScope
323+
event_tracer_profiler_scope(&dummy, "1ExampleProfilerScope");
324+
EXPECT_EQ(strcmp(dummy.get_event_name(), "1ExampleProfilerScope"), 0);
325+
}
326+
}
327+
}

runtime/executor/method.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,8 @@ Result<Method> Method::load(
572572

573573
Error Method::init(executorch_flatbuffer::ExecutionPlan* s_plan) {
574574
EXECUTORCH_SCOPE_PROF("Method::init");
575-
internal::EventTracerProfileScope event_tracer_profile_scope =
576-
internal::EventTracerProfileScope(event_tracer_, "Method::init");
575+
internal::EventTracerProfileMethodScope event_tracer_profile_scope =
576+
internal::EventTracerProfileMethodScope(event_tracer_, "Method::init");
577577
ET_CHECK_OR_RETURN_ERROR(
578578
// Don't use !initialized() here because we also want to fail on the
579579
// InitializationFailed state.
@@ -1022,8 +1022,8 @@ Error Method::execute_instruction() {
10221022
switch (instruction->instr_args_type()) {
10231023
case executorch_flatbuffer::InstructionArguments::KernelCall: {
10241024
EXECUTORCH_SCOPE_PROF("OPERATOR_CALL");
1025-
internal::EventTracerProfileScope event_tracer_scope =
1026-
internal::EventTracerProfileScope(event_tracer_, "OPERATOR_CALL");
1025+
internal::EventTracerProfileOpScope event_tracer_op_scope =
1026+
internal::EventTracerProfileOpScope(event_tracer_, "OPERATOR_CALL");
10271027
// TODO(T147221312): Also expose tensor resizer via the context.
10281028
KernelRuntimeContext context(event_tracer_, temp_allocator_);
10291029
auto args = chain.argument_lists_[step_state_.instr_idx];
@@ -1057,8 +1057,8 @@ Error Method::execute_instruction() {
10571057
} break;
10581058
case executorch_flatbuffer::InstructionArguments::DelegateCall: {
10591059
EXECUTORCH_SCOPE_PROF("DELEGATE_CALL");
1060-
internal::EventTracerProfileScope event_tracer_profile_scope =
1061-
internal::EventTracerProfileScope(event_tracer_, "DELEGATE_CALL");
1060+
internal::EventTracerProfileOpScope event_tracer_op_scope =
1061+
internal::EventTracerProfileOpScope(event_tracer_, "DELEGATE_CALL");
10621062
// We know that instr_args_as_DelegateCall is non-null because it was
10631063
// checked at init time.
10641064
auto delegate_idx =
@@ -1101,8 +1101,8 @@ Error Method::execute_instruction() {
11011101
} break;
11021102
case executorch_flatbuffer::InstructionArguments::JumpFalseCall: {
11031103
EXECUTORCH_SCOPE_PROF("JF_CALL");
1104-
internal::EventTracerProfileScope event_tracer_profile_scope =
1105-
internal::EventTracerProfileScope(event_tracer_, "JF_CALL");
1104+
internal::EventTracerProfileOpScope event_tracer_op_scope =
1105+
internal::EventTracerProfileOpScope(event_tracer_, "JF_CALL");
11061106
// We know that instr_args_as_JumpFalseCall is non-null because it was
11071107
// checked at init time.
11081108
auto jf_call = instruction->instr_args_as_JumpFalseCall();
@@ -1120,17 +1120,17 @@ Error Method::execute_instruction() {
11201120
} break;
11211121
case executorch_flatbuffer::InstructionArguments::MoveCall: {
11221122
EXECUTORCH_SCOPE_PROF("MOVE_CALL");
1123-
internal::EventTracerProfileScope event_tracer_profile_scope =
1124-
internal::EventTracerProfileScope(event_tracer_, "MOVE_CALL");
1123+
internal::EventTracerProfileOpScope event_tracer_op_scope =
1124+
internal::EventTracerProfileOpScope(event_tracer_, "MOVE_CALL");
11251125
// We know that instr_args_as_MoveCall is non-null because it was checked
11261126
// at init time.
11271127
auto move_call = instruction->instr_args_as_MoveCall();
11281128
mutable_value(move_call->move_to()) = get_value(move_call->move_from());
11291129
} break;
11301130
case executorch_flatbuffer::InstructionArguments::FreeCall: {
11311131
EXECUTORCH_SCOPE_PROF("FREE_CALL");
1132-
internal::EventTracerProfileScope event_tracer_profile_scope =
1133-
internal::EventTracerProfileScope(event_tracer_, "FREE_CALL");
1132+
internal::EventTracerProfileOpScope event_tracer_op_scope =
1133+
internal::EventTracerProfileOpScope(event_tracer_, "FREE_CALL");
11341134
// We know that instr_args_as_FreeCall is non-null because it was checked
11351135
// at init time.
11361136
auto free_call = instruction->instr_args_as_FreeCall();
@@ -1191,8 +1191,8 @@ Error Method::step() {
11911191
static_cast<int32_t>(step_state_.chain_idx),
11921192
static_cast<uint32_t>(step_state_.instr_idx));
11931193
EXECUTORCH_SCOPE_PROF("Method::step");
1194-
internal::EventTracerProfileScope event_tracer_profile_scope =
1195-
internal::EventTracerProfileScope(event_tracer_, "Method::step");
1194+
internal::EventTracerProfileMethodScope event_tracer_profile_scope =
1195+
internal::EventTracerProfileMethodScope(event_tracer_, "Method::step");
11961196
ET_CHECK_OR_RETURN_ERROR(
11971197
initialized(),
11981198
InvalidState,
@@ -1233,8 +1233,8 @@ Error Method::experimental_step() {
12331233

12341234
Error Method::execute() {
12351235
internal::event_tracer_create_event_block(event_tracer_, "Execute");
1236-
internal::EventTracerProfileScope event_tracer_profile_scope =
1237-
internal::EventTracerProfileScope(event_tracer_, "Method::execute");
1236+
internal::EventTracerProfileMethodScope event_tracer_profile_scope =
1237+
internal::EventTracerProfileMethodScope(event_tracer_, "Method::execute");
12381238
EXECUTORCH_SCOPE_PROF("Method::execute");
12391239
ET_CHECK_OR_RETURN_ERROR(
12401240
initialized(),

runtime/executor/program.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,9 @@ Result<Method> Program::load_method(
241241
EventTracer* event_tracer) const {
242242
EXECUTORCH_SCOPE_PROF("Program::load_method");
243243
internal::event_tracer_create_event_block(event_tracer, "Default");
244-
internal::EventTracerProfileScope event_tracer_scope =
245-
internal::EventTracerProfileScope(event_tracer, "Program::load_method");
244+
internal::EventTracerProfileMethodScope event_tracer_scope =
245+
internal::EventTracerProfileMethodScope(
246+
event_tracer, "Program::load_method");
246247
// If we can't create a MethodMeta for the Method, the Method is corrupt;
247248
// Method::method_meta() assumes success, so we must fail here.
248249
Result<MethodMeta> meta = method_meta(method_name);

0 commit comments

Comments
 (0)