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