• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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