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