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