Commit | Line | Data |
---|---|---|
5e0cbfb0 PP |
1 | --- |
2 | id: tracing-your-own-user-application | |
3 | --- | |
4 | ||
5 | The previous section helped you create a trace out of Linux kernel events. | |
6 | This section steps you through a simple example showing you how to trace | |
7 | a _Hello world_ program written in C. | |
8 | ||
3fd4924d | 9 | Make sure the LTTng-tools and LTTng-UST packages |
5e0cbfb0 PP |
10 | [are installed](#doc-installing-lttng). |
11 | ||
12 | Tracing is just like having `printf()` calls at specific locations of | |
069b9061 | 13 | your source code, albeit LTTng is much faster and more flexible than |
5e0cbfb0 PP |
14 | `printf()`. In the LTTng realm, **`tracepoint()`** is analogous to |
15 | `printf()`. | |
16 | ||
17 | Unlike `printf()`, though, `tracepoint()` does not use a format string to | |
18 | know the types of its arguments: the formats of all tracepoints must be | |
19 | defined before using them. So before even writing our _Hello world_ program, | |
3fd4924d PP |
20 | we need to define the format of our tracepoint. This is done by creating a |
21 | **tracepoint provider**, which consists of a tracepoint provider header | |
22 | (`.h` file) and a tracepoint provider definition (`.c` file). | |
5e0cbfb0 | 23 | |
3fd4924d PP |
24 | The tracepoint provider header contains some boilerplate as well as a |
25 | list of tracepoint definitions and other optional definition entries | |
26 | which we skip for this quickstart. Each tracepoint is defined using the | |
5e0cbfb0 PP |
27 | `TRACEPOINT_EVENT()` macro. For each tracepoint, you must provide: |
28 | ||
3fd4924d PP |
29 | * a **provider name**, which is the "scope" or namespace of this |
30 | tracepoint (this usually includes the company and project names) | |
5e0cbfb0 | 31 | * a **tracepoint name** |
3fd4924d PP |
32 | * a **list of arguments** for the eventual `tracepoint()` call, each |
33 | item being: | |
5e0cbfb0 PP |
34 | * the argument C type |
35 | * the argument name | |
47bfcb75 PP |
36 | * a **list of fields**, which correspond to the actual fields of the |
37 | recorded events for this tracepoint | |
5e0cbfb0 | 38 | |
3fd4924d PP |
39 | Here's an example of a simple tracepoint provider header with two |
40 | arguments: an integer and a string: | |
5e0cbfb0 PP |
41 | |
42 | ~~~ c | |
3fd4924d PP |
43 | #undef TRACEPOINT_PROVIDER |
44 | #define TRACEPOINT_PROVIDER hello_world | |
45 | ||
46 | #undef TRACEPOINT_INCLUDE | |
ca3db0f4 | 47 | #define TRACEPOINT_INCLUDE "./hello-tp.h" |
3fd4924d PP |
48 | |
49 | #if !defined(_HELLO_TP_H) || defined(TRACEPOINT_HEADER_MULTI_READ) | |
50 | #define _HELLO_TP_H | |
51 | ||
52 | #include <lttng/tracepoint.h> | |
53 | ||
5e0cbfb0 PP |
54 | TRACEPOINT_EVENT( |
55 | hello_world, | |
56 | my_first_tracepoint, | |
57 | TP_ARGS( | |
58 | int, my_integer_arg, | |
59 | char*, my_string_arg | |
60 | ), | |
61 | TP_FIELDS( | |
62 | ctf_string(my_string_field, my_string_arg) | |
63 | ctf_integer(int, my_integer_field, my_integer_arg) | |
64 | ) | |
65 | ) | |
3fd4924d PP |
66 | |
67 | #endif /* _HELLO_TP_H */ | |
68 | ||
69 | #include <lttng/tracepoint-event.h> | |
5e0cbfb0 PP |
70 | ~~~ |
71 | ||
72 | The exact syntax is well explained in the | |
3fd4924d | 73 | [C application](#doc-c-application) instrumentation guide of the |
5e0cbfb0 | 74 | [Using LTTng](#doc-using-lttng) chapter, as well as in the |
5037eb52 | 75 | <a href="/man/3/lttng-ust" class="ext">LTTng-UST man page</a>. |
5e0cbfb0 | 76 | |
3fd4924d | 77 | Save the above snippet as `hello-tp.h`. |
5e0cbfb0 | 78 | |
3fd4924d PP |
79 | Write the tracepoint provider definition as `hello-tp.c`: |
80 | ||
81 | ~~~ c | |
82 | #define TRACEPOINT_CREATE_PROBES | |
83 | #define TRACEPOINT_DEFINE | |
5e0cbfb0 | 84 | |
3fd4924d PP |
85 | #include "hello-tp.h" |
86 | ~~~ | |
5e0cbfb0 | 87 | |
3fd4924d | 88 | Create the tracepoint provider: |
5e0cbfb0 | 89 | |
3fd4924d PP |
90 | <pre class="term"> |
91 | gcc -c -I. hello-tp.c | |
92 | </pre> | |
5e0cbfb0 PP |
93 | |
94 | Now, by including `hello-tp.h` in your own application, you may use the | |
95 | tracepoint defined above by properly refering to it when calling | |
96 | `tracepoint()`: | |
97 | ||
98 | ~~~ c | |
99 | #include <stdio.h> | |
100 | #include "hello-tp.h" | |
101 | ||
3fd4924d | 102 | int main(int argc, char *argv[]) |
5e0cbfb0 PP |
103 | { |
104 | int x; | |
105 | ||
106 | puts("Hello, World!\nPress Enter to continue..."); | |
107 | ||
3fd4924d PP |
108 | /* |
109 | * The following getchar() call is only placed here for the purpose | |
5e0cbfb0 PP |
110 | * of this demonstration, for pausing the application in order for |
111 | * you to have time to list its events. It's not needed otherwise. | |
112 | */ | |
113 | getchar(); | |
114 | ||
3fd4924d PP |
115 | /* |
116 | * A tracepoint() call. Arguments, as defined in hello-tp.h: | |
5e0cbfb0 PP |
117 | * |
118 | * 1st: provider name (always) | |
119 | * 2nd: tracepoint name (always) | |
120 | * 3rd: my_integer_arg (first user-defined argument) | |
121 | * 4th: my_string_arg (second user-defined argument) | |
122 | * | |
123 | * Notice the provider and tracepoint names are NOT strings; | |
124 | * they are in fact parts of variables created by macros in | |
125 | * hello-tp.h. | |
126 | */ | |
127 | tracepoint(hello_world, my_first_tracepoint, 23, "hi there!"); | |
128 | ||
129 | for (x = 0; x < argc; ++x) { | |
130 | tracepoint(hello_world, my_first_tracepoint, x, argv[x]); | |
131 | } | |
132 | ||
133 | puts("Quitting now!"); | |
134 | ||
135 | tracepoint(hello_world, my_first_tracepoint, x * x, "x^2"); | |
136 | ||
137 | return 0; | |
138 | } | |
139 | ~~~ | |
140 | ||
3fd4924d | 141 | Save this as `hello.c`, next to `hello-tp.c`. |
5e0cbfb0 | 142 | |
3fd4924d PP |
143 | Notice `hello-tp.h`, the tracepoint provider header, is included |
144 | by `hello.c`. | |
5e0cbfb0 PP |
145 | |
146 | You are now ready to compile the application with LTTng-UST support: | |
147 | ||
148 | <pre class="term"> | |
3fd4924d PP |
149 | gcc -c hello.c |
150 | gcc -o hello hello.o hello-tp.o -llttng-ust -ldl</strong> | |
5e0cbfb0 PP |
151 | </pre> |
152 | ||
3fd4924d PP |
153 | Here's the whole build process: |
154 | ||
5703c9f3 | 155 | <figure class="img img-100"> |
3fd4924d | 156 | <img src="/images/docs26/ust-flow.png" alt="User space tracing's build process"> |
d9a0e8b1 PP |
157 | <figcaption> |
158 | User space tracing build process | |
159 | </figcaption> | |
5703c9f3 | 160 | </figure> |
3fd4924d | 161 | |
5e0cbfb0 | 162 | If you followed the |
3fd4924d | 163 | [Tracing the Linux kernel](#doc-tracing-the-linux-kernel) tutorial, the |
47bfcb75 | 164 | following steps should look familiar. |
5e0cbfb0 PP |
165 | |
166 | First, run the application with a few arguments: | |
167 | ||
168 | <pre class="term"> | |
169 | ./hello world and beyond | |
170 | </pre> | |
171 | ||
172 | You should see | |
173 | ||
174 | ~~~ text | |
175 | Hello, World! | |
176 | Press Enter to continue... | |
177 | ~~~ | |
178 | ||
179 | Use the `lttng` tool to list all available user space events: | |
180 | ||
181 | <pre class="term"> | |
182 | lttng list --userspace | |
183 | </pre> | |
184 | ||
185 | You should see the `hello_world:my_first_tracepoint` tracepoint listed | |
186 | under the `./hello` process. | |
187 | ||
188 | Create a tracing session: | |
189 | ||
190 | <pre class="term"> | |
3fd4924d | 191 | lttng create |
5e0cbfb0 PP |
192 | </pre> |
193 | ||
194 | Enable the `hello_world:my_first_tracepoint` tracepoint: | |
195 | ||
196 | <pre class="term"> | |
197 | lttng enable-event --userspace hello_world:my_first_tracepoint | |
198 | </pre> | |
199 | ||
200 | Start tracing: | |
201 | ||
202 | <pre class="term"> | |
203 | lttng start | |
204 | </pre> | |
205 | ||
206 | Go back to the running `hello` application and press Enter. All `tracepoint()` | |
47bfcb75 | 207 | calls are executed and the program finally exits. |
5e0cbfb0 | 208 | |
8eb0513d | 209 | Stop tracing: |
5e0cbfb0 PP |
210 | |
211 | <pre class="term"> | |
212 | lttng stop | |
5e0cbfb0 PP |
213 | </pre> |
214 | ||
215 | Done! You may use `lttng view` to list the recorded events. This command | |
216 | starts | |
3fd4924d PP |
217 | <a href="http://diamon.org/babeltrace" class="ext"><code>babeltrace</code></a> |
218 | in the background, if it's installed: | |
5e0cbfb0 PP |
219 | |
220 | <pre class="term"> | |
221 | lttng view | |
222 | </pre> | |
223 | ||
224 | should output something like: | |
225 | ||
226 | ~~~ text | |
227 | [18:10:27.684304496] (+?.?????????) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "hi there!", my_integer_field = 23 } | |
228 | [18:10:27.684338440] (+0.000033944) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "./hello", my_integer_field = 0 } | |
229 | [18:10:27.684340692] (+0.000002252) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "world", my_integer_field = 1 } | |
230 | [18:10:27.684342616] (+0.000001924) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "and", my_integer_field = 2 } | |
231 | [18:10:27.684343518] (+0.000000902) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "beyond", my_integer_field = 3 } | |
232 | [18:10:27.684357978] (+0.000014460) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "x^2", my_integer_field = 16 } | |
233 | ~~~ | |
234 | ||
8eb0513d PP |
235 | When you're done, you may destroy the tracing session, which does _not_ |
236 | destroy the generated trace files, leaving them available for further | |
237 | analysis: | |
238 | ||
239 | <pre class="term"> | |
3fd4924d | 240 | lttng destroy |
8eb0513d PP |
241 | </pre> |
242 | ||
5e0cbfb0 PP |
243 | The next section presents other alternatives to view and analyze your |
244 | LTTng traces. |