1.. _tracing: 2 3Tracing 4####### 5 6Overview 7******** 8 9The tracing feature provides hooks that permits you to collect data from 10your application and allows tools running on a host to visualize the inner-working of 11the kernel and various subsystems. 12 13Every system has application-specific events to trace out. Historically, 14that has implied: 15 161. Determining the application-specific payload, 172. Choosing suitable serialization-format, 183. Writing the on-target serialization code, 194. Deciding on and writing the I/O transport mechanics, 205. Writing the PC-side deserializer/parser, 216. Writing custom ad-hoc tools for filtering and presentation. 22 23An application can use one of the existing formats or define a custom format by 24overriding the macros declared in :zephyr_file:`include/zephyr/tracing/tracing.h`. 25 26Different formats, transports and host tools are available and supported in 27Zephyr. 28 29In fact, I/O varies greatly from system to system. Therefore, it is 30instructive to create a taxonomy for I/O types when we must ensure the 31interface between payload/format (Top Layer) and the transport mechanics 32(bottom Layer) is generic and efficient enough to model these. See the 33*I/O taxonomy* section below. 34 35 36Serialization Formats 37********************** 38 39.. _ctf: 40 41Common Trace Format (CTF) Support 42================================= 43 44Common Trace Format, CTF, is an open format and language to describe trace 45formats. This enables tool reuse, of which line-textual (babeltrace) and 46graphical (TraceCompass) variants already exist. 47 48CTF should look familiar to C programmers but adds stronger typing. 49See `CTF - A Flexible, High-performance Binary Trace Format 50<http://diamon.org/ctf/>`_. 51 52 53CTF allows us to formally describe application specific payload and the 54serialization format, which enables common infrastructure for host tools 55and parsers and tools for filtering and presentation. 56 57 58A Generic Interface 59-------------------- 60 61In CTF, an event is serialized to a packet containing one or more fields. 62As seen from *I/O taxonomy* section below, a bottom layer may: 63 64- perform actions at transaction-start (e.g. mutex-lock), 65- process each field in some way (e.g. sync-push emit, concat, enqueue to 66 thread-bound FIFO), 67- perform actions at transaction-stop (e.g. mutex-release, emit of concat 68 buffer). 69 70CTF Top-Layer Example 71---------------------- 72 73The CTF_EVENT macro will serialize each argument to a field:: 74 75 /* Example for illustration */ 76 static inline void ctf_top_foo(uint32_t thread_id, ctf_bounded_string_t name) 77 { 78 CTF_EVENT( 79 CTF_LITERAL(uint8_t, 42), 80 thread_id, 81 name, 82 "hello, I was emitted from function: ", 83 __func__ /* __func__ is standard since C99 */ 84 ); 85 } 86 87How to serialize and emit fields as well as handling alignment, can be done 88internally and statically at compile-time in the bottom-layer. 89 90 91The CTF top layer is enabled using the configuration option 92:kconfig:option:`CONFIG_TRACING_CTF` and can be used with the different transport 93backends both in synchronous and asynchronous modes. 94 95 96SEGGER SystemView Support 97========================= 98 99Zephyr provides built-in support for `SEGGER SystemView`_ that can be enabled in 100any application for platforms that have the required hardware support. 101 102The payload and format used with SystemView is custom to the application and 103relies on RTT as a transport. Newer versions of SystemView support other 104transports, for example UART or using snapshot mode (both still not 105supported in Zephyr). 106 107To enable tracing support with `SEGGER SystemView`_ add the configuration option 108:kconfig:option:`CONFIG_SEGGER_SYSTEMVIEW` to your project configuration file and set 109it to *y*. For example, this can be added to the 110:zephyr:code-sample:`synchronization` sample to visualize fast switching between threads. 111SystemView can also be used for post-mortem tracing, which can be enabled with 112`CONFIG_SEGGER_SYSVIEW_POST_MORTEM_MODE`. In this mode, a debugger can 113be attached after the system has crashed using ``west attach`` after which the 114latest data from the internal RAM buffer can be loaded into SystemView:: 115 116 CONFIG_STDOUT_CONSOLE=y 117 # enable to use thread names 118 CONFIG_THREAD_NAME=y 119 CONFIG_SEGGER_SYSTEMVIEW=y 120 CONFIG_USE_SEGGER_RTT=y 121 CONFIG_TRACING=y 122 # enable for post-mortem tracing 123 CONFIG_SEGGER_SYSVIEW_POST_MORTEM_MODE=n 124 125 126.. figure:: segger_systemview.png 127 :align: center 128 :alt: SEGGER SystemView 129 :figclass: align-center 130 :width: 80% 131 132.. _SEGGER SystemView: https://www.segger.com/products/development-tools/systemview/ 133 134 135Recent versions of `SEGGER SystemView`_ come with an API translation table for 136Zephyr which is incomplete and does not match the current level of support 137available in Zephyr. To use the latest Zephyr API description table, copy the 138file available in the tree to your local configuration directory to override the 139builtin table:: 140 141 # On Linux and MacOS 142 cp $ZEPHYR_BASE/subsys/tracing/sysview/SYSVIEW_Zephyr.txt ~/.config/SEGGER/ 143 144User-Defined Tracing 145==================== 146 147This tracing format allows the user to define functions to perform any work desired 148when a task is switched in or out, when an interrupt is entered or exited, and when the cpu 149is idle. 150 151Examples include: 152- simple toggling of GPIO for external scope tracing while minimizing extra cpu load 153- generating/outputting trace data in a non-standard or proprietary format that can 154not be supported by the other tracing systems 155 156The following functions can be defined by the user: 157 158.. code-block:: c 159 160 void sys_trace_thread_create_user(struct k_thread *thread); 161 void sys_trace_thread_abort_user(struct k_thread *thread); 162 void sys_trace_thread_suspend_user(struct k_thread *thread); 163 void sys_trace_thread_resume_user(struct k_thread *thread); 164 void sys_trace_thread_name_set_user(struct k_thread *thread); 165 void sys_trace_thread_switched_in_user(struct k_thread *thread); 166 void sys_trace_thread_switched_out_user(struct k_thread *thread); 167 void sys_trace_thread_info_user(struct k_thread *thread); 168 void sys_trace_thread_sched_ready_user(struct k_thread *thread); 169 void sys_trace_thread_pend_user(struct k_thread *thread); 170 void sys_trace_thread_priority_set_user(struct k_thread *thread, int prio); 171 void sys_trace_isr_enter_user(int nested_interrupts); 172 void sys_trace_isr_exit_user(int nested_interrupts); 173 void sys_trace_idle_user(); 174 175Enable this format with the :kconfig:option:`CONFIG_TRACING_USER` option. 176 177Transport Backends 178****************** 179 180The following backends are currently supported: 181 182* UART 183* USB 184* File (Using the native port with POSIX architecture based targets) 185* RTT (With SystemView) 186* RAM (buffer to be retrieved by a debugger) 187 188Using Tracing 189************* 190 191The sample :zephyr_file:`samples/subsys/tracing` demonstrates tracing with 192different formats and backends. 193 194To get started, the simplest way is to use the CTF format with the :ref:`native_sim <native_sim>` 195port, build the sample as follows: 196 197.. zephyr-app-commands:: 198 :tool: all 199 :app: samples/subsys/tracing 200 :board: native_sim 201 :gen-args: -DCONF_FILE=prj_native_ctf.conf 202 :goals: build 203 204You can then run the resulting binary with the option ``-trace-file`` to generate 205the tracing data:: 206 207 mkdir data 208 cp $ZEPHYR_BASE/subsys/tracing/ctf/tsdl/metadata data/ 209 ./build/zephyr/zephyr.exe -trace-file=data/channel0_0 210 211The resulting CTF output can be visualized using babeltrace or TraceCompass 212by pointing the tool to the ``data`` directory with the metadata and trace files. 213 214Using RAM backend 215================= 216 217For devices that do not have available I/O for tracing such as USB or UART but have 218enough RAM to collect trace data, the ram backend can be enabled with configuration 219:kconfig:option:`CONFIG_TRACING_BACKEND_RAM`. 220Adjust :kconfig:option:`CONFIG_RAM_TRACING_BUFFER_SIZE` to be able to record enough traces for your needs. 221Then thanks to a runtime debugger such as gdb this buffer can be fetched from the target 222to an host computer:: 223 224 (gdb) dump binary memory data/channel0_0 <ram_tracing_start> <ram_tracing_end> 225 226The resulting channel0_0 file have to be placed in a directory with the ``metadata`` 227file like the other backend. 228 229Visualisation Tools 230******************* 231 232TraceCompass 233============= 234 235TraceCompass is an open source tool that visualizes CTF events such as thread 236scheduling and interrupts, and is helpful to find unintended interactions and 237resource conflicts on complex systems. 238 239See also the presentation by Ericsson, 240`Advanced Trouble-shooting Of Real-time Systems 241<https://wiki.eclipse.org/images/0/0e/TechTalkOnlineDemoFeb2017_v1.pdf>`_. 242 243 244 245Future LTTng Inspiration 246************************ 247 248Currently, the top-layer provided here is quite simple and bare-bones, 249and needlessly copied from Zephyr's Segger SystemView debug module. 250 251For an OS like Zephyr, it would make sense to draw inspiration from 252Linux's LTTng and change the top-layer to serialize to the same format. 253Doing this would enable direct reuse of TraceCompass' canned analyses 254for Linux. Alternatively, LTTng-analyses in TraceCompass could be 255customized to Zephyr. It is ongoing work to enable TraceCompass 256visibility of Zephyr in a target-agnostic and open source way. 257 258 259I/O Taxonomy 260============= 261 262- Atomic Push/Produce/Write/Enqueue: 263 264 - synchronous: 265 means data-transmission has completed with the return of the 266 call. 267 268 - asynchronous: 269 means data-transmission is pending or ongoing with the return 270 of the call. Usually, interrupts/callbacks/signals or polling 271 is used to determine completion. 272 273 - buffered: 274 means data-transmissions are copied and grouped together to 275 form a larger ones. Usually for amortizing overhead (burst 276 dequeue) or jitter-mitigation (steady dequeue). 277 278 Examples: 279 - sync unbuffered 280 E.g. PIO via GPIOs having steady stream, no extra FIFO memory needed. 281 Low jitter but may be less efficient (can't amortize the overhead of 282 writing). 283 284 - sync buffered 285 E.g. ``fwrite()`` or enqueuing into FIFO. 286 Blockingly burst the FIFO when its buffer-waterlevel exceeds threshold. 287 Jitter due to bursts may lead to missed deadlines. 288 289 - async unbuffered 290 E.g. DMA, or zero-copying in shared memory. 291 Be careful of data hazards, race conditions, etc! 292 293 - async buffered 294 E.g. enqueuing into FIFO. 295 296 297 298- Atomic Pull/Consume/Read/Dequeue: 299 300 - synchronous: 301 means data-reception has completed with the return of the call. 302 303 - asynchronous: 304 means data-reception is pending or ongoing with the return of 305 the call. Usually, interrupts/callbacks/signals or polling is 306 used to determine completion. 307 308 - buffered: 309 means data is copied-in in larger chunks than request-size. 310 Usually for amortizing wait-time. 311 312 Examples: 313 - sync unbuffered 314 E.g. Blocking read-call, ``fread()`` or SPI-read, zero-copying in shared 315 memory. 316 317 - sync buffered 318 E.g. Blocking read-call with caching applied. 319 Makes sense if read pattern exhibits spatial locality. 320 321 - async unbuffered 322 E.g. zero-copying in shared memory. 323 Be careful of data hazards, race conditions, etc! 324 325 - async buffered 326 E.g. ``aio_read()`` or DMA. 327 328 329 330Unfortunately, I/O may not be atomic and may, therefore, require locking. 331Locking may not be needed if multiple independent channels are available. 332 333 - The system has non-atomic write and one shared channel 334 E.g. UART. Locking required. 335 336 ``lock(); emit(a); emit(b); emit(c); release();`` 337 338 - The system has non-atomic write but many channels 339 E.g. Multi-UART. Lock-free if the bottom-layer maps each Zephyr 340 thread+ISR to its own channel, thus alleviating races as each 341 thread is sequentially consistent with itself. 342 343 ``emit(a,thread_id); emit(b,thread_id); emit(c,thread_id);`` 344 345 - The system has atomic write but one shared channel 346 E.g. ``native_sim`` or board with DMA. May or may not need locking. 347 348 ``emit(a ## b ## c); /* Concat to buffer */`` 349 350 ``lock(); emit(a); emit(b); emit(c); release(); /* No extra mem */`` 351 352 - The system has atomic write and many channels 353 E.g. native_sim or board with multi-channel DMA. Lock-free. 354 355 ``emit(a ## b ## c, thread_id);`` 356 357 358Object tracking 359*************** 360 361The kernel can also maintain lists of objects that can be used to track 362their usage. Currently, the following lists can be enabled:: 363 364 struct k_timer *_track_list_k_timer; 365 struct k_mem_slab *_track_list_k_mem_slab; 366 struct k_sem *_track_list_k_sem; 367 struct k_mutex *_track_list_k_mutex; 368 struct k_stack *_track_list_k_stack; 369 struct k_msgq *_track_list_k_msgq; 370 struct k_mbox *_track_list_k_mbox; 371 struct k_pipe *_track_list_k_pipe; 372 struct k_queue *_track_list_k_queue; 373 struct k_event *_track_list_k_event; 374 375Those global variables are the head of each list - they can be traversed 376with the help of macro ``SYS_PORT_TRACK_NEXT``. For instance, to traverse 377all initialized mutexes, one can write:: 378 379 struct k_mutex *cur = _track_list_k_mutex; 380 while (cur != NULL) { 381 /* Do something */ 382 383 cur = SYS_PORT_TRACK_NEXT(cur); 384 } 385 386To enable object tracking, enable :kconfig:option:`CONFIG_TRACING_OBJECT_TRACKING`. 387Note that each list can be enabled or disabled via their tracing 388configuration. For example, to disable tracking of semaphores, one can 389disable :kconfig:option:`CONFIG_TRACING_SEMAPHORE`. 390 391Object tracking is behind tracing configuration as it currently leverages 392tracing infrastructure to perform the tracking. 393 394API 395*** 396 397 398Common 399====== 400 401.. doxygengroup:: subsys_tracing_apis 402 403Threads 404======= 405 406.. doxygengroup:: subsys_tracing_apis_thread 407 408Work Queues 409=========== 410 411.. doxygengroup:: subsys_tracing_apis_work 412 413Poll 414==== 415 416.. doxygengroup:: subsys_tracing_apis_poll 417 418Semaphore 419========= 420 421.. doxygengroup:: subsys_tracing_apis_sem 422 423Mutex 424===== 425 426.. doxygengroup:: subsys_tracing_apis_mutex 427 428Condition Variables 429=================== 430 431.. doxygengroup:: subsys_tracing_apis_condvar 432 433Queues 434====== 435 436.. doxygengroup:: subsys_tracing_apis_queue 437 438FIFO 439==== 440 441.. doxygengroup:: subsys_tracing_apis_fifo 442 443LIFO 444==== 445.. doxygengroup:: subsys_tracing_apis_lifo 446 447Stacks 448====== 449 450.. doxygengroup:: subsys_tracing_apis_stack 451 452Message Queues 453============== 454 455.. doxygengroup:: subsys_tracing_apis_msgq 456 457Mailbox 458======= 459 460.. doxygengroup:: subsys_tracing_apis_mbox 461 462Pipes 463====== 464 465.. doxygengroup:: subsys_tracing_apis_pipe 466 467Heaps 468===== 469 470.. doxygengroup:: subsys_tracing_apis_heap 471 472Memory Slabs 473============ 474 475.. doxygengroup:: subsys_tracing_apis_mslab 476 477Timers 478====== 479 480.. doxygengroup:: subsys_tracing_apis_timer 481 482Object tracking 483=============== 484 485.. doxygengroup:: subsys_tracing_object_tracking 486 487Syscalls 488======== 489 490.. doxygengroup:: subsys_tracing_apis_syscall 491