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 | |
13 | your source code, albeit LTTng is much more faster and flexible than | |
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 | |
47 | #define TRACEPOINT_INCLUDE "./tp.h" | |
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 | ||
155 | <div class="img"> | |
156 | <img src="/images/docs26/ust-flow.png" alt="User space tracing's build process"> | |
157 | </div> | |
158 | ||
5e0cbfb0 | 159 | If you followed the |
3fd4924d | 160 | [Tracing the Linux kernel](#doc-tracing-the-linux-kernel) tutorial, the |
47bfcb75 | 161 | following steps should look familiar. |
5e0cbfb0 PP |
162 | |
163 | First, run the application with a few arguments: | |
164 | ||
165 | <pre class="term"> | |
166 | ./hello world and beyond | |
167 | </pre> | |
168 | ||
169 | You should see | |
170 | ||
171 | ~~~ text | |
172 | Hello, World! | |
173 | Press Enter to continue... | |
174 | ~~~ | |
175 | ||
176 | Use the `lttng` tool to list all available user space events: | |
177 | ||
178 | <pre class="term"> | |
179 | lttng list --userspace | |
180 | </pre> | |
181 | ||
182 | You should see the `hello_world:my_first_tracepoint` tracepoint listed | |
183 | under the `./hello` process. | |
184 | ||
185 | Create a tracing session: | |
186 | ||
187 | <pre class="term"> | |
3fd4924d | 188 | lttng create |
5e0cbfb0 PP |
189 | </pre> |
190 | ||
191 | Enable the `hello_world:my_first_tracepoint` tracepoint: | |
192 | ||
193 | <pre class="term"> | |
194 | lttng enable-event --userspace hello_world:my_first_tracepoint | |
195 | </pre> | |
196 | ||
197 | Start tracing: | |
198 | ||
199 | <pre class="term"> | |
200 | lttng start | |
201 | </pre> | |
202 | ||
203 | Go back to the running `hello` application and press Enter. All `tracepoint()` | |
47bfcb75 | 204 | calls are executed and the program finally exits. |
5e0cbfb0 | 205 | |
8eb0513d | 206 | Stop tracing: |
5e0cbfb0 PP |
207 | |
208 | <pre class="term"> | |
209 | lttng stop | |
5e0cbfb0 PP |
210 | </pre> |
211 | ||
212 | Done! You may use `lttng view` to list the recorded events. This command | |
213 | starts | |
3fd4924d PP |
214 | <a href="http://diamon.org/babeltrace" class="ext"><code>babeltrace</code></a> |
215 | in the background, if it's installed: | |
5e0cbfb0 PP |
216 | |
217 | <pre class="term"> | |
218 | lttng view | |
219 | </pre> | |
220 | ||
221 | should output something like: | |
222 | ||
223 | ~~~ text | |
224 | [18:10:27.684304496] (+?.?????????) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "hi there!", my_integer_field = 23 } | |
225 | [18:10:27.684338440] (+0.000033944) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "./hello", my_integer_field = 0 } | |
226 | [18:10:27.684340692] (+0.000002252) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "world", my_integer_field = 1 } | |
227 | [18:10:27.684342616] (+0.000001924) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "and", my_integer_field = 2 } | |
228 | [18:10:27.684343518] (+0.000000902) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "beyond", my_integer_field = 3 } | |
229 | [18:10:27.684357978] (+0.000014460) hostname hello_world:my_first_tracepoint: { cpu_id = 0 }, { my_string_field = "x^2", my_integer_field = 16 } | |
230 | ~~~ | |
231 | ||
8eb0513d PP |
232 | When you're done, you may destroy the tracing session, which does _not_ |
233 | destroy the generated trace files, leaving them available for further | |
234 | analysis: | |
235 | ||
236 | <pre class="term"> | |
3fd4924d | 237 | lttng destroy |
8eb0513d PP |
238 | </pre> |
239 | ||
5e0cbfb0 PP |
240 | The next section presents other alternatives to view and analyze your |
241 | LTTng traces. |