| 1 | --- |
| 2 | id: tracepoint-provider |
| 3 | --- |
| 4 | |
| 5 | Before jumping into defining tracepoints and inserting |
| 6 | them into the application source code, you must understand what a |
| 7 | _tracepoint provider_ is. |
| 8 | |
| 9 | For the sake of this guide, consider the following two files: |
| 10 | |
| 11 | `tp.h`: |
| 12 | |
| 13 | ~~~ c |
| 14 | #undef TRACEPOINT_PROVIDER |
| 15 | #define TRACEPOINT_PROVIDER my_provider |
| 16 | |
| 17 | #undef TRACEPOINT_INCLUDE |
| 18 | #define TRACEPOINT_INCLUDE "./tp.h" |
| 19 | |
| 20 | #if !defined(_TP_H) || defined(TRACEPOINT_HEADER_MULTI_READ) |
| 21 | #define _TP_H |
| 22 | |
| 23 | #include <lttng/tracepoint.h> |
| 24 | |
| 25 | TRACEPOINT_EVENT( |
| 26 | my_provider, |
| 27 | my_first_tracepoint, |
| 28 | TP_ARGS( |
| 29 | int, my_integer_arg, |
| 30 | char*, my_string_arg |
| 31 | ), |
| 32 | TP_FIELDS( |
| 33 | ctf_string(my_string_field, my_string_arg) |
| 34 | ctf_integer(int, my_integer_field, my_integer_arg) |
| 35 | ) |
| 36 | ) |
| 37 | |
| 38 | TRACEPOINT_EVENT( |
| 39 | my_provider, |
| 40 | my_other_tracepoint, |
| 41 | TP_ARGS( |
| 42 | int, my_int |
| 43 | ), |
| 44 | TP_FIELDS( |
| 45 | ctf_integer(int, some_field, my_int) |
| 46 | ) |
| 47 | ) |
| 48 | |
| 49 | #endif /* _TP_H */ |
| 50 | |
| 51 | #include <lttng/tracepoint-event.h> |
| 52 | ~~~ |
| 53 | |
| 54 | `tp.c`: |
| 55 | |
| 56 | ~~~ c |
| 57 | #define TRACEPOINT_CREATE_PROBES |
| 58 | |
| 59 | #include "tp.h" |
| 60 | ~~~ |
| 61 | |
| 62 | The two files above are defining a _tracepoint provider_. A tracepoint |
| 63 | provider is some sort of namespace for _tracepoint definitions_. Tracepoint |
| 64 | definitions are written above with the `TRACEPOINT_EVENT()` macro, and allow |
| 65 | eventual `tracepoint()` calls respecting their definitions to be inserted |
| 66 | into the user application's C source code (we explore this in a |
| 67 | later section). |
| 68 | |
| 69 | Many tracepoint definitions may be part of the same tracepoint provider |
| 70 | and many tracepoint providers may coexist in a user space application. A |
| 71 | tracepoint provider is packaged either: |
| 72 | |
| 73 | * directly into an existing user application's C source file |
| 74 | * as an object file |
| 75 | * as a static library |
| 76 | * as a shared library |
| 77 | |
| 78 | The two files above, `tp.h` and `tp.c`, show a typical template for |
| 79 | writing a tracepoint provider. LTTng-UST was designed so that two |
| 80 | tracepoint providers should not be defined in the same header file. |
| 81 | |
| 82 | We will now go through the various parts of the above files and |
| 83 | give them a meaning. As you may have noticed, the LTTng-UST API for |
| 84 | C/C++ applications is some preprocessor sorcery. The LTTng-UST macros |
| 85 | used in your application and those in the LTTng-UST headers are |
| 86 | combined to produce actual source code needed to make tracing possible |
| 87 | using LTTng. |
| 88 | |
| 89 | Let's start with the header file, `tp.h`. It begins with |
| 90 | |
| 91 | ~~~ c |
| 92 | #undef TRACEPOINT_PROVIDER |
| 93 | #define TRACEPOINT_PROVIDER my_provider |
| 94 | ~~~ |
| 95 | |
| 96 | `TRACEPOINT_PROVIDER` defines the name of the provider to which the |
| 97 | following tracepoint definitions belong. It is used internally by |
| 98 | LTTng-UST headers and _must_ be defined. Since `TRACEPOINT_PROVIDER` |
| 99 | could have been defined by another header file also included by the same |
| 100 | C source file, the best practice is to undefine it first. |
| 101 | |
| 102 | <div class="tip"> |
| 103 | <p><span class="t">Note:</span>Names in LTTng-UST follow the C |
| 104 | <em>identifier</em> syntax (starting with a letter and containing either |
| 105 | letters, numbers or underscores); they are <em>not</em> C strings |
| 106 | (not surrounded by double quotes). This is because LTTng-UST macros |
| 107 | use those identifier-like strings to create symbols (named types and |
| 108 | variables).</p> |
| 109 | </div> |
| 110 | |
| 111 | The tracepoint provider is a group of tracepoint definitions; its chosen |
| 112 | name should reflect this. A hierarchy like Java packages is recommended, |
| 113 | using underscores instead of dots, e.g., `org_company_project_component`. |
| 114 | |
| 115 | Next is `TRACEPOINT_INCLUDE`: |
| 116 | |
| 117 | ~~~ c |
| 118 | #undef TRACEPOINT_INCLUDE |
| 119 | #define TRACEPOINT_INCLUDE "./tp.h" |
| 120 | ~~~ |
| 121 | |
| 122 | This little bit of instrospection is needed by LTTng-UST to include |
| 123 | your header at various predefined places. |
| 124 | |
| 125 | Include guard follows: |
| 126 | |
| 127 | ~~~ c |
| 128 | #if !defined(_TP_H) || defined(TRACEPOINT_HEADER_MULTI_READ) |
| 129 | #define _TP_H |
| 130 | ~~~ |
| 131 | |
| 132 | Add these precompiler conditionals to ensure the tracepoint event |
| 133 | generation can include this file more than once. |
| 134 | |
| 135 | The `TRACEPOINT_EVENT()` macro is defined in a LTTng-UST header file which |
| 136 | must be included: |
| 137 | |
| 138 | ~~~ c |
| 139 | #include <lttng/tracepoint.h> |
| 140 | ~~~ |
| 141 | |
| 142 | This also allows the application to use the `tracepoint()` macro. |
| 143 | |
| 144 | Next is a list of `TRACEPOINT_EVENT()` macro calls which create the |
| 145 | actual tracepoint definitions. We skip this for the moment and |
| 146 | come back to how to use `TRACEPOINT_EVENT()` |
| 147 | [in a later section](#doc-defining-tracepoints). Just pay attention to |
| 148 | the first argument: it's always the name of the tracepoint provider |
| 149 | being defined in this header file. |
| 150 | |
| 151 | End of include guard: |
| 152 | |
| 153 | ~~~ c |
| 154 | #endif /* _TP_H */ |
| 155 | ~~~ |
| 156 | |
| 157 | Finally, include `<lttng/tracepoint-event.h>` to expand the macros: |
| 158 | |
| 159 | ~~~ c |
| 160 | #include <lttng/tracepoint-event.h> |
| 161 | ~~~ |
| 162 | |
| 163 | That's it for `tp.h`. Of course, this is only a header file; it must be |
| 164 | included in some C source file to actually use it. This is the job of |
| 165 | `tp.c`: |
| 166 | |
| 167 | ~~~ c |
| 168 | #define TRACEPOINT_CREATE_PROBES |
| 169 | |
| 170 | #include "tp.h" |
| 171 | ~~~ |
| 172 | |
| 173 | When `TRACEPOINT_CREATE_PROBES` is defined, the macros used in `tp.h`, |
| 174 | which is included just after, actually create the source code for |
| 175 | LTTng-UST probes (global data structures and functions) out of your |
| 176 | tracepoint definitions. How exactly this is done is out of this text's scope. |
| 177 | `TRACEPOINT_CREATE_PROBES` is discussed further |
| 178 | in [Building/linking tracepoint providers and the user application](#doc-building-tracepoint-providers-and-user-application). |
| 179 | |
| 180 | You could include other header files like `tp.h` here to create the probes |
| 181 | of different tracepoint providers, e.g.: |
| 182 | |
| 183 | ~~~ c |
| 184 | #define TRACEPOINT_CREATE_PROBES |
| 185 | |
| 186 | #include "tp1.h" |
| 187 | #include "tp2.h" |
| 188 | ~~~ |
| 189 | |
| 190 | The rule is: probes of a given tracepoint provider |
| 191 | must be created in exactly one source file. This source file could be one |
| 192 | of your project's; it doesn't have to be on its own like `tp.c`, although |
| 193 | [a later section](#doc-building-tracepoint-providers-and-user-application) |
| 194 | shows that doing so allows packaging the tracepoint providers |
| 195 | independently and keep them out of your application, also making it |
| 196 | possible to reuse them between projects. |
| 197 | |
| 198 | The following sections explain how to define tracepoints, how to use the |
| 199 | `tracepoint()` macro to instrument your user space C application and how |
| 200 | to build/link tracepoint providers and your application with LTTng-UST |
| 201 | support. |