forked from pytorch/executorch
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathevent_tracer.h
More file actions
592 lines (552 loc) · 24.8 KB
/
event_tracer.h
File metadata and controls
592 lines (552 loc) · 24.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <executorch/runtime/core/array_ref.h>
#include <executorch/runtime/core/evalue.h>
#include <executorch/runtime/core/result.h>
#include <executorch/runtime/platform/platform.h>
#include <stdlib.h>
#include <cstdint>
#pragma once
namespace executorch {
namespace runtime {
/// Represents an allocator id returned by track_allocator.
typedef uint32_t AllocatorID;
/// Represents the chain id that will be passed in by the user during
/// event logging.
typedef int32_t ChainID;
/// Represents the debug handle that is generally associated with each
/// op executed in the runtime.
typedef uint32_t DebugHandle;
// Represents the delegate debug id that is generally associated with each
// delegate event.
typedef int32_t DelegateDebugIntId;
/// Default id's for chain id and debug handle.
constexpr ChainID kUnsetChainId = -1;
constexpr DebugHandle kUnsetDebugHandle = 0;
constexpr DelegateDebugIntId kUnsetDelegateDebugIntId = -1;
// Default bundled input index to indicate that it hasn't been set yet.
constexpr int kUnsetBundledInputIndex = -1;
/// Different types of delegate debug identifiers that are supported currently.
enum class DelegateDebugIdType {
/// Default value, indicates that it's not a delegate event.
kNone,
/// Indicates a delegate event logged using an integer delegate debug
/// identifier.
kInt,
/// Indicates a delegate event logged using a string delegate debug
/// identifier i.e. the delegate debug id is a pointer to a string table
/// managed by the class implementing EventTracer functionality.
kStr
};
/// Indicates the type of the EValue that was logged. These values could be
/// serialized and should not be changed.
enum class LoggedEValueType {
/// Intermediate output from an operator.
kIntermediateOutput = 0,
/// Output at the program level. This is essentially the output
/// of the model.
kProgramOutput = 1,
};
/// Indicates the level of event tracer debug logging. Verbosity of the logging
/// increases as we go down the enum list.
enum class EventTracerDebugLogLevel {
/// No logging.
kNoLogging,
/// When set to this only the program level outputs will be logged.
kProgramOutputs,
/// When set to this all intermediate outputs and program level outputs
/// will be logged.
kIntermediateOutputs,
};
/**
* EventTracerFilterBase is an abstract base class that provides an interface
* for filtering events based on their name or delegate debug index.
* Derived classes should implement the filter method to define specific
* filtering logic.
*/
class EventTracerFilterBase {
public:
/**
* Filters events based on the given name or delegate debug index.
*
* Note that only one of either the name or delegate_debug_index should be
* passed in.
*
* @param[in] name A pointer to a string representing the `name` of the
* event. If `delegate_debug_index` is not set to kUnsetDebugHandle, `name`
* should be set to nullptr.
*
* @param[in] delegate_debug_index A DebugHandle representing the debug index
* of the delegate. If `name` is not nullptr, this should be set to
* kUnsetDebugHandle.
*
* @return A Result<bool> indicating whether the event matches the filter
* criteria.
* - True if the event matches the filter.
* - False if the event does not match or is unknown.
* - An error code if an error occurs during filtering.
*/
virtual Result<bool> filter(
const char* name,
DelegateDebugIntId delegate_debug_index) = 0;
/**
* Virtual destructor for the EventTracerFilterBase class.
* Ensures proper cleanup of derived class objects.
*/
virtual ~EventTracerFilterBase() = default;
};
/**
* Indicates the level of profiling that should be enabled. Profiling
* events will be logged in increasing order of verbosity as we go down the
* enum list. Thus it is important to keep the enum values in the right order.
*/
enum class EventTracerProfilingLevel {
/// No operator profiling.
kProfileMethodOnly,
/// All profiling events enabled.
kProfileAllEvents,
};
/**
* This is the struct which should be returned when a profiling event is
* started. This is used to uniquely identify that profiling event and will be
* required to be passed into the end_profiling call to signal that the event
* identified by this struct has completed.
*
* TODO(gasoonjia): Now this struct is mix-used for both delegate and
*non-delegate events. In the future we should separate them into two different
*structs: EventTracerEntry for non-delegate events holding DebugHandle, and
*DelegateEventTracerEntry for delegate events holding DelegateDebugIntId.
**/
struct EventTracerEntry {
/// An event id to uniquely identify this event that was generated during a
/// call to start the tracking of an event.
int64_t event_id;
/// The chain to which this event belongs to.
ChainID chain_id;
/// The debug handle corresponding to this event.
DebugHandle debug_handle;
/// The time at which this event was started to be tracked.
et_timestamp_t start_time;
/// When delegate_event_id_type != DelegateDebugIdType::kNone it indicates
/// that event_id represents a delegate event. If delegate_event_id_type is:
/// 1) kInt then event_id contains an integer delegate debug id.
/// 2) kStr then event_id contains a string table index into a string table
/// maintained by the class implementing EventTracer functionality that will
/// give us the string identifier of this delegate event. For more details
/// refer to the DelegateMappingBuilder library present in
/// executorch/exir/backend/utils.py.
DelegateDebugIdType delegate_event_id_type;
};
/**
* EventTracer is a class that users can inherit and implement to
* log/serialize/stream etc. the profiling and debugging events that are
* generated at runtime for a model. An example of this is the ETDump
* implementation in the devtools codebase that serializes these events to a
* flatbuffer.
*/
class EventTracer {
public:
/**
* Start a new event block (can consist of profiling and/or debugging events.)
* identified by this name. A block is conceptually a set of events that we
* want to group together. e.g. all the events that occur during the call to
* execute() (i.e. model inference) could be categorized as a block.
*
* @param[in] name A human readable identifier for the event block. Users
* calling this interface do not need to keep the memory pointed to by this
* pointer around. The string must be copied over into internal memory during
* this call.
*/
virtual void create_event_block(const char* name) = 0;
/**
* Start the profiling of the event identified by name and debug_handle.
* The user can pass in a chain_id and debug_handle to this call, or leave
* them empty (default values) which would then result in the chain_id and
* debug handle stored within (set by set_chain_debug_handle) this class to be
* used.
* @param[in] name Human readable name for the profiling event. Users calling
* this interface do not need to keep the memory pointed to by this pointer
* around. The string must be copied over into internal memory during this
* call.
* @param[in] chain_id The id of the chain to which this event belongs to. If
* kUnsetChainId is passed in the chain_id and kUnsetDebugHandle for
* debug_handle then the values stored in the class internally for these
* properties will be used.
* @param[in] debug_handle Debug handle generated ahead-of-time during model
* compilation.
*
* @return Returns an instance of EventTracerEntry which should be passed back
* into the end_profiling() call.
*/
virtual EventTracerEntry start_profiling(
const char* name,
ChainID chain_id = kUnsetChainId,
DebugHandle debug_handle = kUnsetDebugHandle) = 0;
/**
* Start the profiling of a delegate event. Similar to start_profiling it will
* return an instance of EventTracerEntry that contains the details of this
* event.
*
* @param[in] name Human readable name for the delegate event. This name has
* to be the same name that was passed in during the Debug delegate mapping
* generation in the export/ahead-of-time process. If indices and not names
* are used by this delegate to identify ops executed in the backend then
* nullptr can be passed in. Users calling this interface do not need to keep
* the memory pointed to by this pointer around. The string must be copied
* over into internal memory during this call.
* @param[in] delegate_debug_index The id of the delegate event. If string
* based names are used by this delegate to identify ops executed in the
* backend then kUnsetDebugHandle should be passed in here.
*/
virtual EventTracerEntry start_profiling_delegate(
const char* name,
DelegateDebugIntId delegate_debug_index) = 0;
/**
* Signal the end of the delegate profiling event contained in
* event_tracer_entry. Users also have the option to log some some free-from
* string based metadata along with this.
*
* @param[in] event_tracer_entry The EventTracerEntry returned by a call to
* start_profiling_delegate().
* @param[in] metadata Optional data relevant to the execution that the user
* wants to log along with this event. Pointer to metadata doesn't need to be
* valid after the call to this function. The contents and format of the data
* are transparent to the event tracer. It will just pipe along the data and
* make it available for the user again in the post-processing stage.
* @param[in] metadata_len Length of the metadata buffer.
*/
virtual void end_profiling_delegate(
EventTracerEntry event_tracer_entry,
const void* metadata = nullptr,
size_t metadata_len = 0) = 0;
/**
* Some delegates get access to the profiling details only after the complete
* graph has been executed. This interface is to support such use cases. It
* can be called in a loop etc. to log any number of profiling events that are
* part of this delegate.
*
* @param[in] name Human readable name for the delegate event. This name has
* to be the same name that was passed in during the Debug delegate mapping
* generation in the export/ahead-of-time process. If indices and not names
* are used by this delegate to identify ops executed in the backend then
* nullptr can be passed in. Users calling this interface do not need to keep
* the memory pointed to by this pointer around. The string must be copied
* over into internal memory during this call.
* @param[in] delegate_debug_index The id of the delegate event. If string
* based names are used by this delegate to identify ops executed in the
* backend then kUnsetDebugHandle should be passed in here.
* @param[in] start_time The timestamp when the delegate event started.
* @param[in] end_time The timestamp when the delegate event finished.
* @param[in] metadata Optional data relevant to the execution that the user
* wants to log along with this event. Pointer to metadata doesn't need to be
* valid after the call to this function. The contents and format of the data
* are transparent to the event tracer. It will just pipe along the data and
* make it available for the user again in the post-processing stage.
* @param[in] metadata_len Length of the metadata buffer.
*/
virtual void log_profiling_delegate(
const char* name,
DelegateDebugIntId delegate_debug_index,
et_timestamp_t start_time,
et_timestamp_t end_time,
const void* metadata = nullptr,
size_t metadata_len = 0) = 0;
/**
* End the profiling of the event identified by prof_entry
*
* @param[in] prof_entry Value returned by a call to start_profiling
*/
virtual void end_profiling(EventTracerEntry prof_entry) = 0;
/**
* Track this allocation done via a MemoryAllocator which had profiling
* enabled on it.
*
* @param[in] id Allocator id generated by a call to track_allocator.
* @param[in] size The size of the allocation done, in bytes.
*/
virtual void track_allocation(AllocatorID id, size_t size) = 0;
/**
* Generate an allocator id for this memory allocator that will be used in the
* future to identify all the allocations done by this allocator.
*
* @param[in] name Human readable name for the allocator. Users calling
* this interface do not need to keep the memory pointed to by this pointer
* around. The string should be copied over into internal memory during this
* call.
*
* @return Identifier to uniquely identify this allocator.
*/
virtual AllocatorID track_allocator(const char* name) = 0;
/**
* Log an evalue during the execution of the model. This is useful for
* debugging purposes. Model outputs are a special case of this and will
* be logged with the output bool enabled.
*
* Users of this should refer to the chain_id and debug_handle to get the
* context for these evalues and their corresponding op.
*
* @param[in] evalue The value to be logged.
* @param[in] evalue_type Indicates what type of output this is logging e.g.
* an intermediate output, program output etc.
* @return A Result<bool> indicating the status of the logging operation.
* - True if the evalue output was successfully logged.
* - An error code if an error occurs during logging.
*/
virtual Result<bool> log_evalue(
const EValue& evalue,
LoggedEValueType evalue_type) = 0;
/**
* Log an intermediate tensor output from a delegate.
*
* @param[in] name Human readable name for the delegate event. This name has
* to be the same name that was passed in during the Debug delegate mapping
* generation in the export/ahead-of-time process. If indices and not names
* are used by this delegate to identify ops executed in the backend then
* nullptr can be passed in. Users calling this interface do not need to keep
* the memory pointed to by this pointer around. The string must be copied
* over into internal memory during this call.
* @param[in] delegate_debug_index The id of the delegate event. If string
* based names are used by this delegate to identify ops executed in the
* backend then kUnsetDebugHandle should be passed in here.
* @param[in] output The tensor type output to be logged.
* @return A Result<bool> indicating the status of the logging operation.
* - True if the tensor type output was successfully logged.
* - False if the tensor type output was filtered out and not logged.
* - An error code if an error occurs during logging.
*/
virtual Result<bool> log_intermediate_output_delegate(
const char* name,
DelegateDebugIntId delegate_debug_index,
const executorch::aten::Tensor& output) = 0;
/**
* Log an intermediate tensor array output from a delegate.
*
* @param[in] name Human readable name for the delegate event. This name has
* to be the same name that was passed in during the Debug delegate mapping
* generation in the export/ahead-of-time process. If indices and not names
* are used by this delegate to identify ops executed in the backend then
* nullptr can be passed in. Users calling this interface do not need to keep
* the memory pointed to by this pointer around. The string must be copied
* over into internal memory during this call.
* @param[in] delegate_debug_index The id of the delegate event. If string
* based names are used by this delegate to identify ops executed in the
* backend then kUnsetDebugHandle should be passed in here.
* @param[in] output The tensor array type output to be logged.
* @return A Result<bool> indicating the status of the logging operation.
* - True if the tensor array type output was successfully logged.
* - False if the tensor array type output was filtered out and not
* logged.
* - An error code if an error occurs during logging.
*/
virtual Result<bool> log_intermediate_output_delegate(
const char* name,
DelegateDebugIntId delegate_debug_index,
const ArrayRef<executorch::aten::Tensor> output) = 0;
/**
* Log an intermediate int output from a delegate.
*
* @param[in] name Human readable name for the delegate event. This name has
* to be the same name that was passed in during the Debug delegate mapping
* generation in the export/ahead-of-time process. If indices and not names
* are used by this delegate to identify ops executed in the backend then
* nullptr can be passed in. Users calling this interface do not need to keep
* the memory pointed to by this pointer around. The string must be copied
* over into internal memory during this call.
* @param[in] delegate_debug_index The id of the delegate event. If string
* based names are used by this delegate to identify ops executed in the
* backend then kUnsetDebugHandle should be passed in here.
* @param[in] output The int type output to be logged.
* @return A Result<bool> indicating the status of the logging operation.
* - True if the int type output was successfully logged.
* - False if the int type output was filtered out and not logged.
* - An error code if an error occurs during logging.
*/
virtual Result<bool> log_intermediate_output_delegate(
const char* name,
DelegateDebugIntId delegate_debug_index,
const int& output) = 0;
/**
* Log an intermediate bool output from a delegate.
*
* @param[in] name Human readable name for the delegate event. This name has
* to be the same name that was passed in during the Debug delegate mapping
* generation in the export/ahead-of-time process. If indices and not names
* are used by this delegate to identify ops executed in the backend then
* nullptr can be passed in. Users calling this interface do not need to keep
* the memory pointed to by this pointer around. The string must be copied
* over into internal memory during this call.
* @param[in] delegate_debug_index The id of the delegate event. If string
* based names are used by this delegate to identify ops executed in the
* backend then kUnsetDebugHandle should be passed in here.
* @param[in] output The bool type output to be logged.
* @return A Result<bool> indicating the status of the logging operation.
* - True if the bool type output was successfully logged.
* - False if the bool type output was filtered out and not logged.
* - An error code if an error occurs during logging.
*/
virtual Result<bool> log_intermediate_output_delegate(
const char* name,
DelegateDebugIntId delegate_debug_index,
const bool& output) = 0;
/**
* Log an intermediate double output from a delegate.
*
* @param[in] name Human readable name for the delegate event. This name has
* to be the same name that was passed in during the Debug delegate mapping
* generation in the export/ahead-of-time process. If indices and not names
* are used by this delegate to identify ops executed in the backend then
* nullptr can be passed in. Users calling this interface do not need to keep
* the memory pointed to by this pointer around. The string must be copied
* over into internal memory during this call.
* @param[in] delegate_debug_index The id of the delegate event. If string
* based names are used by this delegate to identify ops executed in the
* backend then kUnsetDebugHandle should be passed in here.
* @param[in] output The double type output to be logged.
* @return A Result<bool> indicating the status of the logging operation.
* - True if the double type output was successfully logged.
* - False if the double type output was filtered out and not logged.
* - An error code if an error occurs during logging.
*/
virtual Result<bool> log_intermediate_output_delegate(
const char* name,
DelegateDebugIntId delegate_debug_index,
const double& output) = 0;
/**
* Set the filter of event tracer for delegation intermediate outputs.
*/
virtual void set_delegation_intermediate_output_filter(
EventTracerFilterBase* event_tracer_filter) = 0;
/**
* Helper function to set the chain id ands debug handle. Users have two
* options, the first is that they can directly pass in the chain id and debug
* handle to start_profiling or they can explicitly set them through this
* helper before calling start_profiling.
*
* The reason this helper exists is to
* solve a specific problem. We want to do profiling logging inside the
* codegen layer which calls the kernels. The problem though is that the
* codegen layer doesn't have access to these ids when calling
* start_profiling.
*
* Users should ideally use these within a RAII scope interface to make sure
* that these values are unset after the end_profiling call. If non-default
* values are passed into the start_profiling call they will always be given
* precedence over the values set by this interface.
*
* So what we do is call this helper in method.cpp before
* we hit the codegen layer and in the codegen layer we do a start_profiling
* call without passing in a chain_id or debug_handle. This ensures that the
* values set via this helper are the ones associated with that call.
*
* @param[in] chain_id Chain id of the current instruction being exectuted.
* @param[in] debug_handle Debug handle of the current instruction being
* executed. In this context debug handle and instruction id are the same
* thing.
*/
void set_chain_debug_handle(ChainID chain_id, DebugHandle debug_handle) {
chain_id_ = chain_id;
debug_handle_ = debug_handle;
}
/**
* When running a program wrapped in a bundled program, log the bundled input
* index of the current bundled input being tested out on this method.
* If users want to unset the index back to the default value, they can call
* this method with kUnsetBundledInputIndex.
*
* @param[in] bundled_input_index Index of the current input being tested
*/
void set_bundled_input_index(int bundled_input_index) {
bundled_input_index_ = bundled_input_index;
}
/**
* Return the current bundled input index.
*/
int bundled_input_index() {
return bundled_input_index_;
}
/**
* Set the level of event tracer debug logging that is desired.
*
*/
void set_event_tracer_debug_level(EventTracerDebugLogLevel log_level) {
event_tracer_debug_level_ = log_level;
}
/**
* Return the current level of event tracer debug logging.
*/
EventTracerDebugLogLevel event_tracer_debug_level() {
return event_tracer_debug_level_;
}
/**
* Set the level of event tracer profiling that is desired.
*/
void set_event_tracer_profiling_level(
EventTracerProfilingLevel profiling_level) {
event_tracer_profiling_level_ = profiling_level;
}
/**
* Return the current level of event tracer profiling.
*/
EventTracerProfilingLevel event_tracer_profiling_level() {
return event_tracer_profiling_level_;
}
/**
* Return the current status of intermediate outputs logging mode.
*/
bool intermediate_outputs_logging_status() {
return log_intermediate_tensors_;
}
/**
* Get the current chain id.
*
* @return Current chain id.
*/
ChainID current_chain_id() {
return chain_id_;
}
/**
* Get the current debug handle.
*
* @return Current debug handle.
*/
DebugHandle current_debug_handle() {
return debug_handle_;
}
virtual ~EventTracer() {}
protected:
ChainID chain_id_ = kUnsetChainId;
DebugHandle debug_handle_ = kUnsetDebugHandle;
bool event_tracer_enable_debugging_ = false;
bool log_intermediate_tensors_ = false;
int bundled_input_index_ = kUnsetBundledInputIndex;
EventTracerDebugLogLevel event_tracer_debug_level_ =
EventTracerDebugLogLevel::kNoLogging;
EventTracerProfilingLevel event_tracer_profiling_level_ =
EventTracerProfilingLevel::kProfileAllEvents;
};
} // namespace runtime
} // namespace executorch
namespace torch {
namespace executor {
// TODO(T197294990): Remove these deprecated aliases once all users have moved
// to the new `::executorch` namespaces.
using ::executorch::runtime::AllocatorID;
using ::executorch::runtime::ChainID;
using ::executorch::runtime::DebugHandle;
using ::executorch::runtime::DelegateDebugIdType;
using ::executorch::runtime::DelegateDebugIntId;
using ::executorch::runtime::EventTracer;
using ::executorch::runtime::EventTracerDebugLogLevel;
using ::executorch::runtime::EventTracerEntry;
using ::executorch::runtime::kUnsetBundledInputIndex;
using ::executorch::runtime::kUnsetChainId;
using ::executorch::runtime::kUnsetDebugHandle;
using ::executorch::runtime::kUnsetDelegateDebugIntId;
using ::executorch::runtime::LoggedEValueType;
} // namespace executor
} // namespace torch