liyujie
2025-08-28 786ff4f4ca2374bdd9177f2e24b503d43e7a3b93
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
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#ifndef ANDROID_ML_NN_COMMON_TRACING_H
#define ANDROID_ML_NN_COMMON_TRACING_H
 
#define ATRACE_TAG ATRACE_TAG_NNAPI
#include "utils/Trace.h"
 
// Neural Networks API (NNAPI) systracing
//
// Primary goal of the tracing is to capture and present timings for NNAPI.
// (Other uses include providing visibility to split of execution between
// drivers and the CPU fallback, and the ability to visualize call sequences).
//
// The tracing has three parts:
//  1 Trace macros defined in this file and used throughout the codebase,
//    modelled after and using atrace. These implement a naming convention for
//    the tracepoints, interpreted by the systrace parser.
//  2 Android systrace (atrace) on-device capture and host-based analysis.
//  3 A systrace parser (TODO) to summarize the timings.
//
// For an overview and introduction, please refer to the "NNAPI Systrace design
// and HOWTO" (internal Docs for now). This header doesn't try to replicate all
// the information in that document. For the contract between traces in code and
// the statistics created by the systrace parser, see
// tools/systrace-parser/contract-between-code-and-parser.txt.
//
// Glossary:
// - Phase: stage in processing (e.g., Preparation, Compilation, Execution);
//   Overall phase nests rest, Execution nests Input/Output, Transformation,
//   Computation and Results; optionally Executions can be nested in a
//   Warmup and Benchmark - otherwise not nested (Initialization phase
//   functions may occur inside other phases but will be counted out during
//   analysis). Nested phases (other than Initialization) are analysed as a
//   breakdown of the parent phase.
// - Layer: component in the stack (from top to bottom: App, Runtime, IPC,
//   Driver/CPU). Calls to lower layers are typically nested within calls to upper
//   layers.
// - Bucket: unit of timing analysis, the combination of Phase and Layer (and
//   thus also typically nested).
// - Detail: specific unit being executed, typically a function.
 
// Convenience macros to be used in the code (phases defined below).
// (Macros so that string concatenation is done at compile time).
//
// These exist in three variants:
// - Simple (NNTRACE_<layer and potentially phase>) - to be used when only one
//   Phase is active within a scope
// - "Switch" (NNTRACE_<...>_SWITCH) - to be used when multiple Phases
//   share a scope (e.g., transformation of data and computation in same
//   function).
// - "Subtract" (NNTRACE_<...>_SUBTRACT) - to be used when nesting is violated
//   and the time should be subtracted from the parent scope
// Arguments:
// - phase: one of the NNTRACE_PHASE_* macros defined below.
// - detail: free-form string constant, typically function name.
// Example usage:
//   // Simple
//   int ANeuralNetworksMemory_createFromFd(...) {
//     NNTRACE_RT(NNTRACE_PHASE_PREPARATION, "ANeuralNetworksMemory_createFromFd");
//   }
//   // Switch
//   bool concatenationFloat32(...) {
//     NNTRACE_TRANS("concatenationFloat32");  // Transformation of data begins
//     ...
//     NNTRACE_COMP_SWITCH("optimized_ops::Concatenation"); // Transformation
//                                                          // ends and computation
//                                                          // begins
//   }
//   // Subtract
//   static int compile(...) {
//     NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "prepareModel");
//     device->getInterface()->prepareModel(..., preparedModelCallback);
//     preparedModelCallback->wait()
//   }
//   ErrorStatus VersionedIDevice::prepareModel(...) {
//     ... IPC work ...
//     {
//       NNTRACE_FULL_SUBTRACT(NNTRACE_LAYER_RUNTIME, NNTRACE_PHASE_COMPILATION,
//                             "VersionedIDevice::prepareModel");
//       ... Runtime work ...
//     }
//     ... IPC work ...
//   }
//
// Layer Application - For native applications (e.g., unit tests)
#define NNTRACE_APP(phase, detail) NNTRACE_FULL(NNTRACE_LAYER_APPLICATION, phase, detail)
#define NNTRACE_APP_SWITCH(phase, detail) \
        NNTRACE_FULL_SWITCH(NNTRACE_LAYER_APPLICATION, phase, detail)
// Layer Runtime - For the NNAPI runtime
#define NNTRACE_RT(phase, detail) NNTRACE_FULL(NNTRACE_LAYER_RUNTIME, phase, detail)
#define NNTRACE_RT_SWITCH(phase, detail) NNTRACE_FULL_SWITCH(NNTRACE_LAYER_RUNTIME, phase, detail)
// Layer CPU - CPU executor
#define NNTRACE_CPU(phase, detail) NNTRACE_FULL(NNTRACE_LAYER_CPU, phase, detail)
#define NNTRACE_COMP(detail) NNTRACE_FULL(NNTRACE_LAYER_CPU, \
                                          NNTRACE_PHASE_COMPUTATION, detail)
#define NNTRACE_COMP_SWITCH(detail) NNTRACE_FULL_SWITCH(NNTRACE_LAYER_CPU, \
                                                        NNTRACE_PHASE_COMPUTATION, detail)
#define NNTRACE_TRANS(detail) NNTRACE_FULL(NNTRACE_LAYER_CPU, \
                                           NNTRACE_PHASE_TRANSFORMATION, detail)
 
// Fully specified macros to be used when no convenience wrapper exists for your
// need.
#define NNTRACE_FULL(layer, phase, detail) NNTRACE_NAME_1(("[NN_" layer "_" phase "]" detail))
#define NNTRACE_FULL_SWITCH(layer, phase, detail) \
        NNTRACE_NAME_SWITCH(("[SW][NN_" layer "_" phase "]" detail))
#define NNTRACE_FULL_SUBTRACT(layer, phase, detail) \
        NNTRACE_NAME_1(("[SUB][NN_" layer "_" phase "]" detail))
// Raw macro without scoping requirements, for special cases
#define NNTRACE_FULL_RAW(layer, phase, detail) android::ScopedTrace PASTE(___tracer, __LINE__) \
        (ATRACE_TAG, ("[NN_" layer "_" phase "]" detail))
 
// Tracing buckets - for calculating timing summaries over.
//
// Application-only phases
#define NNTRACE_PHASE_OVERALL   "PO"    // Overall program, e.g., one benchmark case
#define NNTRACE_PHASE_WARMUP    "PWU"   // Warmup (nesting multiple executions)
#define NNTRACE_PHASE_BENCHMARK "PBM"   // Benchmark (nesting multiple executions)
// Main phases, usable by all layers
#define NNTRACE_PHASE_INITIALIZATION "PI" // Initialization - not related to a model
#define NNTRACE_PHASE_PREPARATION "PP"  // Model construction
#define NNTRACE_PHASE_COMPILATION "PC"  // Model compilation
#define NNTRACE_PHASE_EXECUTION "PE"    // Executing the model
#define NNTRACE_PHASE_TERMINATION "PT"  // Tearing down
#define NNTRACE_PHASE_UNSPECIFIED "PU"  // Helper code called from multiple phases
// Subphases of execution
#define NNTRACE_PHASE_INPUTS_AND_OUTPUTS "PIO"  // Setting inputs/outputs and allocating buffers
#define NNTRACE_PHASE_TRANSFORMATION "PTR"      // Transforming data for computation
#define NNTRACE_PHASE_COMPUTATION "PCO"         // Computing operations' outputs
#define NNTRACE_PHASE_RESULTS "PR"              // Reading out results
// Layers
#define NNTRACE_LAYER_APPLICATION "LA"
#define NNTRACE_LAYER_RUNTIME "LR"
#define NNTRACE_LAYER_IPC "LI"
#define NNTRACE_LAYER_DRIVER "LD"
#define NNTRACE_LAYER_CPU "LC"
#define NNTRACE_LAYER_OTHER "LO"
#define NNTRACE_LAYER_UTILITY "LU"              // Code used from multiple layers
 
 
// Implementation
//
// Almost same as ATRACE_NAME, but enforcing explicit distinction between
// phase-per-scope and switching phases.
//
// Basic trace, one per scope allowed to enforce disjointness
#define NNTRACE_NAME_1(name) android::ScopedTrace ___tracer_1(ATRACE_TAG, name)
// Switching trace, more than one per scope allowed, translated by
// systrace_parser.py. This is mainly useful for tracing multiple phases through
// one function / scope.
#define NNTRACE_NAME_SWITCH(name) android::ScopedTrace PASTE(___tracer, __LINE__) \
        (ATRACE_TAG, name); \
        (void)___tracer_1  // ensure switch is only used after a basic trace
 
 
// Disallow use of raw ATRACE macros
#undef ATRACE_NAME
#undef ATRACE_CALL
 
#endif // ANDROID_ML_NN_COMMON_TRACING_H