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