Skip to content

Commit acfcdd5

Browse files
tarun292facebook-github-bot
authored andcommitted
Add option to disable operator profiling (#5720)
Summary: X-link: pytorch/pytorch#136838 Pull Request resolved: #5720 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); ``` Reviewed By: dbort Differential Revision: D61883224 fbshipit-source-id: f4fdcb67be00762152ca90b10239d10c2664a926
1 parent d9aeca5 commit acfcdd5

File tree

5 files changed

+152
-25
lines changed

5 files changed

+152
-25
lines changed

runtime/core/event_tracer.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ 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+
enum class EventTracerProfilingLevel {
76+
/// No operator profiling.
77+
kProfileMethodOnly,
78+
/// All profiling events enabled.
79+
kProfileAllEvents,
80+
};
81+
7082
/**
7183
* This is the struct which should be returned when a profiling event is
7284
* started. This is used to uniquely identify that profiling event and will be
@@ -423,6 +435,21 @@ class EventTracer {
423435
return event_tracer_debug_level_;
424436
}
425437

438+
/**
439+
* Set the level of event tracer profiling that is desired.
440+
*/
441+
void set_event_tracer_profiling_level(
442+
EventTracerProfilingLevel profiling_level) {
443+
event_tracer_profiling_level_ = profiling_level;
444+
}
445+
446+
/**
447+
* Return the current level of event tracer profiling.
448+
*/
449+
EventTracerProfilingLevel event_tracer_profiling_level() {
450+
return event_tracer_profiling_level_;
451+
}
452+
426453
/**
427454
* Return the current status of intermediate outputs logging mode.
428455
*/
@@ -458,6 +485,8 @@ class EventTracer {
458485
int bundled_input_index_ = kUnsetBundledInputIndex;
459486
EventTracerDebugLogLevel event_tracer_debug_level_ =
460487
EventTracerDebugLogLevel::kNoLogging;
488+
EventTracerProfilingLevel event_tracer_profiling_level_ =
489+
EventTracerProfilingLevel::kProfileAllEvents;
461490
};
462491

463492
} // namespace runtime

runtime/core/event_tracer_hooks.h

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,58 @@ 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+
77+
using EventTracerProfileScope = EventTracerProfileOpScope;
78+
3679
/**
3780
* This class enables scope based profiling where needed using RAII.
3881
* Profiling will be started when the object is created and will end
39-
* when the object goes out of scope.
82+
* when the object goes out of scope. This is specifically intended to
83+
* be used for profiling methods in the runtime.
4084
*/
41-
class EventTracerProfileScope final {
85+
class EventTracerProfileMethodScope final {
4286
public:
43-
EventTracerProfileScope(EventTracer* event_tracer, const char* name) {
87+
EventTracerProfileMethodScope(EventTracer* event_tracer, const char* name) {
4488
#ifdef ET_EVENT_TRACER_ENABLED
4589
event_tracer_ = event_tracer;
4690
if (event_tracer_ == nullptr) {
@@ -53,7 +97,7 @@ class EventTracerProfileScope final {
5397
#endif
5498
}
5599

56-
~EventTracerProfileScope() {
100+
~EventTracerProfileMethodScope() {
57101
#ifdef ET_EVENT_TRACER_ENABLED
58102
if (event_tracer_ == nullptr) {
59103
return;
@@ -111,6 +155,13 @@ class EventTracerProfileInstructionScope final {
111155
#endif
112156
};
113157

158+
inline bool event_tracer_enabled() {
159+
#ifdef ET_EVENT_TRACER_ENABLED
160+
return true;
161+
#else //! ET_EVENT_TRACER_ENABLED
162+
return false;
163+
#endif
164+
}
114165
/**
115166
* Create a new event block with the specified name. Any events logged
116167
* after this will be associated with this new event block.
@@ -271,7 +322,10 @@ using ::executorch::runtime::internal::event_tracer_set_bundled_input_index;
271322
using ::executorch::runtime::internal::event_tracer_track_allocation;
272323
using ::executorch::runtime::internal::event_tracer_track_allocator;
273324
using ::executorch::runtime::internal::EventTracerProfileInstructionScope;
325+
using ::executorch::runtime::internal::EventTracerProfileMethodScope;
326+
using ::executorch::runtime::internal::EventTracerProfileOpScope;
274327
using ::executorch::runtime::internal::EventTracerProfileScope;
328+
275329
} // namespace internal
276330
} // namespace executor
277331
} // 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+
ET_CHECK(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)