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__) 63 #pragma GCC system_header 64 #endif 65 66 #define PERFETTO_I_TE_CAT_DESCRIPTION_GET(D, ...) D 67 #define PERFETTO_I_TE_CAT_DESCRIPTION_CALL(MACRO, ARGS) MACRO ARGS 68 #define PERFETTO_I_TE_CAT_DESCRIPTION(D, ...) \ 69 PERFETTO_I_TE_CAT_DESCRIPTION_CALL(PERFETTO_I_TE_CAT_DESCRIPTION_GET, (D)) 70 71 #define PERFETTO_I_TE_CAT_NUM_TAGS_(A, B, C, D, E, N, ...) N 72 #define PERFETTO_I_TE_CAT_NUM_TAGS(...) \ 73 PERFETTO_I_TE_CAT_NUM_TAGS_(__VA_ARGS__, 4, 3, 2, 1, 0) 74 75 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_0(...) 76 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_1(NAME, DESC, TAG1) \ 77 static const char* NAME##_tags[] = {TAG1}; 78 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_2(NAME, DESC, TAG1, TAG2) \ 79 static const char* NAME##_tags[] = {TAG1, TAG2}; 80 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_3(NAME, DESC, TAG1, TAG2, TAG3) \ 81 static const char* NAME##_tags[] = {TAG1, TAG2, TAG3}; 82 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_4(NAME, DESC, TAG1, TAG2, TAG3, TAG4) \ 83 static const char* NAME##_tags[] = {TAG1, TAG2, TAG3, TAG4}; 84 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_GET_MACRO(NAME, _1, _2, _3, _4, MACRO, \ 85 ...) \ 86 MACRO 87 #define PERFETTO_I_TE_CAT_DEFINE_TAGS_CALL(MACRO, ARGS) MACRO ARGS 88 #define PERFETTO_I_TE_CAT_DEFINE_TAGS(NAME, ...) \ 89 PERFETTO_I_TE_CAT_DEFINE_TAGS_CALL( \ 90 PERFETTO_I_TE_CAT_DEFINE_TAGS_GET_MACRO( \ 91 __VA_ARGS__, PERFETTO_I_TE_CAT_DEFINE_TAGS_4, \ 92 PERFETTO_I_TE_CAT_DEFINE_TAGS_3, PERFETTO_I_TE_CAT_DEFINE_TAGS_2, \ 93 PERFETTO_I_TE_CAT_DEFINE_TAGS_1, PERFETTO_I_TE_CAT_DEFINE_TAGS_0), \ 94 (NAME, __VA_ARGS__)) 95 96 #define PERFETTO_I_TE_CAT_LIST_TAGS_0(NAME) PERFETTO_NULL 97 #define PERFETTO_I_TE_CAT_LIST_TAGS_1(NAME) NAME##_tags 98 #define PERFETTO_I_TE_CAT_LIST_TAGS_2(NAME) NAME##_tags 99 #define PERFETTO_I_TE_CAT_LIST_TAGS_3(NAME) NAME##_tags 100 #define PERFETTO_I_TE_CAT_LIST_TAGS_4(NAME) NAME##_tags 101 #define PERFETTO_I_TE_CAT_LIST_TAGS_GET_MACRO(NAME, A, B, C, D, MACRO, ...) \ 102 MACRO 103 #define PERFETTO_I_TE_CAT_LIST_TAGS_CALL(MACRO, ARGS) MACRO ARGS 104 #define PERFETTO_I_TE_CAT_LIST_TAGS(NAME, ...) \ 105 PERFETTO_I_TE_CAT_LIST_TAGS_CALL( \ 106 PERFETTO_I_TE_CAT_LIST_TAGS_GET_MACRO( \ 107 __VA_ARGS__, PERFETTO_I_TE_CAT_LIST_TAGS_4, \ 108 PERFETTO_I_TE_CAT_LIST_TAGS_3, PERFETTO_I_TE_CAT_LIST_TAGS_2, \ 109 PERFETTO_I_TE_CAT_LIST_TAGS_1, PERFETTO_I_TE_CAT_LIST_TAGS_0), \ 110 (NAME)) 111 112 #define PERFETTO_I_TE_CAT_DEFINE_CAT(NAME, NAME_STR, ...) \ 113 PERFETTO_I_TE_CAT_DEFINE_TAGS(NAME, __VA_ARGS__) \ 114 struct PerfettoTeCategory NAME = { \ 115 &perfetto_atomic_false, \ 116 PERFETTO_NULL, \ 117 { \ 118 NAME_STR, \ 119 PERFETTO_I_TE_CAT_DESCRIPTION(__VA_ARGS__), \ 120 PERFETTO_I_TE_CAT_LIST_TAGS(NAME, __VA_ARGS__), \ 121 PERFETTO_I_TE_CAT_NUM_TAGS(__VA_ARGS__), \ 122 }, \ 123 0, \ 124 }; 125 126 #define PERFETTO_I_TE_CAT_DECLARE_CAT(NAME, ...) \ 127 extern struct PerfettoTeCategory NAME; 128 129 #define PERFETTO_I_TE_CAT_LIST_CAT_COMMA(NAME, ...) &NAME, 130 131 // Declares (without defining) categories as global variables. `MACROS` is used 132 // to specify the categories, see above for an example. 133 #define PERFETTO_TE_CATEGORIES_DECLARE(MACRO) \ 134 MACRO(PERFETTO_I_TE_CAT_DECLARE_CAT) 135 136 // Defines categories as global variables. `MACROS` is used to specify the 137 // categories, see above for an example. 138 #define PERFETTO_TE_CATEGORIES_DEFINE(MACRO) \ 139 PERFETTO_TE_CATEGORIES_DECLARE(MACRO) \ 140 MACRO(PERFETTO_I_TE_CAT_DEFINE_CAT) 141 142 // Registers categories defined with PERFETTO_TE_CATEGORIES_DEFINE(MACRO). 143 #define PERFETTO_TE_REGISTER_CATEGORIES(MACRO) \ 144 do { \ 145 struct PerfettoTeCategory* perfetto_i_cat_registry[] = { \ 146 MACRO(PERFETTO_I_TE_CAT_LIST_CAT_COMMA)}; \ 147 PerfettoTeRegisterCategories( \ 148 perfetto_i_cat_registry, \ 149 sizeof(perfetto_i_cat_registry) / sizeof(perfetto_i_cat_registry[0])); \ 150 PerfettoTePublishCategories(); \ 151 } while (0) 152 153 // Unregisters categories defined with PERFETTO_TE_CATEGORIES_DEFINE(MACRO). 154 // 155 // WARNING: The categories cannot be used for tracing anymore after this. 156 // Executing PERFETTO_TE() on unregistered categories will cause a null pointer 157 // dereference. 158 #define PERFETTO_TE_UNREGISTER_CATEGORIES(MACRO) \ 159 do { \ 160 struct PerfettoTeCategory* perfetto_i_cat_registry[] = { \ 161 MACRO(PERFETTO_I_TE_CAT_LIST_CAT_COMMA)}; \ 162 PerfettoTeUnregisterCategories( \ 163 perfetto_i_cat_registry, \ 164 sizeof(perfetto_i_cat_registry) / sizeof(perfetto_i_cat_registry[0])); \ 165 PerfettoTePublishCategories(); \ 166 } while (0) 167 168 #endif // INCLUDE_PERFETTO_PUBLIC_TE_CATEGORY_MACROS_H_ 169