• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_MACROS_H_
18 #define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_MACROS_H_
19 
20 // This file contains underlying macros for the trace point track event
21 // implementation. Perfetto API users typically don't need to use anything here
22 // directly.
23 
24 #include "perfetto/base/thread_annotations.h"
25 #include "perfetto/tracing/internal/track_event_data_source.h"
26 #include "perfetto/tracing/string_helpers.h"
27 #include "perfetto/tracing/track_event_category_registry.h"
28 
29 #if defined(__GNUC__) || defined(__clang__)
30 #if defined(__clang__)
31 #pragma clang diagnostic push
32 // Fix 'error: #pragma system_header ignored in main file' for clang in Google3.
33 #pragma clang diagnostic ignored "-Wpragma-system-header-outside-header"
34 #endif
35 
36 // Ignore GCC warning about a missing argument for a variadic macro parameter.
37 #pragma GCC system_header
38 
39 #if defined(__clang__)
40 #pragma clang diagnostic pop
41 #endif
42 #endif
43 
44 // Defines data structures for backing a category registry.
45 //
46 // Each category has one enabled/disabled bit per possible data source instance.
47 // The bits are packed, i.e., each byte holds the state for instances. To
48 // improve cache locality, the bits for each instance are stored separately from
49 // the names of the categories:
50 //
51 //   byte 0                      byte 1
52 //   (inst0, inst1, ..., inst7), (inst0, inst1, ..., inst7)
53 //
54 #define PERFETTO_INTERNAL_DECLARE_CATEGORIES(attrs, ...)                      \
55   namespace internal {                                                        \
56   constexpr ::perfetto::Category kCategories[] = {__VA_ARGS__};               \
57   constexpr size_t kCategoryCount =                                           \
58       sizeof(kCategories) / sizeof(kCategories[0]);                           \
59   /* The per-instance enable/disable state per category */                    \
60   attrs extern std::atomic<uint8_t> g_category_state_storage[kCategoryCount]; \
61   /* The category registry which mediates access to the above structures. */  \
62   /* The registry is used for two purposes: */                                \
63   /**/                                                                        \
64   /*    1) For looking up categories at build (constexpr) time. */            \
65   /*    2) For declaring the per-namespace TrackEvent data source. */         \
66   /**/                                                                        \
67   /* Because usage #1 requires a constexpr type and usage #2 requires an */   \
68   /* extern type (to avoid declaring a type based on a translation-unit */    \
69   /* variable), we need two separate copies of the registry with different */ \
70   /* storage specifiers. */                                                   \
71   /**/                                                                        \
72   /* Note that because of a Clang/Windows bug, the constexpr category */      \
73   /* registry isn't given the enabled/disabled state array. All access */     \
74   /* to the category states should therefore be done through the */           \
75   /* non-constexpr registry. See */                                           \
76   /* https://bugs.llvm.org/show_bug.cgi?id=51558 */                           \
77   /**/                                                                        \
78   /* TODO(skyostil): Unify these using a C++17 inline constexpr variable. */  \
79   constexpr ::perfetto::internal::TrackEventCategoryRegistry                  \
80       kConstExprCategoryRegistry(kCategoryCount, &kCategories[0], nullptr);   \
81   attrs extern const ::perfetto::internal::TrackEventCategoryRegistry         \
82       kCategoryRegistry;                                                      \
83   static_assert(kConstExprCategoryRegistry.ValidateCategories(),              \
84                 "Invalid category names found");                              \
85   }  // namespace internal
86 
87 // In a .cc file, declares storage for each category's runtime state.
88 #define PERFETTO_INTERNAL_CATEGORY_STORAGE(attrs)                      \
89   namespace internal {                                                 \
90   attrs std::atomic<uint8_t> g_category_state_storage[kCategoryCount]; \
91   attrs const ::perfetto::internal::TrackEventCategoryRegistry         \
92       kCategoryRegistry(kCategoryCount,                                \
93                         &kCategories[0],                               \
94                         &g_category_state_storage[0]);                 \
95   }  // namespace internal
96 
97 // Defines the TrackEvent data source for the current track event namespace.
98 // `virtual ~TrackEvent` is added to avoid `-Wweak-vtables` warning.
99 // Learn more : aosp/2019906
100 #define PERFETTO_INTERNAL_DECLARE_TRACK_EVENT_DATA_SOURCE(attrs)               \
101   struct attrs TrackEvent : public ::perfetto::internal::TrackEventDataSource< \
102                                 TrackEvent, &internal::kCategoryRegistry> {    \
103     virtual ~TrackEvent();                                                     \
104   }
105 
106 #define PERFETTO_INTERNAL_DEFINE_TRACK_EVENT_DATA_SOURCE() \
107   TrackEvent::~TrackEvent() = default;
108 
109 // At compile time, turns a category name represented by a static string into an
110 // index into the current category registry. A build error will be generated if
111 // the category hasn't been registered or added to the list of allowed dynamic
112 // categories. See PERFETTO_DEFINE_CATEGORIES.
113 #define PERFETTO_GET_CATEGORY_INDEX(category)                                \
114   PERFETTO_TRACK_EVENT_NAMESPACE::internal::kConstExprCategoryRegistry.Find( \
115       category,                                                              \
116       ::PERFETTO_TRACK_EVENT_NAMESPACE::internal::IsDynamicCategory(category))
117 
118 // Generate a unique variable name with a given prefix.
119 #define PERFETTO_INTERNAL_CONCAT2(a, b) a##b
120 #define PERFETTO_INTERNAL_CONCAT(a, b) PERFETTO_INTERNAL_CONCAT2(a, b)
121 #define PERFETTO_UID(prefix) PERFETTO_INTERNAL_CONCAT(prefix, __LINE__)
122 
123 #if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_MSVC)
124 // MSVC with /permissive- fails to build without this. Probably a compiler bug.
125 #define PERFETTO_INTERNAL_STATIC_FOR_MSVC static
126 #else
127 // On the other hand, if we add static with clang, binary size of the chromium
128 // build will increase dramatically.
129 #define PERFETTO_INTERNAL_STATIC_FOR_MSVC
130 #endif
131 
132 // Efficiently determines whether tracing is enabled for the given category, and
133 // if so, emits one trace event with the given arguments.
134 #define PERFETTO_INTERNAL_TRACK_EVENT_WITH_METHOD(method, category, name, ...) \
135   do {                                                                         \
136     ::perfetto::internal::ValidateEventNameType<decltype(name)>();             \
137     namespace tns = PERFETTO_TRACK_EVENT_NAMESPACE;                            \
138     /* Compute the category index outside the lambda to work around a */       \
139     /* GCC 7 bug */                                                            \
140     PERFETTO_INTERNAL_STATIC_FOR_MSVC constexpr auto PERFETTO_UID(             \
141         kCatIndex_ADD_TO_PERFETTO_DEFINE_CATEGORIES_IF_FAILS_) =               \
142         PERFETTO_GET_CATEGORY_INDEX(category);                                 \
143     if (::PERFETTO_TRACK_EVENT_NAMESPACE::internal::IsDynamicCategory(         \
144             category)) {                                                       \
145       tns::TrackEvent::CallIfEnabled(                                          \
146           [&](uint32_t instances) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {         \
147             tns::TrackEvent::method(                                           \
148                 instances, category,                                           \
149                 ::perfetto::internal::DecayEventNameType(name),                \
150                 ##__VA_ARGS__);                                                \
151           });                                                                  \
152     } else {                                                                   \
153       tns::TrackEvent::CallIfCategoryEnabled(                                  \
154           PERFETTO_UID(kCatIndex_ADD_TO_PERFETTO_DEFINE_CATEGORIES_IF_FAILS_), \
155           [&](uint32_t instances) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {         \
156             tns::TrackEvent::method(                                           \
157                 instances,                                                     \
158                 PERFETTO_UID(                                                  \
159                     kCatIndex_ADD_TO_PERFETTO_DEFINE_CATEGORIES_IF_FAILS_),    \
160                 ::perfetto::internal::DecayEventNameType(name),                \
161                 ##__VA_ARGS__);                                                \
162           });                                                                  \
163     }                                                                          \
164   } while (false)
165 
166 // C++17 doesn't like a move constructor being defined for the EventFinalizer
167 // class but C++11 and MSVC doesn't compile without it being defined so support
168 // both.
169 #if !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_MSVC)
170 #define PERFETTO_INTERNAL_EVENT_FINALIZER_KEYWORD delete
171 #else
172 #define PERFETTO_INTERNAL_EVENT_FINALIZER_KEYWORD default
173 #endif
174 
175 #define PERFETTO_INTERNAL_SCOPED_EVENT_FINALIZER(category)                    \
176   struct PERFETTO_UID(ScopedEvent) {                                          \
177     struct EventFinalizer {                                                   \
178       /* The parameter is an implementation detail. It allows the          */ \
179       /* anonymous struct to use aggregate initialization to invoke the    */ \
180       /* lambda (which emits the BEGIN event and returns an integer)       */ \
181       /* with the proper reference capture for any                         */ \
182       /* TrackEventArgumentFunction in |__VA_ARGS__|. This is required so  */ \
183       /* that the scoped event is exactly ONE line and can't escape the    */ \
184       /* scope if used in a single line if statement.                      */ \
185       EventFinalizer(...) {}                                                  \
186       ~EventFinalizer() {                                                     \
187         TRACE_EVENT_END(category);                                            \
188       }                                                                       \
189                                                                               \
190       EventFinalizer(const EventFinalizer&) = delete;                         \
191       inline EventFinalizer& operator=(const EventFinalizer&) = delete;       \
192                                                                               \
193       EventFinalizer(EventFinalizer&&) =                                      \
194           PERFETTO_INTERNAL_EVENT_FINALIZER_KEYWORD;                          \
195       EventFinalizer& operator=(EventFinalizer&&) = delete;                   \
196     } finalizer;                                                              \
197   }
198 
199 #define PERFETTO_INTERNAL_SCOPED_TRACK_EVENT(category, name, ...) \
200   PERFETTO_INTERNAL_SCOPED_EVENT_FINALIZER(category)              \
201   PERFETTO_UID(scoped_event) {                                    \
202     [&]() {                                                       \
203       TRACE_EVENT_BEGIN(category, name, ##__VA_ARGS__);           \
204       return 0;                                                   \
205     }()                                                           \
206   }
207 
208 #if PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
209 // Required for TRACE_EVENT_WITH_FLOW legacy macros, which pass the bind_id as
210 // id.
211 #define PERFETTO_INTERNAL_SCOPED_LEGACY_TRACK_EVENT_WITH_ID(               \
212     category, name, track, flags, thread_id, id, ...)                      \
213   PERFETTO_INTERNAL_SCOPED_EVENT_FINALIZER(category)                       \
214   PERFETTO_UID(scoped_event) {                                             \
215     [&]() {                                                                \
216       PERFETTO_INTERNAL_TRACK_EVENT_WITH_METHOD(                           \
217           TraceForCategoryLegacyWithId, category, name,                    \
218           ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN, track, \
219           'B', flags, thread_id, id, ##__VA_ARGS__);                       \
220       return 0;                                                            \
221     }()                                                                    \
222   }
223 #endif  // PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
224 
225 #if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC) || \
226     PERFETTO_BUILDFLAG(PERFETTO_COMPILER_MSVC)
227 // On GCC versions <9 there's a bug that prevents using captured constant
228 // variables in constexpr evaluation inside a lambda:
229 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82643
230 // TODO(khokhlov): Remove this fallback after Perfetto moves to a more recent
231 // GCC version.
232 #define PERFETTO_INTERNAL_CATEGORY_ENABLED(category)                           \
233   (::PERFETTO_TRACK_EVENT_NAMESPACE::internal::IsDynamicCategory(category)     \
234        ? PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent::IsDynamicCategoryEnabled( \
235              ::perfetto::DynamicCategory(category))                            \
236        : PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent::IsCategoryEnabled(        \
237              PERFETTO_GET_CATEGORY_INDEX(category)))
238 #else  // !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
239 #define PERFETTO_INTERNAL_CATEGORY_ENABLED(category)                     \
240   [&]() -> bool {                                                        \
241     using PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent;                    \
242     using ::PERFETTO_TRACK_EVENT_NAMESPACE::internal::IsDynamicCategory; \
243     constexpr auto PERFETTO_UID(index) =                                 \
244         PERFETTO_GET_CATEGORY_INDEX(category);                           \
245     constexpr auto PERFETTO_UID(dynamic) = IsDynamicCategory(category);  \
246     return PERFETTO_UID(dynamic)                                         \
247                ? TrackEvent::IsDynamicCategoryEnabled(                   \
248                      ::perfetto::DynamicCategory(category))              \
249                : TrackEvent::IsCategoryEnabled(PERFETTO_UID(index));     \
250   }()
251 #endif  // !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
252 
253 // Emits an empty trace packet into the trace to ensure that the service can
254 // safely read the last event from the trace buffer. This can be used to
255 // periodically "flush" the last event on threads that don't support explicit
256 // flushing of the shared memory buffer chunk when the tracing session stops
257 // (e.g. thread pool workers in Chromium).
258 //
259 // This workaround is only required because the tracing service cannot safely
260 // read the last trace packet from an incomplete SMB chunk (crbug.com/1021571
261 // and b/162206162) when scraping the SMB. Adding an empty trace packet ensures
262 // that all prior events can be scraped by the service.
263 #define PERFETTO_INTERNAL_ADD_EMPTY_EVENT()                                \
264   do {                                                                     \
265     PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent::Trace(                     \
266         [](PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent::TraceContext ctx) { \
267           ctx.AddEmptyTracePacket();                                       \
268         });                                                                \
269   } while (false)
270 
271 #endif  // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_MACROS_H_
272