diff --git a/doc/trace/tracepoints.rst b/doc/trace/tracepoints.rst new file mode 100644 index 0000000000000000000000000000000000000000..b61c34785bb68807139b8e339b58fc9fcb224e48 --- /dev/null +++ b/doc/trace/tracepoints.rst @@ -0,0 +1,137 @@ +================================= +Adding static tracepoints to Jami +================================= + +:Author: Olivier Dion <olivier.dion@savoirfairelinux.com> + +This documentation explains the scope usage of static tracepoints in Jami and +how to add new tracepoints. + +Scope +----- + +Tracepoints work kind of like a logging system. It's however much faster, more +tolerant to faults and can incorporate additional contextual information only +available in the kernel. + +For example, tracepoints are buffered in a ring buffer that is shared with a +consumer daemon. Thus, Jami is not slow down by I/O operations like with +regular text logging. This makes some scenario much more reproducible. Also, +since the traces are in shared memory, even if Jami crashes the last traces are +still available to be consumed by the daemon + +For the contextual information, these can come from performance counters such +as the number of cache misses, branch misses, cpu cycles etc. It can also be +coming from the kernel itself such as the number of cpu migrations for a thread, +context switches, page faults, etc. + +These contextual information are **not** statically decided at compile time +when the tracepoint is defined. They are rather determined at trace time in a +tracing session (see doc/trace/tracepoint-analysis.rst). + +Enabling tracepoints +-------------------- + +To enable tracepoints in Jami, you should configure the project using the +``--enable-tracepoint`` feature. You also need ``lttng-ust >= 2.13.0`` and +``liburcu >= 0.13.0``. + +How to define a tracepoint +-------------------------- + +To define a new tracepoints, you need to add the definition in src/tracepoint.h + +It's recommended to use the ``LTTNG_UST_TRACEPOINT_EVENT`` macro and avoid using +the others except if you know what you're doing. + +The ``LTTNG_UST_TRACEPOINT_EVENT`` is composed of 4 parts: + + 1. The provider name. This is always ``jami``. + 2. The tracepoint name. A tracepoint name must be unique in a provider. + 3. The arguments passed to the tracepoints. Arguments are only evaluated if + the tracepoint is enabled at runtime. + 4. The fields of the tracepoint. Fields can use the tracepoint's arguments. + +NOTE! As the documentation of LTTng says, the concatenation of provider name + +tracepoint name must **not exceed 254 characters** or you will get bite. + +For example, here's the definition of a tracepoint for the scheduled executor in +src/tracepoint.h:: + + LTTNG_UST_TRACEPOINT_EVENT( + jami, + scheduled_executor_task_begin, + LTTNG_UST_TP_ARGS( + const char *, executor_name, + const char *, filename, + uint32_t, linum, + uint64_t, cookie + ), + LTTNG_UST_TP_FIELDS( + lttng_ust_field_string(executor, executor_name) + lttng_ust_field_string(source_filename, filename) + lttng_ust_field_integer(uint32_t, source_line, linum) + lttng_ust_field_integer(uint64_t, cookie, cookie) + ) + ) + +We can see that: + + 1. The provider name is ``jami``. + 2. The tracepoint name is ``scheduled_executor_task_begin``. + 3. The tracepoint takes 4 arguments of types ``const char *``, ``const char *``, + ``uint32_t``, ``uint64_t`` respectively named ``executor_name``, ``filename``, + ``linum``, ``cookie``. + 4. The tracepoint generates 4 fields of CTF type ``string``, ``string``, + ``integer``, ``integer`` respectively named ``executor``, ``source_filename``, + ``source_line``, ``cookie``. + +NOTE! In this example, the expressions of the fields are the arguments of the +tracepoint but it could be different. For example, you could replace +``lttng_ust_field_integer(uint64_t, cookie, cookie)`` with +``lttng_ust_field_integer(uint64_t, cookie, linum + cookie * cookie)``. At the +end, any C expression can be used in the value of a field. The expression can +refer to all arguments of the tracepoints. Thus, if one of your argument to the +tracepoint is a pointer to a structure, you can deference the structure to read +a member. Just be careful for side effects. + +How to use a tracepoint +----------------------- + +Now that you have defined a tracepoint, you perhaps want to use it in Jami or +reuse an existing one. The first thing to do is to import src/tracepoint.h in +your compilation unit. Then you need to use the ``jami_tracepoint()`` +macro. It takes at least two arguments followed by a variable number of +arguments. The first argument is the provider name which is always ``jami`` in +our case. The second argument is the tracepoint name. The rest of the +arguments are the arguments defined by the tracepoint. + +For example, here's how the tracepoint ``secheduled_executor_task_begin`` is +used in src/scheduled_executor.h:: + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + void run(const char* executor_name) + { + if (job_.fn) { + jami_tracepoint(scheduled_executor_task_begin, + executor_name, + job_.filename, job_.linum, + cookie_); + job_.fn(); + jami_tracepoint(scheduled_executor_task_end, + cookie_); + } + } + #pragma GCC pop + +NOTE! The ``jami_tracepoint(...)`` macro expands to +``static_assert(true)`` if tracepoints are not enabled in Jami. Thus, never do +side effects in tracepoint! This is also why we use the GCC diagnostic pragma +here to avoid the warnings about unused parameter when tracepoints are disabled. + + +Further reading +--------------- + +`https://lttng.org/docs/v2.13/`_