237 lines
7.8 KiB
ReStructuredText
237 lines
7.8 KiB
ReStructuredText
.. _ctf:
|
|
|
|
Common Trace Format for Zephyr
|
|
##############################
|
|
|
|
Common Trace Format, CTF, is an open format and language to describe trace
|
|
formats. This enables tool reuse, of which line-textual (babeltrace) and
|
|
graphical (TraceCompass) variants already exist.
|
|
|
|
CTF should look familiar to C programmers but adds stronger typing.
|
|
See `CTF - A Flexible, High-performance Binary Trace Format
|
|
<http://diamon.org/ctf/>`_.
|
|
|
|
Every system has application-specific events to trace out. Historically,
|
|
that has implied:
|
|
|
|
1. Determining the application-specific payload,
|
|
2. Choosing suitable serialization-format,
|
|
3. Writing the on-target serialization code,
|
|
4. Deciding on and writing the I/O transport mechanics,
|
|
5. Writing the PC-side deserializer/parser,
|
|
6. Writing custom ad-hoc tools for filtering and presentation.
|
|
|
|
CTF allows us to formally describe #1 and #2, which enables common
|
|
infrastructure for #5 and #6. This leaves #3 serialization code and #4
|
|
I/O mechanics up to a custom implementation.
|
|
|
|
This CTF debug module aims at providing a common #1 and #2 for Zephyr
|
|
("middle"), while providing a lean & generic interface for I/O ("bottom").
|
|
Currently, only one CTF bottom-layer exists, POSIX ``fwrite``, but many others
|
|
are possible:
|
|
|
|
- Async UART
|
|
- Async DMA
|
|
- Sync GPIO
|
|
- ... and many more.
|
|
|
|
In fact, I/O varies greatly from system to system. Therefore, it is
|
|
instructive to create a taxonomy for I/O types when we must ensure the
|
|
interface between CTF-middle and CTF-bottom is generic and efficient
|
|
enough to model these. See the *I/O taxonomy* section below.
|
|
|
|
|
|
A Generic Interface
|
|
-------------------
|
|
|
|
In CTF, an event is serialized to a packet containing one or more fields.
|
|
As seen from *I/O taxonomy* section below, a bottom layer may:
|
|
|
|
- perform actions at transaction-start (e.g. mutex-lock),
|
|
- process each field in some way (e.g. sync-push emit, concat, enqueue to
|
|
thread-bound FIFO),
|
|
- perform actions at transaction-stop (e.g. mutex-release, emit of concat
|
|
buffer).
|
|
|
|
The bottom-layer then needs to implement the following macros:
|
|
|
|
- ``CTF_BOTTOM_LOCK``: No-op or how to lock the I/O transaction
|
|
- ``CTF_BOTTOM_UNLOCK``: No-op or how to release the I/O transaction
|
|
- ``CTF_BOTTOM_FIELDS``: Var-args of fields. May process each field with ``MAP``
|
|
- ``CTF_BOTTOM_TIMESTAMPED_INTERNALLY``: Tells where timestamping is done
|
|
|
|
These macros along with inline functions of the middle-layer can yield a
|
|
very low-overhead tracing infrastructure.
|
|
|
|
|
|
CTF Middle-Layer Example
|
|
------------------------
|
|
|
|
The CTF_EVENT macro will serialize each argument to a field::
|
|
|
|
/* Example for illustration */
|
|
static inline void ctf_middle_foo(u32_t thread_id, ctf_bounded_string_t name)
|
|
{
|
|
CTF_EVENT(
|
|
CTF_LITERAL(u8_t, 42),
|
|
thread_id,
|
|
name,
|
|
"hello, I was emitted from function: ",
|
|
__func__ /* __func__ is standard since C99 */
|
|
);
|
|
}
|
|
|
|
How to serialize and emit fields as well as handling alignment, can be done
|
|
internally and statically at compile-time in the bottom-layer.
|
|
|
|
|
|
How to Activate?
|
|
----------------
|
|
|
|
Make sure ``CONFIG_TRACING_CTF=y`` is set (``CONFIG_TRACING_CTF_BOTTOM_POSIX=y``
|
|
is selected by default when using ``BOARD_NATIVE_POSIX``).
|
|
|
|
|
|
How to Use?
|
|
-----------
|
|
|
|
The resulting CTF output can be visualized using babeltrace or TraceCompass:
|
|
|
|
- The CTF output file can be specified in native posix using the ``-ctf-path``
|
|
command line option
|
|
|
|
- Create a new empty directory and copy into it:
|
|
|
|
- The TSDL file (``subsys/debug/tracing/ctf/tsdl/metadata``)
|
|
|
|
- The CTF output file renaming it to ``channel0_0``
|
|
|
|
- The trace can be opened by pointing TraceCompass or babeltrace to this new
|
|
directory
|
|
|
|
|
|
What is TraceCompass?
|
|
---------------------
|
|
|
|
TraceCompass is an open source tool that visualizes CTF events such as thread
|
|
scheduling and interrupts, and is helpful to find unintended interactions and
|
|
resource conflicts on complex systems.
|
|
|
|
See also the presentation by Ericsson,
|
|
`Advanced Trouble-shooting Of Real-time Systems
|
|
<https://wiki.eclipse.org/images/0/0e/TechTalkOnlineDemoFeb2017_v1.pdf>`_.
|
|
|
|
|
|
Future LTTng Inspiration
|
|
------------------------
|
|
|
|
Currently, the middle-layer provided here is quite simple and bare-bones,
|
|
and needlessly copied from Zephyr's Segger SystemView debug module.
|
|
|
|
For an OS like Zephyr, it would make sense to draw inspiration from
|
|
Linux's LTTng and change the middle-layer to serialize to the same format.
|
|
Doing this would enable direct reuse of TraceCompass' canned analyses
|
|
for Linux. Alternatively, LTTng-analyses in TraceCompass could be
|
|
customized to Zephyr. It is ongoing work to enable TraceCompass
|
|
visibility of Zephyr in a target-agnostic and open source way.
|
|
|
|
|
|
I/O Taxonomy
|
|
------------
|
|
|
|
- Atomic Push/Produce/Write/Enqueue:
|
|
|
|
- synchronous:
|
|
means data-transmission has completed with the return of the
|
|
call.
|
|
|
|
- asynchronous:
|
|
means data-transmission is pending or ongoing with the return
|
|
of the call. Usually, interrupts/callbacks/signals or polling
|
|
is used to determine completion.
|
|
|
|
- buffered:
|
|
means data-transmissions are copied and grouped together to
|
|
form a larger ones. Usually for amortizing overhead (burst
|
|
dequeue) or jitter-mitigation (steady dequeue).
|
|
|
|
Examples:
|
|
- sync unbuffered
|
|
E.g. PIO via GPIOs having steady stream, no extra FIFO memory needed.
|
|
Low jitter but may be less efficient (cant amortize the overhead of
|
|
writing).
|
|
|
|
- sync buffered
|
|
E.g. ``fwrite()`` or enqueuing into FIFO.
|
|
Blockingly burst the FIFO when its buffer-waterlevel exceeds threshold.
|
|
Jitter due to bursts may lead to missed deadlines.
|
|
|
|
- async unbuffered
|
|
E.g. DMA, or zero-copying in shared memory.
|
|
Be careful of data hazards, race conditions, etc!
|
|
|
|
- async buffered
|
|
E.g. enqueuing into FIFO.
|
|
|
|
|
|
|
|
- Atomic Pull/Consume/Read/Dequeue:
|
|
|
|
- synchronous:
|
|
means data-reception has completed with the return of the call.
|
|
|
|
- asynchronous:
|
|
means data-reception is pending or ongoing with the return of
|
|
the call. Usually, interrupts/callbacks/signals or polling is
|
|
used to determine completion.
|
|
|
|
- buffered:
|
|
means data is copied-in in larger chunks than request-size.
|
|
Usually for amortizing wait-time.
|
|
|
|
Examples:
|
|
- sync unbuffered
|
|
E.g. Blocking read-call, ``fread()`` or SPI-read, zero-copying in shared
|
|
memory.
|
|
|
|
- sync buffered
|
|
E.g. Blocking read-call with caching applied.
|
|
Makes sense if read pattern exhibits spatial locality.
|
|
|
|
- async unbuffered
|
|
E.g. zero-copying in shared memory.
|
|
Be careful of data hazards, race conditions, etc!
|
|
|
|
- async buffered
|
|
E.g. ``aio_read()`` or DMA.
|
|
|
|
|
|
|
|
Unfortunately, I/O may not be atomic and may, therefore, require locking.
|
|
Locking may not be needed if multiple independent channels are available.
|
|
|
|
- The system has non-atomic write and one shared channel
|
|
E.g. UART. Locking required.
|
|
|
|
``lock(); emit(a); emit(b); emit(c); release();``
|
|
|
|
- The system has non-atomic write but many channels
|
|
E.g. Multi-UART. Lock-free if the bottom-layer maps each Zephyr
|
|
thread+ISR to its own channel, thus alleviating races as each
|
|
thread is sequentially consistent with itself.
|
|
|
|
``emit(a,thread_id); emit(b,thread_id); emit(c,thread_id);``
|
|
|
|
- The system has atomic write but one shared channel
|
|
E.g. ``native_posix`` or board with DMA. May or may not need locking.
|
|
|
|
``emit(a ## b ## c); /* Concat to buffer */``
|
|
|
|
``lock(); emit(a); emit(b); emit(c); release(); /* No extra mem */``
|
|
|
|
- The system has atomic write and many channels
|
|
E.g. native_posix or board with multi-channel DMA. Lock-free.
|
|
|
|
``emit(a ## b ## c, thread_id);``
|
|
|