• 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__) || 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