xref: /aosp_15_r20/external/executorch/runtime/core/event_tracer_hooks_delegate.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 can be used by runtime delegate backend
17  * authors to log profiling and debugging events from backend code. In order to
18  * use these hooks delegate authors would have needed to generate a delegate
19  * debug identifier mapping using the DelegateMappingBuilder library present in
20  * executorch/exir/backend/utils.py. The delegate debug identifiers generated by
21  * that library are the ones that need to be passed to these hooks to log
22  * events. Using any other identifiers will cause post-processing of the events
23  * data to not properly link back to the nodes in the original lowered graph.
24  *
25  * The benefit of defining these hooks is that we can easily control whether or
26  * not we want to compile in the EventTracer code based on the status of the
27  * ET_EVENT_TRACER_ENABLED flag.
28  */
29 
30 namespace executorch {
31 namespace runtime {
32 
33 /**
34  * Start the profiling of a delegate event. Similar to start_profiling it will
35  * return an instance of EventTracerEntry that contains the details of this
36  * event. Can be left in production code as these hooks compile conditionally.
37  *
38  * @param[in] event_tracer The event tracer instance that is doing the logging.
39  * @param[in] name Human readable name for the delegate event. This name has
40  * to be the same name that was passed in during the Debug delegate mapping
41  * generation in the export/ahead-of-time process. If indices and not names
42  * are used by this delegate to identify ops executed in the backend then
43  * nullptr can be passed in. Users calling this interface do not need to keep
44  * the memory pointed to by this pointer around. The string must be copied over
45  * into internal memory during this call.
46  * @param[in] delegate_debug_id The id of the delegate event. If string
47  * based names are used by this delegate to identify ops executed in the
48  * backend then kUnsetDebugHandle should be passed in here.
49  */
event_tracer_start_profiling_delegate(EventTracer * event_tracer,const char * name,DebugHandle delegate_debug_id)50 inline EventTracerEntry event_tracer_start_profiling_delegate(
51     EventTracer* event_tracer,
52     const char* name,
53     DebugHandle delegate_debug_id) {
54 #ifdef ET_EVENT_TRACER_ENABLED
55   if (event_tracer) {
56     return event_tracer->start_profiling_delegate(name, delegate_debug_id);
57   }
58 #else //! ET_EVENT_TRACER_ENABLED
59   (void)name;
60   (void)delegate_debug_id;
61 #endif
62   // There is no active tracer; this value will be ignored.
63   return EventTracerEntry();
64 }
65 
66 /**
67  * Signal the end of the delegate profiling event contained in
68  * event_tracer_entry. Users also have the option to log some some free-from
69  * string based metadata along with this. Can be left in production code as
70  * these hooks compile conditionally.
71  *
72  * @param[in] event_tracer The event tracer instance that is doing the logging.
73  * @param[in] event_tracer_entry The EventTracerEntry returned by a call to
74  * start_profiling_delegate().
75  * @param[in] metadata Optional data relevant to the execution that the user
76  * wants to log along with this event. Pointer to metadata doesn't need to be
77  * valid after the call to this function. The contents and format of the data
78  * are transparent to the event tracer. It will just pipe along the data and
79  * make it available for the user again in the post-processing stage.
80  * @param[in] metadata_len Length of the metadata buffer.
81  */
82 inline void event_tracer_end_profiling_delegate(
83     EventTracer* event_tracer,
84     EventTracerEntry event_tracer_entry,
85     const void* metadata = nullptr,
86     size_t metadata_len = 0) {
87 #ifdef ET_EVENT_TRACER_ENABLED
88   if (event_tracer) {
89     event_tracer->end_profiling_delegate(
90         event_tracer_entry, metadata, metadata_len);
91   }
92 #else //! ET_EVENT_TRACER_ENABLED
93   (void)event_tracer_entry;
94   (void)metadata;
95   (void)metadata_len;
96 #endif
97 }
98 
99 /**
100  * Some delegates get access to the profiling details only after the complete
101  * graph has been executed. This interface is to support such use cases. It
102  * can be called in a loop etc. to log any number of profiling events that are
103  * part of this delegate. Can be left in production code as these hooks
104  * compile conditionally.
105  *
106  * @param[in] event_tracer The event tracer instance that is doing the logging.
107  * @param[in] name Human readable name for the delegate event. This name has
108  * to be the same name that was passed in during the Debug delegate mapping
109  * generation in the export/ahead-of-time process. If indices and not names
110  * are used by this delegate to identify ops executed in the backend then
111  * nullptr can be passed in. Users calling this interface do not need to keep
112  * the memory pointed to by this pointer around. The string must
113  * be copied over into internal memory during this call.
114  * @param[in] delegate_debug_id The id of the delegate event. If string
115  * based names are used by this delegate to identify ops executed in the
116  * backend then -1 should be passed in here.
117  * @param[in] start_time The timestamp when the delegate event started.
118  * @param[in] end_time The timestamp when the delegate event finished.
119  * @param[in] metadata Optional data relevant to the execution that the user
120  * wants to log along with this event. Pointer to metadata doesn't need to be
121  * valid after the call to this function. The contents and format of the data
122  * are transparent to the event tracer. It will just pipe along the data and
123  * make it available for the user again in the post-processing stage.
124  * @param[in] metadata_len Length of the metadata buffer.
125  */
126 inline void event_tracer_log_profiling_delegate(
127     EventTracer* event_tracer,
128     const char* name,
129     DebugHandle delegate_debug_id,
130     et_timestamp_t start_time,
131     et_timestamp_t end_time,
132     const void* metadata = nullptr,
133     size_t metadata_len = 0) {
134 #ifdef ET_EVENT_TRACER_ENABLED
135   if (event_tracer) {
136     event_tracer->log_profiling_delegate(
137         name, delegate_debug_id, start_time, end_time, metadata, metadata_len);
138   }
139 #else //! ET_EVENT_TRACER_ENABLED
140   (void)name;
141   (void)delegate_debug_id;
142   (void)start_time;
143   (void)end_time;
144   (void)metadata;
145   (void)metadata_len;
146 #endif
147 }
148 
149 /**
150  * This templated interfaces can be called in a loop etc. to log any number of
151  * debug events that are part of this delegate. Supported values types are int,
152  * bool, double, tensor and array of tensors. Can be left in production code as
153  * these hooks compile conditionally.
154  *
155  * @param[in] event_tracer The event tracer instance that is doing the logging.
156  * @param[in] name Human readable name for the delegate event. This name has
157  * to be the same name that was passed in during the Debug delegate mapping
158  * generation in the export/ahead-of-time process. If indices and not names
159  * are used by this delegate to identify ops executed in the backend then
160  * nullptr can be passed in. Users calling this interface do not need to keep
161  * the memory pointed to by this pointer around. The string must
162  * be copied over into internal memory during this call.
163  * @param[in] delegate_debug_id The id of the delegate event. If string
164  * based names are used by this delegate to identify ops executed in the
165  * backend then -1 should be passed in here.
166  * @param[in] output The output to be logged.
167  */
168 template <typename T>
event_tracer_log_output_delegate(EventTracer * event_tracer,const char * name,DebugHandle delegate_debug_id,const T & output)169 inline void event_tracer_log_output_delegate(
170     EventTracer* event_tracer,
171     const char* name,
172     DebugHandle delegate_debug_id,
173     const T& output) {
174 #ifdef ET_EVENT_TRACER_ENABLED
175   if (event_tracer) {
176     static_assert(
177         std::is_same<T, int>::value || std::is_same<T, bool>::value ||
178             std::is_same<T, double>::value ||
179             std::is_same<T, executorch::aten::Tensor>::value ||
180             std::is_same<T, ArrayRef<executorch::aten::Tensor>>::value,
181         "Unsupported type for intermediate output");
182     event_tracer->log_intermediate_output_delegate(
183         name, delegate_debug_id, output);
184   }
185 #else //! ET_EVENT_TRACER_ENABLED
186   (void)name;
187   (void)delegate_debug_id;
188   (void)output;
189 #endif
190 }
191 
192 } // namespace runtime
193 } // namespace executorch
194 
195 namespace torch {
196 namespace executor {
197 // TODO(T197294990): Remove these deprecated aliases once all users have moved
198 // to the new `::executorch` namespaces.
199 using ::executorch::runtime::event_tracer_end_profiling_delegate;
200 using ::executorch::runtime::event_tracer_log_output_delegate;
201 using ::executorch::runtime::event_tracer_log_profiling_delegate;
202 using ::executorch::runtime::event_tracer_start_profiling_delegate;
203 } // namespace executor
204 } // namespace torch
205