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 * TODO(dbort): Make this a private header of runtime/executor. It only contains
28 * runtime-internal functions and should not be part of the public set of
29 * headers.
30 */
31
32 namespace executorch {
33 namespace runtime {
34 namespace internal {
35
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:
EventTracerProfileOpScope(EventTracer * event_tracer,const char * name)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
~EventTracerProfileOpScope()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
79 /**
80 * This class enables scope based profiling where needed using RAII.
81 * Profiling will be started when the object is created and will end
82 * when the object goes out of scope. This is specifically intended to
83 * be used for profiling methods in the runtime.
84 */
85 class EventTracerProfileMethodScope final {
86 public:
EventTracerProfileMethodScope(EventTracer * event_tracer,const char * name)87 EventTracerProfileMethodScope(EventTracer* event_tracer, const char* name) {
88 #ifdef ET_EVENT_TRACER_ENABLED
89 event_tracer_ = event_tracer;
90 if (event_tracer_ == nullptr) {
91 return;
92 }
93 event_entry_ = event_tracer->start_profiling(name);
94 #else //! ET_EVENT_TRACER_ENABLED
95 (void)event_tracer;
96 (void)name;
97 #endif
98 }
99
~EventTracerProfileMethodScope()100 ~EventTracerProfileMethodScope() {
101 #ifdef ET_EVENT_TRACER_ENABLED
102 if (event_tracer_ == nullptr) {
103 return;
104 }
105 event_tracer_->end_profiling(event_entry_);
106 #endif
107 }
108
109 private:
110 #ifdef ET_EVENT_TRACER_ENABLED
111 EventTracer* event_tracer_;
112 EventTracerEntry event_entry_;
113 #endif
114 };
115
116 /**
117 * This class helps us set and then clear out the chain id and debug handle
118 * values stored in the event tracer class using RAII. This is typically called
119 * in the executor loop before entering the codegen layer to configure the chain
120 * id and debug handle of the current instruction being executed.
121 * After we return from the kernel execution we can then reset the chain id and
122 * debug handle to defaults when this object goes out of scope.
123 */
124 class EventTracerProfileInstructionScope final {
125 public:
EventTracerProfileInstructionScope(EventTracer * event_tracer,ChainID chain_idx,DebugHandle debug_handle)126 EventTracerProfileInstructionScope(
127 EventTracer* event_tracer,
128 ChainID chain_idx,
129 DebugHandle debug_handle) {
130 #ifdef ET_EVENT_TRACER_ENABLED
131 event_tracer_ = event_tracer;
132 if (event_tracer_ == nullptr) {
133 return;
134 }
135 event_tracer_->set_chain_debug_handle(chain_idx, debug_handle);
136 #else //! ET_EVENT_TRACER_ENABLED
137 (void)event_tracer;
138 (void)chain_idx;
139 (void)debug_handle;
140 #endif
141 }
142
~EventTracerProfileInstructionScope()143 ~EventTracerProfileInstructionScope() {
144 #ifdef ET_EVENT_TRACER_ENABLED
145 if (event_tracer_ == nullptr) {
146 return;
147 }
148 event_tracer_->set_chain_debug_handle(kUnsetChainId, kUnsetDebugHandle);
149 #endif
150 }
151
152 private:
153 #ifdef ET_EVENT_TRACER_ENABLED
154 EventTracer* event_tracer_;
155 #endif
156 };
157
event_tracer_enabled()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 }
165 /**
166 * Create a new event block with the specified name. Any events logged
167 * after this will be associated with this new event block.
168 */
event_tracer_create_event_block(EventTracer * event_tracer,char const * name)169 inline void event_tracer_create_event_block(
170 EventTracer* event_tracer,
171 char const* name) {
172 #ifdef ET_EVENT_TRACER_ENABLED
173 if (event_tracer) {
174 event_tracer->create_event_block(name);
175 }
176 #else //! ET_EVENT_TRACER_ENABLED
177 (void)event_tracer;
178 (void)name;
179 #endif
180 }
181
182 /**
183 * Explicitly mark the beginning of a new profiling event. This returns
184 * an instance of an EventTracerEntry object that the user needs to keep
185 * around and pass into the corresponding event_tracer_end_profiling_event
186 * call.
187 */
event_tracer_begin_profiling_event(EventTracer * event_tracer,char const * name)188 inline EventTracerEntry event_tracer_begin_profiling_event(
189 EventTracer* event_tracer,
190 char const* name) {
191 #ifdef ET_EVENT_TRACER_ENABLED
192 if (event_tracer) {
193 return event_tracer->start_profiling(name);
194 }
195 #else //! ET_EVENT_TRACER_ENABLED
196 (void)event_tracer;
197 (void)name;
198 #endif
199 // There is no active tracer; this value will be ignored.
200 return EventTracerEntry();
201 }
202
203 /**
204 * Mark the end of a profiling event passing in the entry token
205 * returned by a previous call to ET_EVENT_TRACER_BEGIN_PROFILING_EVENT.
206 */
event_tracer_end_profiling_event(EventTracer * event_tracer,EventTracerEntry event)207 inline void event_tracer_end_profiling_event(
208 EventTracer* event_tracer,
209 EventTracerEntry event) {
210 #ifdef ET_EVENT_TRACER_ENABLED
211 if (event_tracer) {
212 event_tracer->end_profiling(event);
213 }
214 #else //! ET_EVENT_TRACER_ENABLED
215 (void)event_tracer;
216 (void)event;
217 #endif
218 }
219
220 /**
221 * Start the tracking of the allocator represented by this name and returns
222 * an AllocatorID that will be used to track all subsequent allocations done by
223 * this allocator.
224 */
event_tracer_track_allocator(EventTracer * event_tracer,const char * name)225 inline AllocatorID event_tracer_track_allocator(
226 EventTracer* event_tracer,
227 const char* name) {
228 #ifdef ET_EVENT_TRACER_ENABLED
229 if (event_tracer) {
230 return event_tracer->track_allocator(name);
231 }
232 #else //! ET_EVENT_TRACER_ENABLED
233 (void)event_tracer;
234 (void)name;
235 #endif
236 // There is no active tracer; this value will be ignored.
237 return 0;
238 }
239
240 /// Log the allocation event done via the allocator represented by id.
event_tracer_track_allocation(EventTracer * event_tracer,AllocatorID id,size_t size)241 inline void event_tracer_track_allocation(
242 EventTracer* event_tracer,
243 AllocatorID id,
244 size_t size) {
245 #ifdef ET_EVENT_TRACER_ENABLED
246 if (event_tracer) {
247 event_tracer->track_allocation(id, size);
248 }
249 #else //! ET_EVENT_TRACER_ENABLED
250 (void)event_tracer;
251 (void)id;
252 (void)size;
253 #endif
254 }
255
256 /// Log an intermediate value.
event_tracer_log_evalue(EventTracer * event_tracer,EValue & evalue)257 inline void event_tracer_log_evalue(EventTracer* event_tracer, EValue& evalue) {
258 #ifdef ET_EVENT_TRACER_ENABLED
259 if (event_tracer) {
260 if (event_tracer->event_tracer_debug_level() >=
261 EventTracerDebugLogLevel::kIntermediateOutputs) {
262 event_tracer->log_evalue(evalue, LoggedEValueType::kIntermediateOutput);
263 }
264 }
265 #else //! ET_EVENT_TRACER_ENABLED
266 (void)event_tracer;
267 (void)evalue;
268 #endif
269 }
270
271 /// Log a program output.
event_tracer_log_evalue_output(EventTracer * event_tracer,const EValue & evalue)272 inline void event_tracer_log_evalue_output(
273 EventTracer* event_tracer,
274 const EValue& evalue) {
275 #ifdef ET_EVENT_TRACER_ENABLED
276 /*
277 * If debugging via event tracer is enabled but intermediate output logging is
278 * disabled then we want to only log the outputs.
279 */
280 if (event_tracer) {
281 if (event_tracer->event_tracer_debug_level() >=
282 EventTracerDebugLogLevel::kProgramOutputs) {
283 event_tracer->log_evalue(evalue, LoggedEValueType::kProgramOutput);
284 }
285 }
286 #else //! ET_EVENT_TRACER_ENABLED
287 (void)event_tracer;
288 (void)evalue;
289 #endif
290 }
291
292 // Set the bundled input index of the current bundled input being used by the
293 // method.
event_tracer_set_bundled_input_index(EventTracer * event_tracer,int bundled_input_index)294 inline void event_tracer_set_bundled_input_index(
295 EventTracer* event_tracer,
296 int bundled_input_index) {
297 #ifdef ET_EVENT_TRACER_ENABLED
298 if (event_tracer) {
299 event_tracer->set_bundled_input_index(bundled_input_index);
300 }
301 #else //! ET_EVENT_TRACER_ENABLED
302 (void)event_tracer;
303 (void)bundled_input_index;
304 #endif
305 }
306
307 } // namespace internal
308 } // namespace runtime
309 } // namespace executorch
310
311 namespace torch {
312 namespace executor {
313 namespace internal {
314 // TODO(T197294990): Remove these deprecated aliases once all users have moved
315 // to the new `::executorch` namespaces.
316 using ::executorch::runtime::internal::event_tracer_begin_profiling_event;
317 using ::executorch::runtime::internal::event_tracer_create_event_block;
318 using ::executorch::runtime::internal::event_tracer_end_profiling_event;
319 using ::executorch::runtime::internal::event_tracer_log_evalue;
320 using ::executorch::runtime::internal::event_tracer_log_evalue_output;
321 using ::executorch::runtime::internal::event_tracer_set_bundled_input_index;
322 using ::executorch::runtime::internal::event_tracer_track_allocation;
323 using ::executorch::runtime::internal::event_tracer_track_allocator;
324 using ::executorch::runtime::internal::EventTracerProfileInstructionScope;
325 using ::executorch::runtime::internal::EventTracerProfileMethodScope;
326 using ::executorch::runtime::internal::EventTracerProfileOpScope;
327 using ::executorch::runtime::internal::EventTracerProfileScope;
328
329 } // namespace internal
330 } // namespace executor
331 } // namespace torch
332