1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //
6 // Internal declarations used by the C tracing macros.
7 // This is not part of the public API: use <trace/event.h> instead.
8 //
9 
10 #ifndef TRACE_INTERNAL_EVENT_INTERNAL_H_
11 #define TRACE_INTERNAL_EVENT_INTERNAL_H_
12 
13 #include <zircon/compiler.h>
14 
15 #include <trace-engine/instrumentation.h>
16 #include <trace/internal/event_args.h>
17 
18 __BEGIN_CDECLS
19 
20 // Variable used to refer to the current trace context.
21 #define TRACE_INTERNAL_CONTEXT __trace_context
22 
23 // Variable used to hold call-site cache state.
24 #define TRACE_INTERNAL_SITE_STATE __trace_site_state
25 
26 // Variable used to refer to the current trace category's string ref.
27 #define TRACE_INTERNAL_CATEGORY_REF __trace_category_ref
28 
29 // Variable used to contain the array of arguments.
30 #define TRACE_INTERNAL_ARGS __trace_args
31 
32 // Number of arguments recorded in |TRACE_INTERNAL_ARGS|.
33 // TODO(PT-67): Rename this, conventions says TRACE_NUM_ARGS should call this.
34 #define TRACE_INTERNAL_NUM_ARGS (sizeof(TRACE_INTERNAL_ARGS) / sizeof(TRACE_INTERNAL_ARGS[0]))
35 
36 // BEGIN SECTION OF DEPRECATED MACROS, USED BY EXTERNAL CODE
37 // TODO(PT-67): These will be replaced with the NEW_ versions when all existing
38 // code is cleaned up to not use these.
39 
40 // Makes a string literal string ref.
41 #define TRACE_INTERNAL_MAKE_LITERAL_STRING_REF(string_literal_value) \
42     (trace_context_make_registered_string_literal(                   \
43         TRACE_INTERNAL_CONTEXT, (string_literal_value)))
44 
45 // Makes a trace argument.
46 #ifdef __cplusplus
47 #define TRACE_INTERNAL_HOLD_ARG(var_name, idx, name_literal, arg_value) \
48     const auto& arg##idx = (arg_value);
49 #define TRACE_INTERNAL_MAKE_ARG(var_name, idx, name_literal, arg_value)  \
50     { .name_ref = {.encoded_value = 0, .inline_string = (name_literal)}, \
51       .value = ::trace::internal::MakeArgumentValue(arg##idx) }
52 #else
53 #define TRACE_INTERNAL_MAKE_ARG(var_name, idx, name_literal, arg_value)  \
54     { .name_ref = {.encoded_value = 0, .inline_string = (name_literal)}, \
55       .value = (arg_value) }
56 #endif // __cplusplus
57 
58 #ifdef __cplusplus
59 #define TRACE_INTERNAL_DECLARE_ARGS(args...)                                       \
60     TRACE_INTERNAL_APPLY_PAIRWISE(TRACE_INTERNAL_HOLD_ARG, ignore, args)           \
61     trace_arg_t TRACE_INTERNAL_ARGS[] = {                                          \
62         TRACE_INTERNAL_APPLY_PAIRWISE_CSV(TRACE_INTERNAL_MAKE_ARG, ignore, args)}; \
63     static_assert(TRACE_INTERNAL_NUM_ARGS <= TRACE_MAX_ARGS, "too many args")
64 #else
65 #define TRACE_INTERNAL_DECLARE_ARGS(args...)                                       \
66     trace_arg_t TRACE_INTERNAL_ARGS[] = {                                          \
67         TRACE_INTERNAL_APPLY_PAIRWISE_CSV(TRACE_INTERNAL_MAKE_ARG, ignore, args)}; \
68     static_assert(TRACE_INTERNAL_NUM_ARGS <= TRACE_MAX_ARGS, "too many args")
69 #endif // __cplusplus
70 
71 // END SECTION OF DEPRECATED MACROS, USED BY EXTERNAL CODE
72 
73 // Obtains a unique identifier name within the containing scope.
74 #define TRACE_INTERNAL_SCOPE_LABEL() TRACE_INTERNAL_SCOPE_LABEL_(__COUNTER__)
75 #define TRACE_INTERNAL_SCOPE_LABEL_(token) TRACE_INTERNAL_SCOPE_LABEL__(token)
76 #define TRACE_INTERNAL_SCOPE_LABEL__(token) __trace_scope_##token
77 
78 // Scaffolding for a trace macro that does not have a category.
79 #ifndef NTRACE
80 #define TRACE_INTERNAL_SIMPLE_RECORD(stmt, args...)                 \
81     do {                                                            \
82         trace_context_t* TRACE_INTERNAL_CONTEXT =                   \
83             trace_acquire_context();                                \
84         if (unlikely(TRACE_INTERNAL_CONTEXT)) {                     \
85             TRACE_INTERNAL_NEW_DECLARE_ARGS(TRACE_INTERNAL_CONTEXT, \
86                                             TRACE_INTERNAL_ARGS,    \
87                                             args);                  \
88             stmt;                                                   \
89         }                                                           \
90     } while (0)
91 #else
92 #define TRACE_INTERNAL_SIMPLE_RECORD(stmt, args...)                 \
93     do {                                                            \
94         if (0) {                                                    \
95             trace_context_t* TRACE_INTERNAL_CONTEXT = 0;            \
96             TRACE_INTERNAL_NEW_DECLARE_ARGS(TRACE_INTERNAL_CONTEXT, \
97                                             TRACE_INTERNAL_ARGS,    \
98                                             args);                  \
99             stmt;                                                   \
100         }                                                           \
101     } while (0)
102 #endif // NTRACE
103 
104 // Scaffolding for a trace macro that has a category (such as a trace event).
105 #ifndef NTRACE
106 #define TRACE_INTERNAL_EVENT_RECORD(category_literal, stmt, args...) \
107     do {                                                                \
108         static trace_site_t TRACE_INTERNAL_SITE_STATE;                  \
109         trace_string_ref_t TRACE_INTERNAL_CATEGORY_REF;                 \
110         trace_context_t* TRACE_INTERNAL_CONTEXT =                       \
111             trace_acquire_context_for_category_cached(                  \
112                 (category_literal), &TRACE_INTERNAL_SITE_STATE,         \
113                 &TRACE_INTERNAL_CATEGORY_REF);                          \
114         if (unlikely(TRACE_INTERNAL_CONTEXT)) {                         \
115             TRACE_INTERNAL_NEW_DECLARE_ARGS(TRACE_INTERNAL_CONTEXT,     \
116                                             TRACE_INTERNAL_ARGS,        \
117                                             args);                      \
118             stmt;                                                       \
119         }                                                               \
120     } while (0)
121 #else
122 #define TRACE_INTERNAL_EVENT_RECORD(category_literal, stmt, args...) \
123     do {                                                             \
124         if (0) {                                                     \
125             trace_string_ref_t TRACE_INTERNAL_CATEGORY_REF;          \
126             trace_context_t* TRACE_INTERNAL_CONTEXT = 0;             \
127             TRACE_INTERNAL_NEW_DECLARE_ARGS(TRACE_INTERNAL_CONTEXT,  \
128                                             TRACE_INTERNAL_ARGS,     \
129                                             args);                   \
130             stmt;                                                    \
131         }                                                            \
132     } while (0)
133 #endif // NTRACE
134 
135 #define TRACE_INTERNAL_INSTANT(category_literal, name_literal, scope, args...)          \
136     do {                                                                                \
137         TRACE_INTERNAL_EVENT_RECORD(                                                    \
138             (category_literal),                                                         \
139             trace_internal_write_instant_event_record_and_release_context(              \
140                 TRACE_INTERNAL_CONTEXT,                                                 \
141                 &TRACE_INTERNAL_CATEGORY_REF,                                           \
142                 (name_literal), (scope), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
143             args);                                                                      \
144     } while (0)
145 
146 #define TRACE_INTERNAL_COUNTER(category_literal, name_literal, counter_id, args...)          \
147     do {                                                                                     \
148         TRACE_INTERNAL_EVENT_RECORD(                                                         \
149             (category_literal),                                                              \
150             trace_internal_write_counter_event_record_and_release_context(                   \
151                 TRACE_INTERNAL_CONTEXT,                                                      \
152                 &TRACE_INTERNAL_CATEGORY_REF,                                                \
153                 (name_literal), (counter_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
154             args);                                                                           \
155     } while (0)
156 
157 #define TRACE_INTERNAL_DURATION_BEGIN(category_literal, name_literal, args...)    \
158     do {                                                                          \
159         TRACE_INTERNAL_EVENT_RECORD(                                              \
160             (category_literal),                                                   \
161             trace_internal_write_duration_begin_event_record_and_release_context( \
162                 TRACE_INTERNAL_CONTEXT,                                           \
163                 &TRACE_INTERNAL_CATEGORY_REF,                                     \
164                 (name_literal), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS),    \
165             args);                                                                \
166     } while (0)
167 
168 #define TRACE_INTERNAL_DURATION_END(category_literal, name_literal, args...)    \
169     do {                                                                        \
170         TRACE_INTERNAL_EVENT_RECORD(                                            \
171             (category_literal),                                                 \
172             trace_internal_write_duration_end_event_record_and_release_context( \
173                 TRACE_INTERNAL_CONTEXT,                                         \
174                 &TRACE_INTERNAL_CATEGORY_REF,                                   \
175                 (name_literal), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS),  \
176             args);                                                              \
177     } while (0)
178 
179 #ifndef NTRACE
180 #define TRACE_INTERNAL_DECLARE_DURATION_SCOPE(variable, category_literal, name_literal) \
181     __attribute__((cleanup(trace_internal_cleanup_duration_scope)))                     \
182         trace_internal_duration_scope_t variable;                                       \
183     trace_internal_make_duration_scope(&variable, (category_literal), (name_literal))
184 #define TRACE_INTERNAL_DURATION_(scope_label, scope_category_literal, scope_name_literal, args...)  \
185     TRACE_INTERNAL_DECLARE_DURATION_SCOPE(scope_label, scope_category_literal, scope_name_literal); \
186     TRACE_INTERNAL_DURATION_BEGIN(scope_label.category_literal, scope_label.name_literal, args)
187 #define TRACE_INTERNAL_DURATION(category_literal, name_literal, args...) \
188     TRACE_INTERNAL_DURATION_(TRACE_INTERNAL_SCOPE_LABEL(), (category_literal), (name_literal), args)
189 #else
190 #define TRACE_INTERNAL_DURATION(category_literal, name_literal, args...) \
191     TRACE_INTERNAL_DURATION_BEGIN((category_literal), (name_literal), args)
192 #endif // NTRACE
193 
194 #define TRACE_INTERNAL_ASYNC_BEGIN(category_literal, name_literal, async_id, args...)      \
195     do {                                                                                   \
196         TRACE_INTERNAL_EVENT_RECORD(                                                       \
197             (category_literal),                                                            \
198             trace_internal_write_async_begin_event_record_and_release_context(             \
199                 TRACE_INTERNAL_CONTEXT,                                                    \
200                 &TRACE_INTERNAL_CATEGORY_REF,                                              \
201                 (name_literal), (async_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
202             args);                                                                         \
203     } while (0)
204 
205 #define TRACE_INTERNAL_ASYNC_INSTANT(category_literal, name_literal, async_id, args...)    \
206     do {                                                                                   \
207         TRACE_INTERNAL_EVENT_RECORD(                                                       \
208             (category_literal),                                                            \
209             trace_internal_write_async_instant_event_record_and_release_context(           \
210                 TRACE_INTERNAL_CONTEXT,                                                    \
211                 &TRACE_INTERNAL_CATEGORY_REF,                                              \
212                 (name_literal), (async_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
213             args);                                                                         \
214     } while (0)
215 
216 #define TRACE_INTERNAL_ASYNC_END(category_literal, name_literal, async_id, args...)        \
217     do {                                                                                   \
218         TRACE_INTERNAL_EVENT_RECORD(                                                       \
219             (category_literal),                                                            \
220             trace_internal_write_async_end_event_record_and_release_context(               \
221                 TRACE_INTERNAL_CONTEXT,                                                    \
222                 &TRACE_INTERNAL_CATEGORY_REF,                                              \
223                 (name_literal), (async_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
224             args);                                                                         \
225     } while (0)
226 
227 #define TRACE_INTERNAL_FLOW_BEGIN(category_literal, name_literal, flow_id, args...)       \
228     do {                                                                                  \
229         TRACE_INTERNAL_EVENT_RECORD(                                                      \
230             (category_literal),                                                           \
231             trace_internal_write_flow_begin_event_record_and_release_context(             \
232                 TRACE_INTERNAL_CONTEXT,                                                   \
233                 &TRACE_INTERNAL_CATEGORY_REF,                                             \
234                 (name_literal), (flow_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
235             args);                                                                        \
236     } while (0)
237 
238 #define TRACE_INTERNAL_FLOW_STEP(category_literal, name_literal, flow_id, args...)        \
239     do {                                                                                  \
240         TRACE_INTERNAL_EVENT_RECORD(                                                      \
241             (category_literal),                                                           \
242             trace_internal_write_flow_step_event_record_and_release_context(              \
243                 TRACE_INTERNAL_CONTEXT,                                                   \
244                 &TRACE_INTERNAL_CATEGORY_REF,                                             \
245                 (name_literal), (flow_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
246             args);                                                                        \
247     } while (0)
248 
249 #define TRACE_INTERNAL_FLOW_END(category_literal, name_literal, flow_id, args...)         \
250     do {                                                                                  \
251         TRACE_INTERNAL_EVENT_RECORD(                                                      \
252             (category_literal),                                                           \
253             trace_internal_write_flow_end_event_record_and_release_context(               \
254                 TRACE_INTERNAL_CONTEXT,                                                   \
255                 &TRACE_INTERNAL_CATEGORY_REF,                                             \
256                 (name_literal), (flow_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
257             args);                                                                        \
258     } while (0)
259 
260 #define TRACE_INTERNAL_KERNEL_OBJECT(handle, args...)                                 \
261     do {                                                                              \
262         TRACE_INTERNAL_SIMPLE_RECORD(                                                 \
263             trace_internal_write_kernel_object_record_for_handle_and_release_context( \
264                 TRACE_INTERNAL_CONTEXT,                                               \
265                 (handle), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS),              \
266             args);                                                                    \
267     } while (0)
268 
269 #define TRACE_INTERNAL_BLOB(type, name, blob, blob_size)          \
270     do {                                                          \
271         trace_context_t* TRACE_INTERNAL_CONTEXT =                 \
272             trace_acquire_context();                              \
273         if (unlikely(TRACE_INTERNAL_CONTEXT)) {                   \
274             trace_internal_write_blob_record_and_release_context( \
275                 TRACE_INTERNAL_CONTEXT,                           \
276                 (type), (name), (blob), (blob_size));             \
277         }                                                         \
278     } while (0)
279 
280 ///////////////////////////////////////////////////////////////////////////////
281 
282 void trace_internal_write_instant_event_record_and_release_context(
283     trace_context_t* context,
284     const trace_string_ref_t* category_ref,
285     const char* name_literal,
286     trace_scope_t scope,
287     trace_arg_t* args, size_t num_args);
288 
289 void trace_internal_write_counter_event_record_and_release_context(
290     trace_context_t* context,
291     const trace_string_ref_t* category_ref,
292     const char* name_literal,
293     uint64_t counter_id,
294     trace_arg_t* args, size_t num_args);
295 
296 void trace_internal_write_duration_begin_event_record_and_release_context(
297     trace_context_t* context,
298     const trace_string_ref_t* category_ref,
299     const char* name_literal,
300     trace_arg_t* args, size_t num_args);
301 
302 void trace_internal_write_duration_end_event_record_and_release_context(
303     trace_context_t* context,
304     const trace_string_ref_t* category_ref,
305     const char* name_literal,
306     trace_arg_t* args, size_t num_args);
307 
308 void trace_internal_write_async_begin_event_record_and_release_context(
309     trace_context_t* context,
310     const trace_string_ref_t* category_ref,
311     const char* name_literal,
312     trace_async_id_t async_id,
313     trace_arg_t* args, size_t num_args);
314 
315 void trace_internal_write_async_instant_event_record_and_release_context(
316     trace_context_t* context,
317     const trace_string_ref_t* category_ref,
318     const char* name_literal,
319     trace_async_id_t async_id,
320     trace_arg_t* args, size_t num_args);
321 
322 void trace_internal_write_async_end_event_record_and_release_context(
323     trace_context_t* context,
324     const trace_string_ref_t* category_ref,
325     const char* name_literal,
326     trace_async_id_t async_id,
327     trace_arg_t* args, size_t num_args);
328 
329 void trace_internal_write_flow_begin_event_record_and_release_context(
330     trace_context_t* context,
331     const trace_string_ref_t* category_ref,
332     const char* name_literal,
333     trace_flow_id_t flow_id,
334     trace_arg_t* args, size_t num_args);
335 
336 void trace_internal_write_flow_step_event_record_and_release_context(
337     trace_context_t* context,
338     const trace_string_ref_t* category_ref,
339     const char* name_literal,
340     trace_flow_id_t flow_id,
341     trace_arg_t* args, size_t num_args);
342 
343 void trace_internal_write_flow_end_event_record_and_release_context(
344     trace_context_t* context,
345     const trace_string_ref_t* category_ref,
346     const char* name_literal,
347     trace_flow_id_t flow_id,
348     trace_arg_t* args, size_t num_args);
349 
350 void trace_internal_write_kernel_object_record_for_handle_and_release_context(
351     trace_context_t* context,
352     zx_handle_t handle,
353     trace_arg_t* args, size_t num_args);
354 
355 void trace_internal_write_blob_record_and_release_context(
356     trace_context_t* context,
357     trace_blob_type_t type,
358     const char* name_literal,
359     const void* blob, size_t blob_size);
360 
361 #ifndef NTRACE
362 // When "destroyed" (by the cleanup attribute), writes a duration end event.
363 typedef struct {
364     const char* category_literal;
365     const char* name_literal;
366 } trace_internal_duration_scope_t;
367 
trace_internal_make_duration_scope(trace_internal_duration_scope_t * scope,const char * category_literal,const char * name_literal)368 static inline void trace_internal_make_duration_scope(
369     trace_internal_duration_scope_t* scope,
370     const char* category_literal, const char* name_literal) {
371     scope->category_literal = category_literal;
372     scope->name_literal = name_literal;
373 }
374 
trace_internal_cleanup_duration_scope(trace_internal_duration_scope_t * scope)375 static inline void trace_internal_cleanup_duration_scope(
376     trace_internal_duration_scope_t* scope) {
377     TRACE_INTERNAL_DURATION_END(scope->category_literal, scope->name_literal);
378 }
379 #endif // NTRACE
380 
381 __END_CDECLS
382 
383 #endif // TRACE_INTERNAL_EVENT_INTERNAL_H_
384