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 // Types, constants, and inline functions used to encode and decode trace records.
7 // This header is used by C and C++ code. For simple support of all choices of
8 // C/C++ and -O0/-On the inline functions are "static inline".
9 //
10
11 #ifndef TRACE_ENGINE_TYPES_H_
12 #define TRACE_ENGINE_TYPES_H_
13
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <string.h>
17
18 #include <zircon/assert.h>
19 #include <zircon/compiler.h>
20 #include <zircon/syscalls/object.h>
21 #include <zircon/types.h>
22
23 __BEGIN_CDECLS
24
25 // Timebase recorded into trace files, as returned by zx_ticks_get().
26 typedef uint64_t trace_ticks_t;
27
28 // The ids used to correlate related counters, asynchronous operations, flows, and virtual threads.
29 typedef uint64_t trace_counter_id_t;
30 typedef uint64_t trace_async_id_t;
31 typedef uint64_t trace_flow_id_t;
32 typedef uint64_t trace_vthread_id_t;
33
34 // Specifies the scope of instant events.
35 typedef enum {
36 // The event is only relevant to the thread it occurred on.
37 TRACE_SCOPE_THREAD = 0,
38 // The event is only relevant to the process in which it occurred.
39 TRACE_SCOPE_PROCESS = 1,
40 // The event is globally relevant.
41 TRACE_SCOPE_GLOBAL = 2,
42 } trace_scope_t;
43
44 // Thread states used to describe context switches.
45 // Use the |ZX_THREAD_STATE_XXX| values defined in <zircon/syscalls/object.h>.
46 typedef uint32_t trace_thread_state_t;
47
48 // Identifies a particular CPU in a context switch trace record.
49 typedef uint32_t trace_cpu_number_t;
50
51 // Contains a thread's priority in a context switch trace record.
52 typedef uint32_t trace_thread_priority_t;
53
54 // Represents an index into the string table.
55 typedef uint32_t trace_string_index_t;
56
57 // Represents the encoded form of string references.
58 typedef uint32_t trace_encoded_string_ref_t;
59 #define TRACE_ENCODED_STRING_REF_EMPTY ((trace_encoded_string_ref_t)0u)
60 #define TRACE_ENCODED_STRING_REF_INLINE_FLAG ((trace_encoded_string_ref_t)0x8000u)
61 #define TRACE_ENCODED_STRING_REF_LENGTH_MASK ((trace_encoded_string_ref_t)0x7fffu)
62 #define TRACE_ENCODED_STRING_REF_MAX_LENGTH ((trace_encoded_string_ref_t)32000)
63 #define TRACE_ENCODED_STRING_REF_MIN_INDEX ((trace_encoded_string_ref_t)0x1u)
64 #define TRACE_ENCODED_STRING_REF_MAX_INDEX ((trace_encoded_string_ref_t)0x7fffu)
65
66 // Represents an index into the thread table.
67 typedef uint32_t trace_thread_index_t;
68
69 // Represents the encoded form of thread references.
70 typedef uint32_t trace_encoded_thread_ref_t;
71 #define TRACE_ENCODED_THREAD_REF_INLINE ((trace_encoded_thread_ref_t)0u)
72 #define TRACE_ENCODED_THREAD_REF_MIN_INDEX ((trace_encoded_thread_ref_t)0x01)
73 #define TRACE_ENCODED_THREAD_REF_MAX_INDEX ((trace_encoded_thread_ref_t)0xff)
74
75 // A string reference which is either encoded inline or indirectly by string table index.
76 typedef struct trace_string_ref {
77 trace_encoded_string_ref_t encoded_value;
78 const char* inline_string; // only non-null for inline strings
79 } trace_string_ref_t;
80
81 // Makes true if the string ref's content is empty.
trace_is_empty_string_ref(const trace_string_ref_t * string_ref)82 static inline bool trace_is_empty_string_ref(const trace_string_ref_t* string_ref) {
83 return string_ref->encoded_value == TRACE_ENCODED_STRING_REF_EMPTY;
84 }
85
86 // Returns true if the string ref's content is stored inline (rather than empty or indexed).
trace_is_inline_string_ref(const trace_string_ref_t * string_ref)87 static inline bool trace_is_inline_string_ref(const trace_string_ref_t* string_ref) {
88 return string_ref->encoded_value & TRACE_ENCODED_STRING_REF_INLINE_FLAG;
89 }
90
91 // Returns true if the string ref's content is stored as an index into the string table.
trace_is_indexed_string_ref(const trace_string_ref_t * string_ref)92 static inline bool trace_is_indexed_string_ref(const trace_string_ref_t* string_ref) {
93 return string_ref->encoded_value >= TRACE_ENCODED_STRING_REF_MIN_INDEX &&
94 string_ref->encoded_value <= TRACE_ENCODED_STRING_REF_MAX_INDEX;
95 }
96
97 // Returns the length of an inline string.
98 // Only valid for inline strings.
trace_inline_string_ref_length(const trace_string_ref_t * string_ref)99 static inline size_t trace_inline_string_ref_length(const trace_string_ref_t* string_ref) {
100 return string_ref->encoded_value & TRACE_ENCODED_STRING_REF_LENGTH_MASK;
101 }
102
103 // Makes an empty string ref.
trace_make_empty_string_ref(void)104 static inline trace_string_ref_t trace_make_empty_string_ref(void) {
105 trace_string_ref_t ref = {
106 .encoded_value = TRACE_ENCODED_STRING_REF_EMPTY,
107 .inline_string = NULL};
108 return ref;
109 }
110
111 // Makes an inline or empty string ref from a string with given size.
112 // The |string| does not need to be null-terminated because its length is provided.
113 // The |string| must not be null if length is non-zero.
114 // The |string| is truncated if longer than |TRACE_ENCODED_STRING_REF_MAX_LENGTH|.
trace_make_inline_string_ref(const char * string,size_t length)115 static inline trace_string_ref_t trace_make_inline_string_ref(
116 const char* string, size_t length) {
117 if (!length)
118 return trace_make_empty_string_ref();
119
120 ZX_DEBUG_ASSERT(string != NULL);
121 if (length > TRACE_ENCODED_STRING_REF_MAX_LENGTH)
122 length = TRACE_ENCODED_STRING_REF_MAX_LENGTH;
123 trace_string_ref_t ref = {
124 .encoded_value = TRACE_ENCODED_STRING_REF_INLINE_FLAG |
125 (trace_encoded_string_ref_t)length,
126 .inline_string = string};
127 return ref;
128 }
129
130 // Makes an inline or empty string ref from a null-terminated string.
131 // The |string| is truncated if longer than |TRACE_ENCODED_STRING_REF_MAX_LENGTH|.
trace_make_inline_c_string_ref(const char * string)132 static inline trace_string_ref_t trace_make_inline_c_string_ref(const char* string) {
133 return trace_make_inline_string_ref(string,
134 string ? strlen(string) : 0u);
135 }
136
137 // Makes an indexed string ref.
138 // The |index| must be >= |TRACE_ENCODED_STRING_REF_MIN_INDEX|
139 // and <= |TRACE_ENCODED_STRING_REF_MAX_INDEX|.
trace_make_indexed_string_ref(trace_string_index_t index)140 static inline trace_string_ref_t trace_make_indexed_string_ref(trace_string_index_t index) {
141 ZX_DEBUG_ASSERT(index >= TRACE_ENCODED_STRING_REF_MIN_INDEX &&
142 index <= TRACE_ENCODED_STRING_REF_MAX_INDEX);
143 trace_string_ref_t ref = {
144 .encoded_value = index,
145 .inline_string = NULL};
146 return ref;
147 }
148
149 // A thread reference which is either encoded inline or indirectly by thread table index.
150 typedef struct trace_thread_ref {
151 trace_encoded_thread_ref_t encoded_value;
152 zx_koid_t inline_process_koid;
153 zx_koid_t inline_thread_koid;
154 } trace_thread_ref_t;
155
156 // Returns true if the thread ref's value is unknown.
trace_is_unknown_thread_ref(const trace_thread_ref_t * thread_ref)157 static inline bool trace_is_unknown_thread_ref(const trace_thread_ref_t* thread_ref) {
158 return thread_ref->encoded_value == TRACE_ENCODED_THREAD_REF_INLINE &&
159 thread_ref->inline_process_koid == ZX_KOID_INVALID &&
160 thread_ref->inline_thread_koid == ZX_KOID_INVALID;
161 }
162
163 // Returns true if the thread ref's content is stored as an index into the thread table.
trace_is_indexed_thread_ref(const trace_thread_ref_t * thread_ref)164 static inline bool trace_is_indexed_thread_ref(const trace_thread_ref_t* thread_ref) {
165 return thread_ref->encoded_value >= TRACE_ENCODED_THREAD_REF_MIN_INDEX &&
166 thread_ref->encoded_value <= TRACE_ENCODED_THREAD_REF_MAX_INDEX;
167 }
168
169 // Returns true if the thread ref's value is stored inline (rather than unknown or indexed).
trace_is_inline_thread_ref(const trace_thread_ref_t * thread_ref)170 static inline bool trace_is_inline_thread_ref(const trace_thread_ref_t* thread_ref) {
171 return thread_ref->encoded_value == TRACE_ENCODED_THREAD_REF_INLINE &&
172 (thread_ref->inline_process_koid != ZX_KOID_INVALID ||
173 thread_ref->inline_thread_koid != ZX_KOID_INVALID);
174 }
175
176 // Makes a thread ref representing an unknown thread.
177 // TODO(ZX-1030): Reserve thread ref index 0 for unknown threads,
178 // use thread ref index 255 for inline threads.
trace_make_unknown_thread_ref(void)179 static inline trace_thread_ref_t trace_make_unknown_thread_ref(void) {
180 trace_thread_ref_t ref = {
181 .encoded_value = TRACE_ENCODED_THREAD_REF_INLINE,
182 .inline_process_koid = ZX_KOID_INVALID,
183 .inline_thread_koid = ZX_KOID_INVALID};
184 return ref;
185 }
186
187 // Makes a thread ref with an inline value.
188 // The process and thread koids must not both be invalid.
trace_make_inline_thread_ref(zx_koid_t process_koid,zx_koid_t thread_koid)189 static inline trace_thread_ref_t trace_make_inline_thread_ref(zx_koid_t process_koid,
190 zx_koid_t thread_koid) {
191 ZX_DEBUG_ASSERT(process_koid != ZX_KOID_INVALID ||
192 thread_koid != ZX_KOID_INVALID);
193 trace_thread_ref_t ref = {
194 .encoded_value = TRACE_ENCODED_THREAD_REF_INLINE,
195 .inline_process_koid = process_koid,
196 .inline_thread_koid = thread_koid};
197 return ref;
198 }
199
200 // Makes an indexed thread ref.
201 // The index must be >= |TRACE_ENCODED_THREAD_REF_MIN_INDEX|
202 // and <= |TRACE_ENCODED_THREAD_REF_MAX_INDEX|.
trace_make_indexed_thread_ref(trace_thread_index_t index)203 static inline trace_thread_ref_t trace_make_indexed_thread_ref(trace_thread_index_t index) {
204 ZX_DEBUG_ASSERT(index >= TRACE_ENCODED_THREAD_REF_MIN_INDEX &&
205 index <= TRACE_ENCODED_THREAD_REF_MAX_INDEX);
206 trace_thread_ref_t ref = {
207 .encoded_value = (trace_encoded_thread_ref_t)index,
208 .inline_process_koid = ZX_KOID_INVALID,
209 .inline_thread_koid = ZX_KOID_INVALID};
210 return ref;
211 }
212
213 // The maximum length of a trace record in bytes.
214 // This is constrained by the number of bits used to encode the length in
215 // the record header.
216 #define TRACE_ENCODED_RECORD_MAX_LENGTH ((size_t)32760u)
217
218 // Enumerates all known argument types.
219 typedef enum {
220 TRACE_ARG_NULL = 0,
221 TRACE_ARG_INT32 = 1,
222 TRACE_ARG_UINT32 = 2,
223 TRACE_ARG_INT64 = 3,
224 TRACE_ARG_UINT64 = 4,
225 TRACE_ARG_DOUBLE = 5,
226 TRACE_ARG_STRING = 6,
227 TRACE_ARG_POINTER = 7,
228 TRACE_ARG_KOID = 8,
229 } trace_arg_type_t;
230
231 // A typed argument value.
232 typedef struct {
233 trace_arg_type_t type;
234 union {
235 int32_t int32_value;
236 uint32_t uint32_value;
237 int64_t int64_value;
238 uint64_t uint64_value;
239 double double_value;
240 trace_string_ref_t string_value_ref;
241 uintptr_t pointer_value;
242 zx_koid_t koid_value;
243 uintptr_t reserved_for_future_expansion[2];
244 };
245 } trace_arg_value_t;
246
247 // Makes a null argument value.
trace_make_null_arg_value(void)248 static inline trace_arg_value_t trace_make_null_arg_value(void) {
249 trace_arg_value_t arg_value = {.type = TRACE_ARG_NULL, {}};
250 return arg_value;
251 }
252
253 // Makes a signed 32-bit integer argument value.
trace_make_int32_arg_value(int32_t value)254 static inline trace_arg_value_t trace_make_int32_arg_value(int32_t value) {
255 trace_arg_value_t arg_value = {.type = TRACE_ARG_INT32,
256 {.int32_value = value}};
257 return arg_value;
258 }
259
260 // Makes an unsigned 32-bit integer argument value.
trace_make_uint32_arg_value(uint32_t value)261 static inline trace_arg_value_t trace_make_uint32_arg_value(uint32_t value) {
262 trace_arg_value_t arg_value = {.type = TRACE_ARG_UINT32,
263 {.uint32_value = value}};
264 return arg_value;
265 }
266
267 // Makes a signed 64-bit integer argument value.
trace_make_int64_arg_value(int64_t value)268 static inline trace_arg_value_t trace_make_int64_arg_value(int64_t value) {
269 trace_arg_value_t arg_value = {.type = TRACE_ARG_INT64,
270 {.int64_value = value}};
271 return arg_value;
272 }
273
274 // Makes an unsigned 64-bit integer argument value.
trace_make_uint64_arg_value(uint64_t value)275 static inline trace_arg_value_t trace_make_uint64_arg_value(uint64_t value) {
276 trace_arg_value_t arg_value = {.type = TRACE_ARG_UINT64,
277 {.uint64_value = value}};
278 return arg_value;
279 }
280
281 // Makes a double-precision floating point argument value.
trace_make_double_arg_value(double value)282 static inline trace_arg_value_t trace_make_double_arg_value(double value) {
283 trace_arg_value_t arg_value = {.type = TRACE_ARG_DOUBLE,
284 {.double_value = value}};
285 return arg_value;
286 }
287
288 // Makes a string argument value.
trace_make_string_arg_value(trace_string_ref_t value_ref)289 static inline trace_arg_value_t trace_make_string_arg_value(trace_string_ref_t value_ref) {
290 trace_arg_value_t arg_value = {.type = TRACE_ARG_STRING,
291 {.string_value_ref = value_ref}};
292 return arg_value;
293 }
294
295 // Makes a pointer argument value.
trace_make_pointer_arg_value(uintptr_t value)296 static inline trace_arg_value_t trace_make_pointer_arg_value(uintptr_t value) {
297 trace_arg_value_t arg_value = {.type = TRACE_ARG_POINTER,
298 {.pointer_value = value}};
299 return arg_value;
300 }
301
302 // Makes a koid argument value.
trace_make_koid_arg_value(zx_koid_t value)303 static inline trace_arg_value_t trace_make_koid_arg_value(zx_koid_t value) {
304 trace_arg_value_t arg_value = {.type = TRACE_ARG_KOID,
305 {.koid_value = value}};
306 return arg_value;
307 }
308
309 // A named argument and value.
310 // Often packed into an array to form an argument list when writing records.
311 typedef struct {
312 trace_string_ref_t name_ref;
313 trace_arg_value_t value;
314 } trace_arg_t;
315
316 // Makes an argument with name and value.
trace_make_arg(trace_string_ref_t name_ref,trace_arg_value_t value)317 static inline trace_arg_t trace_make_arg(trace_string_ref_t name_ref,
318 trace_arg_value_t value) {
319 trace_arg_t arg = {.name_ref = name_ref, .value = value};
320 return arg;
321 }
322
323 // The trace format specified maximum number of args for a record.
324 #define TRACE_MAX_ARGS ((size_t)15u)
325
326 // BlobType enumerates all known trace blob types.
327 typedef enum {
328 TRACE_BLOB_TYPE_DATA = 1,
329 TRACE_BLOB_TYPE_LAST_BRANCH = 2,
330 } trace_blob_type_t;
331
332 // The maximum size of a blob.
333 // This is slightly less than the actual maximum ((= 0xfff * 8) - header size)
334 // to allow room for reasonably sized blob names should they get inlined.
335 #define TRACE_MAX_BLOB_SIZE ((size_t)32000u)
336
337 // The buffering mode.
338 typedef enum {
339 // Keep filling the trace buffer until it is full and then stop tracing.
340 TRACE_BUFFERING_MODE_ONESHOT = 0,
341 // When the buffer fills start overwriting records from the beginning.
342 TRACE_BUFFERING_MODE_CIRCULAR = 1,
343 // When the buffer reaches a critical point notify the trace manager to
344 // save the trace thus far. Essentially this is an implementation of
345 // double buffering, though the underlying details are unspecified.
346 TRACE_BUFFERING_MODE_STREAMING = 2,
347 } trace_buffering_mode_t;
348
349 __END_CDECLS
350
351 #ifdef __cplusplus
352
353 namespace trace {
354
355 // Enumerates all known record types.
356 enum class RecordType {
357 kMetadata = 0,
358 kInitialization = 1,
359 kString = 2,
360 kThread = 3,
361 kEvent = 4,
362 kBlob = 5,
363 kKernelObject = 7,
364 kContextSwitch = 8,
365 kLog = 9,
366 };
367
368 // MetadataType enumerates all known trace metadata types.
369 enum class MetadataType {
370 kProviderInfo = 1,
371 kProviderSection = 2,
372 kProviderEvent = 3,
373 };
374
375 // Enumerates all provider events.
376 enum class ProviderEventType {
377 kBufferOverflow = 0,
378 };
379
380 // Enumerates all known argument types.
381 enum class ArgumentType {
382 kNull = TRACE_ARG_NULL,
383 kInt32 = TRACE_ARG_INT32,
384 kUint32 = TRACE_ARG_UINT32,
385 kInt64 = TRACE_ARG_INT64,
386 kUint64 = TRACE_ARG_UINT64,
387 kDouble = TRACE_ARG_DOUBLE,
388 kString = TRACE_ARG_STRING,
389 kPointer = TRACE_ARG_POINTER,
390 kKoid = TRACE_ARG_KOID,
391 };
392
393 // EventType enumerates all known trace event types.
394 enum class EventType {
395 kInstant = 0,
396 kCounter = 1,
397 kDurationBegin = 2,
398 kDurationEnd = 3,
399 kDurationComplete = 4,
400 kAsyncBegin = 5,
401 kAsyncInstant = 6,
402 kAsyncEnd = 7,
403 kFlowBegin = 8,
404 kFlowStep = 9,
405 kFlowEnd = 10,
406 };
407
408 // Specifies the scope of instant events.
409 enum class EventScope {
410 kThread = TRACE_SCOPE_THREAD,
411 kProcess = TRACE_SCOPE_PROCESS,
412 kGlobal = TRACE_SCOPE_GLOBAL,
413 };
414
415 // Trace provider id in a trace session.
416 using ProviderId = uint32_t;
417
418 // Thread states used to describe context switches.
419 enum class ThreadState {
420 kNew = ZX_THREAD_STATE_NEW,
421 kRunning = ZX_THREAD_STATE_RUNNING,
422 kSuspended = ZX_THREAD_STATE_SUSPENDED,
423 kBlocked = ZX_THREAD_STATE_BLOCKED,
424 kDying = ZX_THREAD_STATE_DYING,
425 kDead = ZX_THREAD_STATE_DEAD,
426 };
427
428 using ArgumentHeader = uint64_t;
429 using RecordHeader = uint64_t;
430
431 } // namespace trace
432
433 #endif // __cplusplus
434
435 #endif // TRACE_ENGINE_TYPES_H_
436