xref: /aosp_15_r20/external/executorch/runtime/core/event_tracer_hooks.h (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
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