1.. _module-pw_trace: 2 3======== 4pw_trace 5======== 6.. pigweed-module:: 7 :name: pw_trace 8 9Pigweed's tracing module provides facilities for applications to trace 10information about the execution of their application. The module is split into 11two components: 12 131. The facade (this module) which is only a macro interface layer 142. The backend, provided elsewhere, implements the low level tracing. 15 16------ 17Status 18------ 19This module is currently in development, and is therefore still undergoing 20significant changes. 21 22Future work will add: 23 241. A Python library to generate trace files which can be viewed. (pwbug/205) 252. Add more examples with sample output. (pwbug/207) 263. Implement a trace backend module. (pwbug/260) 27 28-------- 29Overview 30-------- 31Traces provide a useful view which shows the flow of events through a system, 32and can greatly assist in understanding complex software problems. These traces 33can either show what tasks are running at any given time, or use added code 34(similar to logging), to help annotate specific interesting flows. 35 36Fundamentally, tracing is similar to logging in that it provides the developer 37with a view into what the system was doing at a particular time. The fundamental 38difference between logs and tracing is that logs present information as ad-hoc 39human-readable strings and are better suited to providing the current state of 40the system. Instead, traces capture sequences of events with precise timestamps, 41and are therefore useful at understanding the flow of events in the system over 42time. 43 44The default backend for pw_trace is pw_trace_null, which disables tracing. 45 46Compatibility 47------------- 48Most of the facade is compatible with C and C++, the only exception to this is 49the Scope and Function tracing macros which are convenience wrappers only 50available in C++. 51 52pw_trace:null 53------------- 54``pw_trace_null`` is a ``pw_trace backend`` that ignores all ``pw_trace`` 55statements. The backend implements ``pw_trace`` with empty inline functions. 56Using empty functions ensure that the arguments are evaluated and their types 57are correct. Since the functions are inline in the header, the compiler will 58optimize out the function call. 59 60This backend can be used to completely disable ``pw_trace``. 61 62Dependencies 63------------- 64``pw_preprocessor`` 65 66Example 67------- 68 69.. code-block:: cpp 70 71 #define PW_TRACE_MODULE_NAME "Input" 72 #include "pw_trace/trace.h" 73 74 void SendButton() { 75 PW_TRACE_FUNCTION() 76 // do something 77 } 78 79 void InputLoop() { 80 while(1) { 81 auto event = WaitNewInputEvent() 82 TRACE_SCOPE("Handle Event"); // measure until loop finished 83 if (event == kNewButton){ 84 SendButton(); 85 PW_TRACE_END("button"); // Trace event was started in ButtonIsr 86 } else { 87 PW_TRACE_INSTANT("Unknown event"); 88 } 89 } 90 } 91 92 void ButtonIsr() { 93 PW_TRACE_START("button"); 94 SendNewInputEvent(kNewButton); 95 } 96 97 98------------ 99Trace macros 100------------ 101 102The ``pw_trace`` public API provides three basic trace events: 103 104- ``PW_TRACE_INSTANT`` - This is used to trace an instant event, which has no 105 duration. 106- ``PW_TRACE_START`` & ``PW_TRACE_END`` - Trace 'start' and 'end' events are 107 paired together to measure the duration of an event. 108 109These trace event macros all have the same arguments: 110 111- *label* - Each of these trace events must have a label, which is a string 112 describing the event. In addition to the required label, each of these traces 113 can optionally provide a group label and trace id. 114- *group_label* - The *optional* group label is used if many traces are all 115 measuring the same thing and should be grouped together. This information will 116 be used when visualizing the trace to ensure the information appears together. 117- *trace_id* - The *optional* trace id is similar to the group_id, but instead 118 groups events using a runtime value. This can be used if multiple trace flow 119 might happen at the same time and need to be grouped together. 120 For example, this could be used to trace data packets flowing through the 121 system; when a new sample might arrive before the previous packet is finished 122 processing. This would result in two start events occurring before the end 123 event. By providing a trace id with a different value for each packet, these 124 can be separated when decoding. 125 126.. tip:: 127 128 All of these arguments must be the same for a *start* and *end* pair. 129 130This results in 9 different trace calls: 131 132.. cpp:function:: PW_TRACE_INSTANT(label) 133.. cpp:function:: PW_TRACE_INSTANT(label, group_label) 134.. cpp:function:: PW_TRACE_INSTANT(label, group_label, trace_id) 135.. cpp:function:: PW_TRACE_START(label) 136.. cpp:function:: PW_TRACE_START(label, group_label) 137.. cpp:function:: PW_TRACE_START(label, group_label, trace_id) 138.. cpp:function:: PW_TRACE_END(label) 139.. cpp:function:: PW_TRACE_END(label, group_label) 140.. cpp:function:: PW_TRACE_END(label, group_label, trace_id) 141 142Modules 143------- 144In addition to these arguments, traces can be grouped into modules similar to 145logging. This is done by redefining the ``PW_TRACE_MODULE_NAME``. 146 147Flags 148----- 149Each trace event also has a flags field which can be used to provide additional 150compile time trace information. Each trace macro has a matching macro which 151allows specifying the flag: 152 153.. cpp:function:: PW_TRACE_INSTANT_FLAG(flag, label) 154.. cpp:function:: PW_TRACE_INSTANT_FLAG(flag, label, group_label) 155.. cpp:function:: PW_TRACE_INSTANT_FLAG(flag, label, group_label, trace_id) 156.. cpp:function:: PW_TRACE_START_FLAG(flag, label) 157.. cpp:function:: PW_TRACE_START_FLAG(flag, label, group_label) 158.. cpp:function:: PW_TRACE_START_FLAG(flag, label, group_label, trace_id) 159.. cpp:function:: PW_TRACE_END_FLAG(flag, label) 160.. cpp:function:: PW_TRACE_END_FLAG(flag, label, group_label) 161.. cpp:function:: PW_TRACE_END_FLAG(flag, label, group_label, trace_id) 162 163When not specified the flag uses the value of the macro ``PW_TRACE_FLAGS``. 164 165Data 166---- 167Each macro also has a variant which allows appending additional data: 168 169.. cpp:function:: PW_TRACE_INSTANT_DATA(label, data_format_string, data, size) 170.. cpp:function:: PW_TRACE_INSTANT_DATA(\ 171 label, group_label, data_format_string, data, size) 172.. cpp:function:: PW_TRACE_INSTANT_DATA(\ 173 label, group_label, trace_id, data_format_string, data, size) 174.. cpp:function:: PW_TRACE_START_DATA(label, data_format_string, data, size) 175.. cpp:function:: PW_TRACE_START_DATA(\ 176 label, group_label, data_format_string, data, size) 177.. cpp:function:: PW_TRACE_START_DATA(\ 178 label, group_label, trace_id, data_format_string, data, size) 179.. cpp:function:: PW_TRACE_END_DATA(label, data_format_string, data, size) 180.. cpp:function:: PW_TRACE_END_DATA(\ 181 label, group_label, data_format_string, data, size) 182.. cpp:function:: PW_TRACE_END_DATA(\ 183 label, group_label, trace_id, data_format_string, data, size) 184 185These macros require 3 additional arguments: 186 187- *data_format_string* - A string which is used by the decoder to identify the 188 data. This could for example either be printf style tokens, python struct 189 packed fmt string or a custom label recognized by the decoder. 190- *data* - A pointer to a buffer of arbitrary caller-provided data (void*). 191- *size* - The size of the data (size_t). 192 193Currently the included python tool supports a few different options for 194*data_format_string*: 195 196- *@pw_arg_label* - Uses the string in the data as the trace event label. 197- *@pw_arg_group* - Uses the string in the data as the trace event group. 198- *@pw_arg_counter* - Uses the data as a little endian integer value, and 199 visualizes it as a counter value in the trace (on a graph). 200- *@pw_py_struct_fmt:* - Interprets the string after the ":" as a python struct 201 format string, and uses that format string to unpack the data elements. This 202 can be used to either provide a single value type, or provide multiple 203 different values with a variety of types. Options for format string types can 204 be found here: https://docs.python.org/3/library/struct.html#format-characters 205 . The data is always assumed to be packed with little-endian ordering if not 206 indicated otherwise:: 207 208 // Example 209 data_format_string = "@pw_py_struct_fmt:ll" 210 data = 0x1400000014000000 211 args = {data_0: 20, data_1:20} 212- *@pw_py_map_fmt:* - Interprets the string after the ":" as a dictionary 213 relating the data field name to the python struct format string. Once 214 collected, the format strings are concatenated and used to unpack the data 215 elements as above. The data is always assumed to be packed with little-endian 216 ordering if not indicated otherwise. To specify a different ordering, 217 construct the format string as ``@pw_py_map_fmt:[@=<>!]{k:v,...}``:: 218 219 // Example 220 data_format_string = "@pw_py_map_fmt:{Field: l, Field2: l }" 221 data = 0x1400000014000000 222 args = {Field: 20, Field2:20} 223 224.. tip:: 225 226 It is ok for only one event of a start/end pair to contain data, as long the 227 *label*, *group_label*, and *trace_id*, are all the same. 228 229C++ Only Traces 230--------------- 231Scope API measures durations until the object loses scope. This can for 232example, provide a convenient method of tracing functions or loops. 233 234.. cpp:function:: PW_TRACE_SCOPE(label) 235.. cpp:function:: PW_TRACE_SCOPE(label, group_label) 236.. cpp:function:: PW_TRACE_SCOPE(label, group_label, trace_id) 237 238Function API measures durations until the function returns. This is the only 239macro which does not require a *label*, and instead uses the function name as the 240label. It still can optionally be provided a *group_id*. 241 242.. cpp:function:: PW_TRACE_FUNCTION() 243.. cpp:function:: PW_TRACE_FUNCTION(group_label) 244.. cpp:function:: PW_TRACE_FUNCTION(group_label, trace_id) 245 246Compile time enabling/disabling 247------------------------------- 248Traces in a file can be enabled/disabled at compile time by defining through 249the ``PW_TRACE_ENABLE`` macro. A value of 0 causes traces to be disabled. 250A non-zero value will enable traces. While tracing defaults to enabled, 251it is best practice to define ``PW_TRACE_ENABLE`` explicitly in files that 252use tracing as the default may change in the future. 253 254A good pattern is to have a module level configuration parameter for enabling 255tracing and define ``PW_TRACE_ENABLE`` in terms of that at the top of each 256of the module's files: 257 258 259.. code-block:: cpp 260 261 // Enable tracing based on pw_example module config parameter. 262 #define PW_TRACE_ENABLE PW_EXAMPLE_TRACE_ENABLE 263 264 265Additionally specific trace points (or sets of points) can be enabled/disabled 266using the following pattern: 267 268.. code-block:: cpp 269 270 // Assuming tracing is disabled at the top of the file. 271 272 // Enable specific trace. 273 #undef PW_TRACE_ENABLE 274 #define PW_TRACE_ENABLE 1 275 PW_TRACE_INSTANT("important trace"); 276 277 // Set traces back to disabled. PW_TRACE_ENABLE can not be left 278 // undefined. 279 #undef PW_TRACE_ENABLE 280 #define PW_TRACE_ENABLE 0 281 282----------- 283Backend API 284----------- 285Each of the trace event macros get sent to one of two macros which are 286implemented by the backend: 287 288.. cpp:function:: PW_TRACE(event_type, flags, label, group_label, trace_id) 289.. cpp:function:: PW_TRACE_DATA(event_type, flags, label, group_label, \ 290 trace_id, data_format_string, data, size) 291 292The ``event_type`` value will be whatever the backend defined for that specific 293trace type using the macros defined below. 294 295The backend can optionally not define ``PW_TRACE_DATA`` to have those traces 296disabled. 297 298Trace types 299----------- 300Although there are only 3 basic trace types, each has 3 variants: 301 302- Label only 303- Label and group 304- Label, group, and trace_id 305 306This combination creates 9 different trace event types: 307 308- *PW_TRACE_TYPE_INSTANT*: Instant trace, with only a label. 309- *PW_TRACE_TYPE_DURATION_START*: Start trace, with only a label. 310- *PW_TRACE_TYPE_DURATION_END*: End trace, with only a label. 311- *PW_TRACE_TYPE_INSTANT_GROUP*: Instant trace, with a label and a group. 312- *PW_TRACE_TYPE_DURATION_GROUP_START*: Start trace, with a label and a group. 313- *PW_TRACE_TYPE_DURATION_GROUP_END*: End trace, with a label and a group. 314- *PW_TRACE_TYPE_ASYNC_INSTANT*: Instant trace, with label, group, and trace_id 315- *PW_TRACE_TYPE_ASYNC_START*: Start trace, with label, group, and trace_id. 316- *PW_TRACE_TYPE_ASYNC_END*: End trace, with label, group, and trace_id. 317 318The backend must define these macros to have them enabled. If any are left 319undefined, any traces of that type are removed. 320 321Defaults 322-------- 323The backend can use these macros to change what the default value is if not 324provided. 325 326- *PW_TRACE_FLAGS_DEFAULT*: Default value if no flags are provided. 327- *PW_TRACE_TRACE_ID_DEFAULT*: Default value if no trace_id provided. 328- *PW_TRACE_GROUP_LABEL_DEFAULT*: Default value if no group_label provided. 329 330---------- 331Sample App 332---------- 333A sample application is provided in the examples folder. This code attempts to 334provide examples of the multiple ways tracing can be used. Furthermore, 335trace backends can include the sample app in their own examples to show how to 336use other features. 337 338The sample app contains 3 "fake" tasks, which are each in their own 339`PW_TRACE_MODULE`. 340 341- *Input*: Simulating a driver, which gets data periodically, and sends to 342 *Processing* task. 343- *Processing*: Has a work queue, which handles processing the jobs. 344- *Kernel*: A simple work loop which demonstrates a possible integration of 345 tracing with a RTOS/Kernel. 346 347Jobs are intentionally made to have multiple stages of processing (simulated by 348being re-added to the work-queue). This results in multiple jobs being handled 349at the same time, the trace_id is used to separate these traces. 350 351---------------------- 352Python Trace Generator 353---------------------- 354The Python tool is still in early development, but currently it supports 355generating a list of json lines from a list of trace events. 356 357To view the trace, these lines can be saved to a file and loaded into 358chrome://tracing. 359 360Future work will look to add: 361 362- Config options to customize output. 363- A method of providing custom data formatters. 364- Perfetto support. 365 366 367.. toctree:: 368 :hidden: 369 :maxdepth: 1 370 371 backends 372