lttng: show man page when using command's --help
[lttng-tools.git] / src / bin / lttng / commands / add_context.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _LGPL_SOURCE
20 #include <ctype.h>
21 #include <popt.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <assert.h>
29
30 #include <urcu/list.h>
31
32 #include <common/mi-lttng.h>
33
34 #include "../command.h"
35
36 static char *opt_channel_name;
37 static char *opt_session_name;
38 static int opt_kernel;
39 static int opt_userspace;
40 static int opt_jul;
41 static int opt_log4j;
42 static char *opt_type;
43
44 enum {
45 OPT_HELP = 1,
46 OPT_TYPE,
47 OPT_USERSPACE,
48 OPT_JUL,
49 OPT_LOG4J,
50 OPT_LIST_OPTIONS,
51 OPT_LIST,
52 };
53
54 static struct lttng_handle *handle;
55 static struct mi_writer *writer;
56
57 /*
58 * Taken from the LTTng ABI
59 */
60 enum context_type {
61 CONTEXT_PID = 0,
62 CONTEXT_PERF_COUNTER = 1, /* Backward compat. */
63 CONTEXT_PROCNAME = 2,
64 CONTEXT_PRIO = 3,
65 CONTEXT_NICE = 4,
66 CONTEXT_VPID = 5,
67 CONTEXT_TID = 6,
68 CONTEXT_VTID = 7,
69 CONTEXT_PPID = 8,
70 CONTEXT_VPPID = 9,
71 CONTEXT_PTHREAD_ID = 10,
72 CONTEXT_HOSTNAME = 11,
73 CONTEXT_IP = 12,
74 CONTEXT_PERF_CPU_COUNTER = 13,
75 CONTEXT_PERF_THREAD_COUNTER = 14,
76 CONTEXT_APP_CONTEXT = 15,
77 CONTEXT_INTERRUPTIBLE = 16,
78 CONTEXT_PREEMPTIBLE = 17,
79 CONTEXT_NEED_RESCHEDULE = 18,
80 CONTEXT_MIGRATABLE = 19,
81 };
82
83 /*
84 * Taken from the Perf ABI (all enum perf_*)
85 */
86 enum perf_type {
87 PERF_TYPE_HARDWARE = 0,
88 PERF_TYPE_SOFTWARE = 1,
89 PERF_TYPE_HW_CACHE = 3,
90 };
91
92 enum perf_count_hard {
93 PERF_COUNT_HW_CPU_CYCLES = 0,
94 PERF_COUNT_HW_INSTRUCTIONS = 1,
95 PERF_COUNT_HW_CACHE_REFERENCES = 2,
96 PERF_COUNT_HW_CACHE_MISSES = 3,
97 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
98 PERF_COUNT_HW_BRANCH_MISSES = 5,
99 PERF_COUNT_HW_BUS_CYCLES = 6,
100 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
101 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
102 };
103
104 enum perf_count_soft {
105 PERF_COUNT_SW_CPU_CLOCK = 0,
106 PERF_COUNT_SW_TASK_CLOCK = 1,
107 PERF_COUNT_SW_PAGE_FAULTS = 2,
108 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
109 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
110 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
111 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
112 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
113 PERF_COUNT_SW_EMULATION_FAULTS = 8,
114 };
115
116 /*
117 * Generalized hardware cache events:
118 *
119 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
120 * { read, write, prefetch } x
121 * { accesses, misses }
122 */
123 enum perf_hw_cache_id {
124 PERF_COUNT_HW_CACHE_L1D = 0,
125 PERF_COUNT_HW_CACHE_L1I = 1,
126 PERF_COUNT_HW_CACHE_LL = 2,
127 PERF_COUNT_HW_CACHE_DTLB = 3,
128 PERF_COUNT_HW_CACHE_ITLB = 4,
129 PERF_COUNT_HW_CACHE_BPU = 5,
130
131 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
132 };
133
134 enum perf_hw_cache_op_id {
135 PERF_COUNT_HW_CACHE_OP_READ = 0,
136 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
137 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
138
139 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
140 };
141
142 enum perf_hw_cache_op_result_id {
143 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
144 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
145
146 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
147 };
148
149 static struct poptOption long_options[] = {
150 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
151 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
152 {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
153 {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
154 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
155 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
156 {"jul", 'j', POPT_ARG_NONE, 0, OPT_JUL, 0, 0},
157 {"log4j", 'l', POPT_ARG_NONE, 0, OPT_LOG4J, 0, 0},
158 {"type", 't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
159 {"list", 0, POPT_ARG_NONE, NULL, OPT_LIST, NULL, NULL},
160 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
161 {0, 0, 0, 0, 0, 0, 0}
162 };
163
164 /*
165 * Context options
166 */
167 #define PERF_HW(optstr, name, type, hide) \
168 { \
169 optstr, type, hide, \
170 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
171 }
172
173 #define PERF_SW(optstr, name, type, hide) \
174 { \
175 optstr, type, hide, \
176 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
177 }
178
179 #define _PERF_HW_CACHE(optstr, name, type, op, result, hide) \
180 { \
181 optstr, type, hide, \
182 .u.perf = { \
183 PERF_TYPE_HW_CACHE, \
184 (uint64_t) PERF_COUNT_HW_CACHE_##name \
185 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
186 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
187 }, \
188 }
189
190 #define PERF_HW_CACHE(optstr, name, type, hide) \
191 _PERF_HW_CACHE(optstr "-loads", name, type, \
192 READ, ACCESS, hide), \
193 _PERF_HW_CACHE(optstr "-load-misses", name, type, \
194 READ, MISS, hide), \
195 _PERF_HW_CACHE(optstr "-stores", name, type, \
196 WRITE, ACCESS, hide), \
197 _PERF_HW_CACHE(optstr "-store-misses", name, type, \
198 WRITE, MISS, hide), \
199 _PERF_HW_CACHE(optstr "-prefetches", name, type, \
200 PREFETCH, ACCESS, hide), \
201 _PERF_HW_CACHE(optstr "-prefetch-misses", name, type, \
202 PREFETCH, MISS, hide)
203
204 static
205 const struct ctx_opts {
206 char *symbol;
207 enum context_type ctx_type;
208 int hide_help; /* Hide from --help */
209 union {
210 struct {
211 uint32_t type;
212 uint64_t config;
213 } perf;
214 struct {
215 char *provider_name;
216 char *ctx_name;
217 } app_ctx;
218 } u;
219 } ctx_opts[] = {
220 { "pid", CONTEXT_PID },
221 { "procname", CONTEXT_PROCNAME },
222 { "prio", CONTEXT_PRIO },
223 { "nice", CONTEXT_NICE },
224 { "vpid", CONTEXT_VPID },
225 { "tid", CONTEXT_TID },
226 { "pthread_id", CONTEXT_PTHREAD_ID },
227 { "vtid", CONTEXT_VTID },
228 { "ppid", CONTEXT_PPID },
229 { "vppid", CONTEXT_VPPID },
230 { "hostname", CONTEXT_HOSTNAME },
231 { "ip", CONTEXT_IP },
232 { "interruptible", CONTEXT_INTERRUPTIBLE },
233 { "preemptible", CONTEXT_PREEMPTIBLE },
234 { "need_reschedule", CONTEXT_NEED_RESCHEDULE },
235 { "migratable", CONTEXT_MIGRATABLE },
236
237 /* Perf options */
238
239 /* Perf per-CPU counters */
240 PERF_HW("perf:cpu:cpu-cycles", CPU_CYCLES,
241 CONTEXT_PERF_CPU_COUNTER, 0),
242 PERF_HW("perf:cpu:cycles", CPU_CYCLES,
243 CONTEXT_PERF_CPU_COUNTER, 0),
244 PERF_HW("perf:cpu:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
245 CONTEXT_PERF_CPU_COUNTER, 0),
246 PERF_HW("perf:cpu:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
247 CONTEXT_PERF_CPU_COUNTER, 0),
248 PERF_HW("perf:cpu:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
249 CONTEXT_PERF_CPU_COUNTER, 0),
250 PERF_HW("perf:cpu:idle-cycles-backend", STALLED_CYCLES_BACKEND,
251 CONTEXT_PERF_CPU_COUNTER, 0),
252 PERF_HW("perf:cpu:instructions", INSTRUCTIONS,
253 CONTEXT_PERF_CPU_COUNTER, 0),
254 PERF_HW("perf:cpu:cache-references", CACHE_REFERENCES,
255 CONTEXT_PERF_CPU_COUNTER, 0),
256 PERF_HW("perf:cpu:cache-misses", CACHE_MISSES,
257 CONTEXT_PERF_CPU_COUNTER, 0),
258 PERF_HW("perf:cpu:branch-instructions", BRANCH_INSTRUCTIONS,
259 CONTEXT_PERF_CPU_COUNTER, 0),
260 PERF_HW("perf:cpu:branches", BRANCH_INSTRUCTIONS,
261 CONTEXT_PERF_CPU_COUNTER, 0),
262 PERF_HW("perf:cpu:branch-misses", BRANCH_MISSES,
263 CONTEXT_PERF_CPU_COUNTER, 0),
264 PERF_HW("perf:cpu:bus-cycles", BUS_CYCLES,
265 CONTEXT_PERF_CPU_COUNTER, 0),
266
267 PERF_HW_CACHE("perf:cpu:L1-dcache", L1D,
268 CONTEXT_PERF_CPU_COUNTER, 0),
269 PERF_HW_CACHE("perf:cpu:L1-icache", L1I,
270 CONTEXT_PERF_CPU_COUNTER, 0),
271 PERF_HW_CACHE("perf:cpu:LLC", LL,
272 CONTEXT_PERF_CPU_COUNTER, 0),
273 PERF_HW_CACHE("perf:cpu:dTLB", DTLB,
274 CONTEXT_PERF_CPU_COUNTER, 0),
275 _PERF_HW_CACHE("perf:cpu:iTLB-loads", ITLB,
276 CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
277 _PERF_HW_CACHE("perf:cpu:iTLB-load-misses", ITLB,
278 CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
279 _PERF_HW_CACHE("perf:cpu:branch-loads", BPU,
280 CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
281 _PERF_HW_CACHE("perf:cpu:branch-load-misses", BPU,
282 CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
283
284 PERF_SW("perf:cpu:cpu-clock", CPU_CLOCK,
285 CONTEXT_PERF_CPU_COUNTER, 0),
286 PERF_SW("perf:cpu:task-clock", TASK_CLOCK,
287 CONTEXT_PERF_CPU_COUNTER, 0),
288 PERF_SW("perf:cpu:page-fault", PAGE_FAULTS,
289 CONTEXT_PERF_CPU_COUNTER, 0),
290 PERF_SW("perf:cpu:faults", PAGE_FAULTS,
291 CONTEXT_PERF_CPU_COUNTER, 0),
292 PERF_SW("perf:cpu:major-faults", PAGE_FAULTS_MAJ,
293 CONTEXT_PERF_CPU_COUNTER, 0),
294 PERF_SW("perf:cpu:minor-faults", PAGE_FAULTS_MIN,
295 CONTEXT_PERF_CPU_COUNTER, 0),
296 PERF_SW("perf:cpu:context-switches", CONTEXT_SWITCHES,
297 CONTEXT_PERF_CPU_COUNTER, 0),
298 PERF_SW("perf:cpu:cs", CONTEXT_SWITCHES,
299 CONTEXT_PERF_CPU_COUNTER, 0),
300 PERF_SW("perf:cpu:cpu-migrations", CPU_MIGRATIONS,
301 CONTEXT_PERF_CPU_COUNTER, 0),
302 PERF_SW("perf:cpu:migrations", CPU_MIGRATIONS,
303 CONTEXT_PERF_CPU_COUNTER, 0),
304 PERF_SW("perf:cpu:alignment-faults", ALIGNMENT_FAULTS,
305 CONTEXT_PERF_CPU_COUNTER, 0),
306 PERF_SW("perf:cpu:emulation-faults", EMULATION_FAULTS,
307 CONTEXT_PERF_CPU_COUNTER, 0),
308
309 /* Perf per-thread counters */
310 PERF_HW("perf:thread:cpu-cycles", CPU_CYCLES,
311 CONTEXT_PERF_THREAD_COUNTER, 0),
312 PERF_HW("perf:thread:cycles", CPU_CYCLES,
313 CONTEXT_PERF_THREAD_COUNTER, 0),
314 PERF_HW("perf:thread:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
315 CONTEXT_PERF_THREAD_COUNTER, 0),
316 PERF_HW("perf:thread:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
317 CONTEXT_PERF_THREAD_COUNTER, 0),
318 PERF_HW("perf:thread:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
319 CONTEXT_PERF_THREAD_COUNTER, 0),
320 PERF_HW("perf:thread:idle-cycles-backend", STALLED_CYCLES_BACKEND,
321 CONTEXT_PERF_THREAD_COUNTER, 0),
322 PERF_HW("perf:thread:instructions", INSTRUCTIONS,
323 CONTEXT_PERF_THREAD_COUNTER, 0),
324 PERF_HW("perf:thread:cache-references", CACHE_REFERENCES,
325 CONTEXT_PERF_THREAD_COUNTER, 0),
326 PERF_HW("perf:thread:cache-misses", CACHE_MISSES,
327 CONTEXT_PERF_THREAD_COUNTER, 0),
328 PERF_HW("perf:thread:branch-instructions", BRANCH_INSTRUCTIONS,
329 CONTEXT_PERF_THREAD_COUNTER, 0),
330 PERF_HW("perf:thread:branches", BRANCH_INSTRUCTIONS,
331 CONTEXT_PERF_THREAD_COUNTER, 0),
332 PERF_HW("perf:thread:branch-misses", BRANCH_MISSES,
333 CONTEXT_PERF_THREAD_COUNTER, 0),
334 PERF_HW("perf:thread:bus-cycles", BUS_CYCLES,
335 CONTEXT_PERF_THREAD_COUNTER, 0),
336
337 PERF_HW_CACHE("perf:thread:L1-dcache", L1D,
338 CONTEXT_PERF_THREAD_COUNTER, 0),
339 PERF_HW_CACHE("perf:thread:L1-icache", L1I,
340 CONTEXT_PERF_THREAD_COUNTER, 0),
341 PERF_HW_CACHE("perf:thread:LLC", LL,
342 CONTEXT_PERF_THREAD_COUNTER, 0),
343 PERF_HW_CACHE("perf:thread:dTLB", DTLB,
344 CONTEXT_PERF_THREAD_COUNTER, 0),
345 _PERF_HW_CACHE("perf:thread:iTLB-loads", ITLB,
346 CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
347 _PERF_HW_CACHE("perf:thread:iTLB-load-misses", ITLB,
348 CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
349 _PERF_HW_CACHE("perf:thread:branch-loads", BPU,
350 CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
351 _PERF_HW_CACHE("perf:thread:branch-load-misses", BPU,
352 CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
353
354 PERF_SW("perf:thread:cpu-clock", CPU_CLOCK,
355 CONTEXT_PERF_THREAD_COUNTER, 0),
356 PERF_SW("perf:thread:task-clock", TASK_CLOCK,
357 CONTEXT_PERF_THREAD_COUNTER, 0),
358 PERF_SW("perf:thread:page-fault", PAGE_FAULTS,
359 CONTEXT_PERF_THREAD_COUNTER, 0),
360 PERF_SW("perf:thread:faults", PAGE_FAULTS,
361 CONTEXT_PERF_THREAD_COUNTER, 0),
362 PERF_SW("perf:thread:major-faults", PAGE_FAULTS_MAJ,
363 CONTEXT_PERF_THREAD_COUNTER, 0),
364 PERF_SW("perf:thread:minor-faults", PAGE_FAULTS_MIN,
365 CONTEXT_PERF_THREAD_COUNTER, 0),
366 PERF_SW("perf:thread:context-switches", CONTEXT_SWITCHES,
367 CONTEXT_PERF_THREAD_COUNTER, 0),
368 PERF_SW("perf:thread:cs", CONTEXT_SWITCHES,
369 CONTEXT_PERF_THREAD_COUNTER, 0),
370 PERF_SW("perf:thread:cpu-migrations", CPU_MIGRATIONS,
371 CONTEXT_PERF_THREAD_COUNTER, 0),
372 PERF_SW("perf:thread:migrations", CPU_MIGRATIONS,
373 CONTEXT_PERF_THREAD_COUNTER, 0),
374 PERF_SW("perf:thread:alignment-faults", ALIGNMENT_FAULTS,
375 CONTEXT_PERF_THREAD_COUNTER, 0),
376 PERF_SW("perf:thread:emulation-faults", EMULATION_FAULTS,
377 CONTEXT_PERF_THREAD_COUNTER, 0),
378
379 /*
380 * Perf per-CPU counters, backward compatibilty for names.
381 * Hidden from help listing.
382 */
383 PERF_HW("perf:cpu-cycles", CPU_CYCLES,
384 CONTEXT_PERF_COUNTER, 1),
385 PERF_HW("perf:cycles", CPU_CYCLES,
386 CONTEXT_PERF_COUNTER, 1),
387 PERF_HW("perf:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
388 CONTEXT_PERF_COUNTER, 1),
389 PERF_HW("perf:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
390 CONTEXT_PERF_COUNTER, 1),
391 PERF_HW("perf:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
392 CONTEXT_PERF_COUNTER, 1),
393 PERF_HW("perf:idle-cycles-backend", STALLED_CYCLES_BACKEND,
394 CONTEXT_PERF_COUNTER, 1),
395 PERF_HW("perf:instructions", INSTRUCTIONS,
396 CONTEXT_PERF_COUNTER, 1),
397 PERF_HW("perf:cache-references", CACHE_REFERENCES,
398 CONTEXT_PERF_COUNTER, 1),
399 PERF_HW("perf:cache-misses", CACHE_MISSES,
400 CONTEXT_PERF_COUNTER, 1),
401 PERF_HW("perf:branch-instructions", BRANCH_INSTRUCTIONS,
402 CONTEXT_PERF_COUNTER, 1),
403 PERF_HW("perf:branches", BRANCH_INSTRUCTIONS,
404 CONTEXT_PERF_COUNTER, 1),
405 PERF_HW("perf:branch-misses", BRANCH_MISSES,
406 CONTEXT_PERF_COUNTER, 1),
407 PERF_HW("perf:bus-cycles", BUS_CYCLES,
408 CONTEXT_PERF_COUNTER, 1),
409
410 PERF_HW_CACHE("perf:L1-dcache", L1D,
411 CONTEXT_PERF_COUNTER, 1),
412 PERF_HW_CACHE("perf:L1-icache", L1I,
413 CONTEXT_PERF_COUNTER, 1),
414 PERF_HW_CACHE("perf:LLC", LL,
415 CONTEXT_PERF_COUNTER, 1),
416 PERF_HW_CACHE("perf:dTLB", DTLB,
417 CONTEXT_PERF_COUNTER, 1),
418 _PERF_HW_CACHE("perf:iTLB-loads", ITLB,
419 CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
420 _PERF_HW_CACHE("perf:iTLB-load-misses", ITLB,
421 CONTEXT_PERF_COUNTER, READ, MISS, 1),
422 _PERF_HW_CACHE("perf:branch-loads", BPU,
423 CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
424 _PERF_HW_CACHE("perf:branch-load-misses", BPU,
425 CONTEXT_PERF_COUNTER, READ, MISS, 1),
426
427 PERF_SW("perf:cpu-clock", CPU_CLOCK,
428 CONTEXT_PERF_COUNTER, 1),
429 PERF_SW("perf:task-clock", TASK_CLOCK,
430 CONTEXT_PERF_COUNTER, 1),
431 PERF_SW("perf:page-fault", PAGE_FAULTS,
432 CONTEXT_PERF_COUNTER, 1),
433 PERF_SW("perf:faults", PAGE_FAULTS,
434 CONTEXT_PERF_COUNTER, 1),
435 PERF_SW("perf:major-faults", PAGE_FAULTS_MAJ,
436 CONTEXT_PERF_COUNTER, 1),
437 PERF_SW("perf:minor-faults", PAGE_FAULTS_MIN,
438 CONTEXT_PERF_COUNTER, 1),
439 PERF_SW("perf:context-switches", CONTEXT_SWITCHES,
440 CONTEXT_PERF_COUNTER, 1),
441 PERF_SW("perf:cs", CONTEXT_SWITCHES,
442 CONTEXT_PERF_COUNTER, 1),
443 PERF_SW("perf:cpu-migrations", CPU_MIGRATIONS,
444 CONTEXT_PERF_COUNTER, 1),
445 PERF_SW("perf:migrations", CPU_MIGRATIONS,
446 CONTEXT_PERF_COUNTER, 1),
447 PERF_SW("perf:alignment-faults", ALIGNMENT_FAULTS,
448 CONTEXT_PERF_COUNTER, 1),
449 PERF_SW("perf:emulation-faults", EMULATION_FAULTS,
450 CONTEXT_PERF_COUNTER, 1),
451
452 { NULL, -1 }, /* Closure */
453 };
454
455 #undef PERF_HW_CACHE
456 #undef _PERF_HW_CACHE
457 #undef PERF_SW
458 #undef PERF_HW
459
460 /*
461 * Context type for command line option parsing.
462 */
463 struct ctx_type {
464 struct ctx_opts *opt;
465 struct cds_list_head list;
466 };
467
468 /*
469 * List of context type. Use to enable multiple context on a single command
470 * line entry.
471 */
472 struct ctx_type_list {
473 struct cds_list_head head;
474 } ctx_type_list = {
475 .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
476 };
477
478 /*
479 * Pretty print context type.
480 */
481 static void print_ctx_type(FILE *ofp)
482 {
483 int i = 0;
484
485 while (ctx_opts[i].symbol != NULL) {
486 if (!ctx_opts[i].hide_help) {
487 fprintf(ofp, "%s\n", ctx_opts[i].symbol);
488 }
489 i++;
490 }
491 }
492
493 /*
494 * usage
495 */
496 static void usage(FILE *ofp)
497 {
498 fprintf(ofp, "usage: lttng add-context -t TYPE [-k|-u] [OPTIONS]\n");
499 fprintf(ofp, "\n");
500 fprintf(ofp, "If no channel is given (-c), the context is added to\n");
501 fprintf(ofp, "all channels.\n");
502 fprintf(ofp, "\n");
503 fprintf(ofp, "Otherwise the context is added only to the channel (-c).\n");
504 fprintf(ofp, "\n");
505 fprintf(ofp, "Exactly one domain (-k or -u) must be specified.\n");
506 fprintf(ofp, "\n");
507 fprintf(ofp, "Options:\n");
508 fprintf(ofp, " -h, --help Show this help\n");
509 fprintf(ofp, " --list-options Simple listing of options\n");
510 fprintf(ofp, " -s, --session NAME Apply to session name\n");
511 fprintf(ofp, " -c, --channel NAME Apply to channel\n");
512 fprintf(ofp, " -k, --kernel Apply to the kernel tracer\n");
513 fprintf(ofp, " -u, --userspace Apply to the user-space tracer\n");
514 fprintf(ofp, " -j, --jul Apply to Java application using JUL\n");
515 fprintf(ofp, " -l, --log4j Apply for Java application using LOG4j\n");
516 fprintf(ofp, "\n");
517 fprintf(ofp, "Context:\n");
518 fprintf(ofp, " -t, --type TYPE Context type. You can repeat that option on\n");
519 fprintf(ofp, " the command line to specify multiple contexts at once.\n");
520 fprintf(ofp, " (--kernel preempts --userspace)\n");
521 fprintf(ofp, " TYPE can be one of the strings below:\n");
522 print_ctx_type(ofp);
523 fprintf(ofp, "\n");
524 fprintf(ofp, "Note that the vpid, vppid and vtid context types represent the virtual process id,\n"
525 "virtual parent process id and virtual thread id as seen from the current execution context\n"
526 "as opposed to the pid, ppid and tid which are kernel internal data structures.\n\n");
527 fprintf(ofp, "Example:\n");
528 fprintf(ofp, "This command will add the context information 'prio' and two per-cpu\n"
529 "perf counters (hardware branch misses and cache misses), to all channels\n"
530 "in the trace data output:\n");
531 fprintf(ofp, "# lttng add-context -k -t prio -t perf:cpu:branch-misses -t perf:cpu:cache-misses\n");
532 fprintf(ofp, "\n");
533 }
534
535 /*
536 * Find context numerical value from string.
537 *
538 * Return -1 if not found.
539 */
540 static int find_ctx_type_idx(const char *opt)
541 {
542 int ret, i = 0;
543
544 while (ctx_opts[i].symbol != NULL) {
545 if (strcmp(opt, ctx_opts[i].symbol) == 0) {
546 ret = i;
547 goto end;
548 }
549 i++;
550 }
551
552 ret = -1;
553 end:
554 return ret;
555 }
556
557 static
558 enum lttng_domain_type get_domain(void)
559 {
560 if (opt_kernel) {
561 return LTTNG_DOMAIN_KERNEL;
562 } else if (opt_userspace) {
563 return LTTNG_DOMAIN_UST;
564 } else if (opt_jul) {
565 return LTTNG_DOMAIN_JUL;
566 } else if (opt_log4j) {
567 return LTTNG_DOMAIN_LOG4J;
568 } else {
569 assert(0);
570 }
571 }
572
573 /*
574 * Add context to channel or event.
575 */
576 static int add_context(char *session_name)
577 {
578 int ret = CMD_SUCCESS, warn = 0, success = 0;
579 struct lttng_event_context context;
580 struct lttng_domain dom;
581 struct ctx_type *type;
582 char *ptr;
583
584 memset(&context, 0, sizeof(context));
585 memset(&dom, 0, sizeof(dom));
586
587 dom.type = get_domain();
588 handle = lttng_create_handle(session_name, &dom);
589 if (handle == NULL) {
590 ret = CMD_ERROR;
591 goto error;
592 }
593
594 if (lttng_opt_mi) {
595 /* Open a contexts element */
596 ret = mi_lttng_writer_open_element(writer, config_element_contexts);
597 if (ret) {
598 goto error;
599 }
600 }
601
602 /* Iterate over all the context types given */
603 cds_list_for_each_entry(type, &ctx_type_list.head, list) {
604 context.ctx = (enum lttng_event_context_type) type->opt->ctx_type;
605 switch (context.ctx) {
606 case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
607 case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
608 case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
609 context.u.perf_counter.type = type->opt->u.perf.type;
610 context.u.perf_counter.config = type->opt->u.perf.config;
611 strncpy(context.u.perf_counter.name, type->opt->symbol,
612 LTTNG_SYMBOL_NAME_LEN);
613 context.u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
614 /* Replace : and - by _ */
615 while ((ptr = strchr(context.u.perf_counter.name, '-')) != NULL) {
616 *ptr = '_';
617 }
618 while ((ptr = strchr(context.u.perf_counter.name, ':')) != NULL) {
619 *ptr = '_';
620 }
621 break;
622 case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
623 context.u.app_ctx.provider_name =
624 type->opt->u.app_ctx.provider_name;
625 context.u.app_ctx.ctx_name =
626 type->opt->u.app_ctx.ctx_name;
627 break;
628 default:
629 break;
630 }
631 DBG("Adding context...");
632
633 if (lttng_opt_mi) {
634 /* We leave context open the update the success of the command */
635 ret = mi_lttng_context(writer, &context, 1);
636 if (ret) {
637 ret = CMD_ERROR;
638 goto error;
639 }
640 }
641
642 ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
643 if (ret < 0) {
644 ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
645 warn = 1;
646 success = 0;
647 } else {
648 if (opt_channel_name) {
649 MSG("%s context %s added to channel %s",
650 opt_kernel ? "kernel" : "UST", type->opt->symbol,
651 opt_channel_name);
652 } else {
653 MSG("%s context %s added to all channels",
654 opt_kernel ? "kernel" : "UST", type->opt->symbol)
655 }
656 success = 1;
657 }
658
659 if (lttng_opt_mi) {
660 /* Is the single operation a success ? */
661 ret = mi_lttng_writer_write_element_bool(writer,
662 mi_lttng_element_success, success);
663 if (ret) {
664 ret = CMD_ERROR;
665 goto error;
666 }
667
668 /* Close the context element */
669 ret = mi_lttng_writer_close_element(writer);
670 if (ret) {
671 ret = CMD_ERROR;
672 goto error;
673 }
674 }
675 }
676
677 if (lttng_opt_mi) {
678 /* Close contexts element */
679 ret = mi_lttng_writer_close_element(writer);
680 if (ret) {
681 goto error;
682 }
683 }
684
685 ret = CMD_SUCCESS;
686
687 error:
688 lttng_destroy_handle(handle);
689
690 /*
691 * This means that at least one add_context failed and tells the user to
692 * look on stderr for error(s).
693 */
694 if (!ret && warn) {
695 ret = CMD_WARNING;
696 }
697 return ret;
698 }
699
700 static
701 void destroy_ctx_type(struct ctx_type *type)
702 {
703 if (!type) {
704 return;
705 }
706 free(type->opt->symbol);
707 free(type->opt);
708 free(type);
709 }
710
711 static
712 struct ctx_type *create_ctx_type(void)
713 {
714 struct ctx_type *type = zmalloc(sizeof(*type));
715
716 if (!type) {
717 PERROR("malloc ctx_type");
718 goto end;
719 }
720
721 type->opt = zmalloc(sizeof(*type->opt));
722 if (!type->opt) {
723 PERROR("malloc ctx_type options");
724 destroy_ctx_type(type);
725 type = NULL;
726 goto end;
727 }
728 end:
729 return type;
730 }
731
732 static
733 struct ctx_type *get_context_type(const char *ctx)
734 {
735 int opt_index;
736 struct ctx_type *type = NULL;
737 const char app_ctx_prefix[] = "$app.";
738 char *provider_name = NULL, *ctx_name = NULL;
739 size_t i, len, colon_pos = 0, provider_name_len, ctx_name_len;
740
741 if (!ctx) {
742 goto not_found;
743 }
744
745 type = create_ctx_type();
746 if (!type) {
747 goto not_found;
748 }
749
750 /* Check if ctx matches a known static context. */
751 opt_index = find_ctx_type_idx(ctx);
752 if (opt_index >= 0) {
753 *type->opt = ctx_opts[opt_index];
754 type->opt->symbol = strdup(ctx_opts[opt_index].symbol);
755 goto found;
756 }
757
758 /*
759 * No match found against static contexts; check if it is an app
760 * context.
761 */
762 len = strlen(ctx);
763 if (len <= sizeof(app_ctx_prefix) - 1) {
764 goto not_found;
765 }
766
767 /* String starts with $app. */
768 if (strncmp(ctx, app_ctx_prefix, sizeof(app_ctx_prefix) - 1)) {
769 goto not_found;
770 }
771
772 /* Validate that the ':' separator is present. */
773 for (i = sizeof(app_ctx_prefix); i < len; i++) {
774 const char c = ctx[i];
775
776 if (c == ':') {
777 colon_pos = i;
778 break;
779 }
780 }
781
782 /*
783 * No colon found or no ctx name ("$app.provider:") or no provider name
784 * given ("$app.:..."), which is invalid.
785 */
786 if (!colon_pos || colon_pos == len ||
787 colon_pos == sizeof(app_ctx_prefix)) {
788 ERR("Invalid application context provided: no provider or context name provided.");
789 goto not_found;
790 }
791
792 provider_name_len = colon_pos - sizeof(app_ctx_prefix) + 2;
793 provider_name = zmalloc(provider_name_len);
794 if (!provider_name) {
795 PERROR("malloc provider_name");
796 goto not_found;
797 }
798 strncpy(provider_name, ctx + sizeof(app_ctx_prefix) - 1,
799 provider_name_len - 1);
800 type->opt->u.app_ctx.provider_name = provider_name;
801
802 ctx_name_len = len - colon_pos;
803 ctx_name = zmalloc(ctx_name_len);
804 if (!ctx_name) {
805 PERROR("malloc ctx_name");
806 goto not_found;
807 }
808 strncpy(ctx_name, ctx + colon_pos + 1, ctx_name_len - 1);
809 type->opt->u.app_ctx.ctx_name = ctx_name;
810 type->opt->ctx_type = CONTEXT_APP_CONTEXT;
811 type->opt->symbol = strdup(ctx);
812 found:
813 return type;
814 not_found:
815 free(provider_name);
816 free(ctx_name);
817 destroy_ctx_type(type);
818 return NULL;
819 }
820
821 /*
822 * Add context to channel or event.
823 */
824 int cmd_add_context(int argc, const char **argv)
825 {
826 int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
827 int success = 1;
828 static poptContext pc;
829 struct ctx_type *type, *tmptype;
830 char *session_name = NULL;
831
832 if (argc < 2) {
833 usage(stderr);
834 ret = CMD_ERROR;
835 goto end;
836 }
837
838 pc = poptGetContext(NULL, argc, argv, long_options, 0);
839 poptReadDefaultConfig(pc, 0);
840
841 while ((opt = poptGetNextOpt(pc)) != -1) {
842 switch (opt) {
843 case OPT_HELP:
844 SHOW_HELP();
845 goto end;
846 case OPT_LIST:
847 print_ctx_type(stdout);
848 goto end;
849 case OPT_TYPE:
850 {
851 type = get_context_type(opt_type);
852 if (!type) {
853 ERR("Unknown context type %s", opt_type);
854 ret = CMD_FATAL;
855 goto end;
856 }
857 cds_list_add_tail(&type->list, &ctx_type_list.head);
858 break;
859 }
860 case OPT_USERSPACE:
861 opt_userspace = 1;
862 break;
863 case OPT_JUL:
864 opt_jul = 1;
865 break;
866 case OPT_LOG4J:
867 opt_log4j = 1;
868 break;
869 case OPT_LIST_OPTIONS:
870 list_cmd_options(stdout, long_options);
871 goto end;
872 default:
873 usage(stderr);
874 ret = CMD_UNDEFINED;
875 goto end;
876 }
877 }
878
879 ret = print_missing_or_multiple_domains(opt_kernel + opt_userspace +
880 opt_jul + opt_log4j);
881 if (ret) {
882 ret = CMD_ERROR;
883 goto end;
884 }
885
886 if (!opt_type) {
887 ERR("Missing mandatory -t TYPE");
888 usage(stderr);
889 ret = CMD_ERROR;
890 goto end;
891 }
892
893 if (!opt_session_name) {
894 session_name = get_session_name();
895 if (session_name == NULL) {
896 ret = CMD_ERROR;
897 goto end;
898 }
899 } else {
900 session_name = opt_session_name;
901 }
902
903 /* Mi check */
904 if (lttng_opt_mi) {
905 writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
906 if (!writer) {
907 ret = -LTTNG_ERR_NOMEM;
908 goto end;
909 }
910
911 /* Open command element */
912 ret = mi_lttng_writer_command_open(writer,
913 mi_lttng_element_command_add_context);
914 if (ret) {
915 ret = CMD_ERROR;
916 goto end;
917 }
918
919 /* Open output element */
920 ret = mi_lttng_writer_open_element(writer,
921 mi_lttng_element_command_output);
922 if (ret) {
923 ret = CMD_ERROR;
924 goto end;
925 }
926 }
927
928 command_ret = add_context(session_name);
929 if (command_ret) {
930 success = 0;
931 }
932
933 /* Mi closing */
934 if (lttng_opt_mi) {
935 /* Close output element */
936 ret = mi_lttng_writer_close_element(writer);
937 if (ret) {
938 ret = CMD_ERROR;
939 goto end;
940 }
941
942 /* Success ? */
943 ret = mi_lttng_writer_write_element_bool(writer,
944 mi_lttng_element_command_success, success);
945 if (ret) {
946 ret = CMD_ERROR;
947 goto end;
948 }
949
950 /* Command element close */
951 ret = mi_lttng_writer_command_close(writer);
952 if (ret) {
953 ret = CMD_ERROR;
954 goto end;
955 }
956 }
957
958 end:
959 if (!opt_session_name) {
960 free(session_name);
961 }
962
963 /* Mi clean-up */
964 if (writer && mi_lttng_writer_destroy(writer)) {
965 /* Preserve original error code */
966 ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
967 }
968
969 /* Cleanup allocated memory */
970 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
971 destroy_ctx_type(type);
972 }
973
974 /* Overwrite ret if an error occurred during add_context() */
975 ret = command_ret ? command_ret : ret;
976
977 poptFreeContext(pc);
978 return ret;
979 }
This page took 0.048749 seconds and 5 git commands to generate.