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