• 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/compiler.h"
25 #include "perfetto/tracing/internal/track_event_data_source.h"
26 #include "perfetto/tracing/track_event_category_registry.h"
27 
28 // Ignore GCC warning about a missing argument for a variadic macro parameter.
29 #if defined(__GNUC__) || defined(__clang__)
30 #pragma GCC system_header
31 #endif
32 
33 // Defines data structures for backing a category registry.
34 //
35 // Each category has one enabled/disabled bit per possible data source instance.
36 // The bits are packed, i.e., each byte holds the state for instances. To
37 // improve cache locality, the bits for each instance are stored separately from
38 // the names of the categories:
39 //
40 //   byte 0                      byte 1
41 //   (inst0, inst1, ..., inst7), (inst0, inst1, ..., inst7)
42 //
43 #define PERFETTO_INTERNAL_DECLARE_CATEGORIES(...)                             \
44   namespace internal {                                                        \
45   constexpr ::perfetto::Category kCategories[] = {__VA_ARGS__};               \
46   constexpr size_t kCategoryCount =                                           \
47       sizeof(kCategories) / sizeof(kCategories[0]);                           \
48   /* The per-instance enable/disable state per category */                    \
49   PERFETTO_COMPONENT_EXPORT extern std::atomic<uint8_t>                       \
50       g_category_state_storage[kCategoryCount];                               \
51   /* The category registry which mediates access to the above structures. */  \
52   /* The registry is used for two purposes: */                                \
53   /**/                                                                        \
54   /*    1) For looking up categories at build (constexpr) time. */            \
55   /*    2) For declaring the per-namespace TrackEvent data source. */         \
56   /**/                                                                        \
57   /* Because usage #1 requires a constexpr type and usage #2 requires an */   \
58   /* extern type (to avoid declaring a type based on a translation-unit */    \
59   /* variable), we need two separate copies of the registry with different */ \
60   /* storage specifiers. */                                                   \
61   /**/                                                                        \
62   /* TODO(skyostil): Unify these using a C++17 inline constexpr variable. */  \
63   constexpr ::perfetto::internal::TrackEventCategoryRegistry                  \
64       kConstExprCategoryRegistry(kCategoryCount,                              \
65                                  &kCategories[0],                             \
66                                  &g_category_state_storage[0]);               \
67   PERFETTO_COMPONENT_EXPORT extern const ::perfetto::internal::               \
68       TrackEventCategoryRegistry kCategoryRegistry;                           \
69   static_assert(kConstExprCategoryRegistry.ValidateCategories(),              \
70                 "Invalid category names found");                              \
71   }  // namespace internal
72 
73 // In a .cc file, declares storage for each category's runtime state.
74 #define PERFETTO_INTERNAL_CATEGORY_STORAGE()             \
75   namespace internal {                                   \
76   PERFETTO_COMPONENT_EXPORT std::atomic<uint8_t>         \
77       g_category_state_storage[kCategoryCount];          \
78   PERFETTO_COMPONENT_EXPORT const ::perfetto::internal:: \
79       TrackEventCategoryRegistry kCategoryRegistry(      \
80           kCategoryCount,                                \
81           &kCategories[0],                               \
82           &g_category_state_storage[0]);                 \
83   }  // namespace internal
84 
85 // Defines the TrackEvent data source for the current track event namespace.
86 #define PERFETTO_INTERNAL_DECLARE_TRACK_EVENT_DATA_SOURCE() \
87   struct PERFETTO_COMPONENT_EXPORT TrackEvent               \
88       : public ::perfetto::internal::TrackEventDataSource<  \
89             TrackEvent, &internal::kCategoryRegistry> {}
90 
91 // At compile time, turns a category name represented by a static string into an
92 // index into the current category registry. A build error will be generated if
93 // the category hasn't been registered or added to the list of allowed dynamic
94 // categories. See PERFETTO_DEFINE_CATEGORIES.
95 #define PERFETTO_GET_CATEGORY_INDEX(category)                                  \
96   ::PERFETTO_TRACK_EVENT_NAMESPACE::internal::kConstExprCategoryRegistry.Find( \
97       category,                                                                \
98       ::PERFETTO_TRACK_EVENT_NAMESPACE::internal::IsDynamicCategory(category))
99 
100 // Generate a unique variable name with a given prefix.
101 #define PERFETTO_INTERNAL_CONCAT2(a, b) a##b
102 #define PERFETTO_INTERNAL_CONCAT(a, b) PERFETTO_INTERNAL_CONCAT2(a, b)
103 #define PERFETTO_UID(prefix) PERFETTO_INTERNAL_CONCAT(prefix, __LINE__)
104 
105 // Efficiently determines whether tracing is enabled for the given category, and
106 // if so, emits one trace event with the given arguments.
107 #define PERFETTO_INTERNAL_TRACK_EVENT(category, ...)                           \
108   do {                                                                         \
109     namespace tns = ::PERFETTO_TRACK_EVENT_NAMESPACE;                          \
110     /* Compute the category index outside the lambda to work around a */       \
111     /* GCC 7 bug */                                                            \
112     static constexpr auto PERFETTO_UID(                                        \
113         kCatIndex_ADD_TO_PERFETTO_DEFINE_CATEGORIES_IF_FAILS_) =               \
114         PERFETTO_GET_CATEGORY_INDEX(category);                                 \
115     if (tns::internal::IsDynamicCategory(category)) {                          \
116       tns::TrackEvent::CallIfEnabled(                                          \
117           [&](uint32_t instances) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {         \
118             tns::TrackEvent::TraceForCategory(instances, category,             \
119                                               ##__VA_ARGS__);                  \
120           });                                                                  \
121     } else {                                                                   \
122       tns::TrackEvent::CallIfCategoryEnabled(                                  \
123           PERFETTO_UID(kCatIndex_ADD_TO_PERFETTO_DEFINE_CATEGORIES_IF_FAILS_), \
124           [&](uint32_t instances) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {         \
125             tns::TrackEvent::TraceForCategory(                                 \
126                 instances,                                                     \
127                 PERFETTO_UID(                                                  \
128                     kCatIndex_ADD_TO_PERFETTO_DEFINE_CATEGORIES_IF_FAILS_),    \
129                 ##__VA_ARGS__);                                                \
130           });                                                                  \
131     }                                                                          \
132   } while (false)
133 
134 #define PERFETTO_INTERNAL_SCOPED_TRACK_EVENT(category, name, ...)             \
135   struct PERFETTO_UID(ScopedEvent) {                                          \
136     struct EventFinalizer {                                                   \
137       /* The parameter is an implementation detail. It allows the          */ \
138       /* anonymous struct to use aggregate initialization to invoke the    */ \
139       /* lambda (which emits the BEGIN event and returns an integer)       */ \
140       /* with the proper reference capture for any                         */ \
141       /* TrackEventArgumentFunction in |__VA_ARGS__|. This is required so  */ \
142       /* that the scoped event is exactly ONE line and can't escape the    */ \
143       /* scope if used in a single line if statement.                      */ \
144       EventFinalizer(...) {}                                                  \
145       ~EventFinalizer() { TRACE_EVENT_END(category); }                        \
146     } finalizer;                                                              \
147   } PERFETTO_UID(scoped_event) {                                              \
148     [&]() {                                                                   \
149       TRACE_EVENT_BEGIN(category, name, ##__VA_ARGS__);                       \
150       return 0;                                                               \
151     }()                                                                       \
152   }
153 
154 #define PERFETTO_INTERNAL_CATEGORY_ENABLED(category)                         \
155   (::PERFETTO_TRACK_EVENT_NAMESPACE::internal::IsDynamicCategory(category)   \
156        ? ::PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent::                      \
157              IsDynamicCategoryEnabled(::perfetto::DynamicCategory(category)) \
158        : ::PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent::IsCategoryEnabled(    \
159              PERFETTO_GET_CATEGORY_INDEX(category)))
160 
161 #endif  // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_MACROS_H_
162