1 /* 2 * Copyright (C) 2023 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_PUBLIC_TE_CATEGORY_MACROS_H_ 18 #define INCLUDE_PERFETTO_PUBLIC_TE_CATEGORY_MACROS_H_ 19 20 #include "perfetto/public/track_event.h" 21 22 /* This header provides helper macros to list and register perfetto track event 23 categories. 24 25 Example: 26 27 ``` 28 #define MY_CATEGORIES(C) \ 29 C(c1, "c1", "My category 1 description", "tag1", "tag2") \ 30 C(c2, "c2", "My category 2 description", "tag1") \ 31 C(c3, "c3", "My category 3 description") 32 33 PERFETTO_TE_CATEGORIES_DEFINE(MY_CATEGORIES) 34 35 //... 36 37 int main() { 38 //.. 39 PERFETTO_TE_REGISTER_CATEGORIES(MY_CATEGORIES); 40 ``` 41 42 Three categories are defined (as global variables) `c1`, `c2` and `c3`. The 43 tracing service knows them as "c1", "c2" and "c3" respectively. The extra 44 strings in `C()` after the description are the tags (there can be zero to 45 four tags). 46 */ 47 48 // Implementation details: 49 // 50 // The macros have been tested on GCC, clang and MSVC. The MSVC traditional 51 // preprocessor behaves slightly differently (see 52 // https://learn.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview) 53 // so it sometimes requires an extra level of indirection with an intermediate 54 // macro. 55 // 56 // The header is not technically C99 or C++11 standard compliant for a single 57 // reason: sometimes `...` receives zero arguments (this has been relaxed in the 58 // post 2020 standards). Despite this, the header never uses __VA_ARGS__ when 59 // it would expand to zero arguments, because the behavior is compiler 60 // dependent. 61 62 #if defined(__GNUC__) || defined(__clang__) 63 #if defined(__clang__) 64 #pragma clang diagnostic push 65 // Fix 'error: #pragma system_header ignored in main file' for clang in Google3. 66 #pragma clang diagnostic ignored "-Wpragma-system-header-outside-header" 67 #endif 68 69 // Ignore GCC warning about a missing argument for a variadic macro parameter. 70 #pragma GCC system_header 71 72 #if defined(__clang__) 73 #pragma clang diagnostic pop 74 #endif 75 #endif 76 77 #define PERFETTO_I_TE_CAT_DESCRIPTION_GET(D, ...) D 78 #define PERFETTO_I_TE_CAT_DESCRIPTION_CALL(MACRO, ARGS) MACRO ARGS 79 #define PERFETTO_I_TE_CAT_DESCRIPTION(D, ...) \ 80 PERFETTO_I_TE_CAT_DESCRIPTION_CALL(PERFETTO_I_TE_CAT_DESCRIPTION_GET, (D)) 81 82 #define PERFETTO_I_TE_CAT_NUM_TAGS_(A, B, C, D, E, N, ...) N 83 #define PERFETTO_I_TE_CAT_NUM_TAGS(...) \ 84 PERFETTO_I_TE_CAT_NUM_TAGS_(__VA_ARGS__, 4, 3, 2, 1, 0) 85 86 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_0(...) 87 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_1(NAME, DESC, TAG1) \ 88 static const char* NAME##_tags[] = {TAG1}; 89 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_2(NAME, DESC, TAG1, TAG2) \ 90 static const char* NAME##_tags[] = {TAG1, TAG2}; 91 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_3(NAME, DESC, TAG1, TAG2, TAG3) \ 92 static const char* NAME##_tags[] = {TAG1, TAG2, TAG3}; 93 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_4(NAME, DESC, TAG1, TAG2, TAG3, TAG4) \ 94 static const char* NAME##_tags[] = {TAG1, TAG2, TAG3, TAG4}; 95 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_GET_MACRO(NAME, _1, _2, _3, _4, MACRO, \ 96 ...) \ 97 MACRO 98 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_CALL(MACRO, ARGS) MACRO ARGS 99 #define PERFETTO_I_TE_CAT_DEFINE_TAGS(NAME, ...) \ 100 PERFETTO_I_TE_CAT_DEFINE_TAGS_CALL( \ 101 PERFETTO_I_TE_CAT_DEFINE_TAGS_GET_MACRO( \ 102 __VA_ARGS__, PERFETTO_I_TE_CAT_DEFINE_TAGS_4, \ 103 PERFETTO_I_TE_CAT_DEFINE_TAGS_3, PERFETTO_I_TE_CAT_DEFINE_TAGS_2, \ 104 PERFETTO_I_TE_CAT_DEFINE_TAGS_1, PERFETTO_I_TE_CAT_DEFINE_TAGS_0), \ 105 (NAME, __VA_ARGS__)) 106 107 #define PERFETTO_I_TE_CAT_LIST_TAGS_0(NAME) PERFETTO_NULL 108 #define PERFETTO_I_TE_CAT_LIST_TAGS_1(NAME) NAME##_tags 109 #define PERFETTO_I_TE_CAT_LIST_TAGS_2(NAME) NAME##_tags 110 #define PERFETTO_I_TE_CAT_LIST_TAGS_3(NAME) NAME##_tags 111 #define PERFETTO_I_TE_CAT_LIST_TAGS_4(NAME) NAME##_tags 112 #define PERFETTO_I_TE_CAT_LIST_TAGS_GET_MACRO(NAME, A, B, C, D, MACRO, ...) \ 113 MACRO 114 #define PERFETTO_I_TE_CAT_LIST_TAGS_CALL(MACRO, ARGS) MACRO ARGS 115 #define PERFETTO_I_TE_CAT_LIST_TAGS(NAME, ...) \ 116 PERFETTO_I_TE_CAT_LIST_TAGS_CALL( \ 117 PERFETTO_I_TE_CAT_LIST_TAGS_GET_MACRO( \ 118 __VA_ARGS__, PERFETTO_I_TE_CAT_LIST_TAGS_4, \ 119 PERFETTO_I_TE_CAT_LIST_TAGS_3, PERFETTO_I_TE_CAT_LIST_TAGS_2, \ 120 PERFETTO_I_TE_CAT_LIST_TAGS_1, PERFETTO_I_TE_CAT_LIST_TAGS_0), \ 121 (NAME)) 122 123 #define PERFETTO_I_TE_CAT_DEFINE_CAT(NAME, NAME_STR, ...) \ 124 PERFETTO_I_TE_CAT_DEFINE_TAGS(NAME, __VA_ARGS__) \ 125 struct PerfettoTeCategory NAME = { \ 126 &perfetto_atomic_false, \ 127 PERFETTO_NULL, \ 128 { \ 129 NAME_STR, \ 130 PERFETTO_I_TE_CAT_DESCRIPTION(__VA_ARGS__), \ 131 PERFETTO_I_TE_CAT_LIST_TAGS(NAME, __VA_ARGS__), \ 132 PERFETTO_I_TE_CAT_NUM_TAGS(__VA_ARGS__), \ 133 }, \ 134 0, \ 135 }; 136 137 #define PERFETTO_I_TE_CAT_DECLARE_CAT(NAME, ...) \ 138 extern struct PerfettoTeCategory NAME; 139 140 #define PERFETTO_I_TE_CAT_LIST_CAT_COMMA(NAME, ...) &NAME, 141 142 // Declares (without defining) categories as global variables. `MACROS` is used 143 // to specify the categories, see above for an example. 144 #define PERFETTO_TE_CATEGORIES_DECLARE(MACRO) \ 145 MACRO(PERFETTO_I_TE_CAT_DECLARE_CAT) 146 147 // Defines categories as global variables. `MACROS` is used to specify the 148 // categories, see above for an example. 149 #define PERFETTO_TE_CATEGORIES_DEFINE(MACRO) \ 150 PERFETTO_TE_CATEGORIES_DECLARE(MACRO) \ 151 MACRO(PERFETTO_I_TE_CAT_DEFINE_CAT) 152 153 // Registers categories defined with PERFETTO_TE_CATEGORIES_DEFINE(MACRO). 154 #define PERFETTO_TE_REGISTER_CATEGORIES(MACRO) \ 155 do { \ 156 struct PerfettoTeCategory* perfetto_i_cat_registry[] = { \ 157 MACRO(PERFETTO_I_TE_CAT_LIST_CAT_COMMA)}; \ 158 PerfettoTeRegisterCategories( \ 159 perfetto_i_cat_registry, \ 160 sizeof(perfetto_i_cat_registry) / sizeof(perfetto_i_cat_registry[0])); \ 161 PerfettoTePublishCategories(); \ 162 } while (0) 163 164 // Unregisters categories defined with PERFETTO_TE_CATEGORIES_DEFINE(MACRO). 165 // 166 // WARNING: The categories cannot be used for tracing anymore after this. 167 // Executing PERFETTO_TE() on unregistered categories will cause a null pointer 168 // dereference. 169 #define PERFETTO_TE_UNREGISTER_CATEGORIES(MACRO) \ 170 do { \ 171 struct PerfettoTeCategory* perfetto_i_cat_registry[] = { \ 172 MACRO(PERFETTO_I_TE_CAT_LIST_CAT_COMMA)}; \ 173 PerfettoTeUnregisterCategories( \ 174 perfetto_i_cat_registry, \ 175 sizeof(perfetto_i_cat_registry) / sizeof(perfetto_i_cat_registry[0])); \ 176 PerfettoTePublishCategories(); \ 177 } while (0) 178 179 #endif // INCLUDE_PERFETTO_PUBLIC_TE_CATEGORY_MACROS_H_ 180