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