Standardize lttng command line usage text
[lttng-tools.git] / src / bin / lttng / commands / add_context.c
CommitLineData
d65106b1
DG
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
d14d33bf
AM
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.
d65106b1
DG
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 *
d14d33bf
AM
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.
d65106b1
DG
16 */
17
18#define _GNU_SOURCE
90b9a268 19#include <ctype.h>
d65106b1
DG
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
3301e740
DG
28#include <urcu/list.h>
29
c399183f 30#include "../command.h"
d65106b1 31
b13d56d7
MD
32#define PRINT_LINE_LEN 80
33
d65106b1
DG
34static char *opt_event_name;
35static char *opt_channel_name;
5440dc42 36static char *opt_session_name;
55cc08a6 37static int opt_kernel;
d65106b1 38static int opt_userspace;
d78d6610
DG
39static char *opt_type;
40#if 0
41/* Not implemented yet */
eeac7d46 42static char *opt_cmd_name;
d65106b1 43static pid_t opt_pid;
d78d6610 44#endif
d65106b1
DG
45
46enum {
47 OPT_HELP = 1,
48 OPT_TYPE,
eeac7d46 49 OPT_USERSPACE,
679b4943 50 OPT_LIST_OPTIONS,
d65106b1
DG
51};
52
cd80958d
DG
53static struct lttng_handle *handle;
54
90b9a268
DG
55/*
56 * Taken from the LTTng ABI
57 */
58enum context_type {
59 CONTEXT_PID = 0,
60 CONTEXT_PERF_COUNTER = 1,
95da1297 61 CONTEXT_PROCNAME = 2,
90b9a268
DG
62 CONTEXT_PRIO = 3,
63 CONTEXT_NICE = 4,
64 CONTEXT_VPID = 5,
65 CONTEXT_TID = 6,
66 CONTEXT_VTID = 7,
67 CONTEXT_PPID = 8,
68 CONTEXT_VPPID = 9,
9197c5c4 69 CONTEXT_PTHREAD_ID = 10,
3301e740
DG
70};
71
90b9a268
DG
72/*
73 * Taken from the Perf ABI (all enum perf_*)
74 */
75enum perf_type {
76 PERF_TYPE_HARDWARE = 0,
77 PERF_TYPE_SOFTWARE = 1,
b13d56d7 78 PERF_TYPE_HW_CACHE = 3,
3301e740
DG
79};
80
90b9a268 81enum perf_count_hard {
b13d56d7
MD
82 PERF_COUNT_HW_CPU_CYCLES = 0,
83 PERF_COUNT_HW_INSTRUCTIONS = 1,
84 PERF_COUNT_HW_CACHE_REFERENCES = 2,
85 PERF_COUNT_HW_CACHE_MISSES = 3,
86 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
87 PERF_COUNT_HW_BRANCH_MISSES = 5,
88 PERF_COUNT_HW_BUS_CYCLES = 6,
89 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
90 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
90b9a268
DG
91};
92
93enum perf_count_soft {
94 PERF_COUNT_SW_CPU_CLOCK = 0,
95 PERF_COUNT_SW_TASK_CLOCK = 1,
96 PERF_COUNT_SW_PAGE_FAULTS = 2,
97 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
98 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
99 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
100 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
101 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
102 PERF_COUNT_SW_EMULATION_FAULTS = 8,
3301e740
DG
103};
104
b13d56d7
MD
105/*
106 * Generalized hardware cache events:
107 *
108 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
109 * { read, write, prefetch } x
110 * { accesses, misses }
111 */
112enum perf_hw_cache_id {
113 PERF_COUNT_HW_CACHE_L1D = 0,
114 PERF_COUNT_HW_CACHE_L1I = 1,
115 PERF_COUNT_HW_CACHE_LL = 2,
116 PERF_COUNT_HW_CACHE_DTLB = 3,
117 PERF_COUNT_HW_CACHE_ITLB = 4,
118 PERF_COUNT_HW_CACHE_BPU = 5,
119
120 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
121};
122
123enum perf_hw_cache_op_id {
124 PERF_COUNT_HW_CACHE_OP_READ = 0,
125 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
126 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
127
128 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
129};
130
131enum perf_hw_cache_op_result_id {
132 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
133 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
134
135 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
136};
137
d65106b1
DG
138static struct poptOption long_options[] = {
139 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
140 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
5440dc42 141 {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
d65106b1
DG
142 {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
143 {"event", 'e', POPT_ARG_STRING, &opt_event_name, 0, 0, 0},
144 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
d78d6610 145 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
6caa2bcc 146 {"type", 't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
679b4943 147 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
d65106b1
DG
148 {0, 0, 0, 0, 0, 0, 0}
149};
150
90b9a268 151/*
b13d56d7 152 * Context options
90b9a268 153 */
b13d56d7
MD
154#define PERF_HW(opt, name) \
155 { \
156 "perf:" #opt, CONTEXT_PERF_COUNTER, \
157 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
158 }
90b9a268 159
b13d56d7
MD
160#define PERF_SW(opt, name) \
161 { \
162 "perf:" #opt, CONTEXT_PERF_COUNTER, \
163 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
164 }
90b9a268 165
b13d56d7
MD
166#define _PERF_HW_CACHE(optstr, name, op, result) \
167 { \
168 "perf:" optstr, CONTEXT_PERF_COUNTER, \
169 .u.perf = { \
170 PERF_TYPE_HW_CACHE, \
171 (uint64_t) PERF_COUNT_HW_CACHE_##name \
18829107
MD
172 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
173 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
b13d56d7
MD
174 }, \
175 }
176
177#define PERF_HW_CACHE(opt, name) \
178 _PERF_HW_CACHE(#opt "-loads", name, READ, ACCESS), \
179 _PERF_HW_CACHE(#opt "-load-misses", name, READ, MISS), \
180 _PERF_HW_CACHE(#opt "-stores", name, WRITE, ACCESS), \
181 _PERF_HW_CACHE(#opt "-store-misses", name, WRITE, MISS), \
182 _PERF_HW_CACHE(#opt "-prefetches", name, PREFETCH, ACCESS), \
183 _PERF_HW_CACHE(#opt "-prefetch-misses", name, PREFETCH, MISS) \
184
185static
186const struct ctx_opts {
90b9a268 187 char *symbol;
b13d56d7
MD
188 enum context_type ctx_type;
189 union {
190 struct {
191 uint32_t type;
192 uint64_t config;
193 } perf;
194 } u;
195} ctx_opts[] = {
196 { "pid", CONTEXT_PID },
95da1297 197 { "procname", CONTEXT_PROCNAME },
b13d56d7
MD
198 { "prio", CONTEXT_PRIO },
199 { "nice", CONTEXT_NICE },
200 { "vpid", CONTEXT_VPID },
201 { "tid", CONTEXT_TID },
9197c5c4 202 { "pthread_id", CONTEXT_PTHREAD_ID },
b13d56d7
MD
203 { "vtid", CONTEXT_VTID },
204 { "ppid", CONTEXT_PPID },
205 { "vppid", CONTEXT_VPPID },
206 /* Perf options */
207 PERF_HW(cpu-cycles, CPU_CYCLES),
208 PERF_HW(cycles, CPU_CYCLES),
209 PERF_HW(stalled-cycles-frontend, STALLED_CYCLES_FRONTEND),
210 PERF_HW(idle-cycles-frontend, STALLED_CYCLES_FRONTEND),
211 PERF_HW(stalled-cycles-backend, STALLED_CYCLES_BACKEND),
212 PERF_HW(idle-cycles-backend, STALLED_CYCLES_BACKEND),
213 PERF_HW(instructions, INSTRUCTIONS),
214 PERF_HW(cache-references, CACHE_REFERENCES),
215 PERF_HW(cache-misses, CACHE_MISSES),
216 PERF_HW(branch-instructions, BRANCH_INSTRUCTIONS),
217 PERF_HW(branches, BRANCH_INSTRUCTIONS),
218 PERF_HW(branch-misses, BRANCH_MISSES),
219 PERF_HW(bus-cycles, BUS_CYCLES),
220
221 PERF_HW_CACHE(L1-dcache, L1D),
222 PERF_HW_CACHE(L1-icache, L1I),
223 PERF_HW_CACHE(LLC, LL),
224 PERF_HW_CACHE(dTLB, DTLB),
225 _PERF_HW_CACHE("iTLB-loads", ITLB, READ, ACCESS),
226 _PERF_HW_CACHE("iTLB-load-misses", ITLB, READ, MISS),
227 _PERF_HW_CACHE("branch-loads", BPU, READ, ACCESS),
228 _PERF_HW_CACHE("branch-load-misses", BPU, READ, MISS),
229
230
231 PERF_SW(cpu-clock, CPU_CLOCK),
232 PERF_SW(task-clock, TASK_CLOCK),
233 PERF_SW(page-fault, PAGE_FAULTS),
234 PERF_SW(faults, PAGE_FAULTS),
235 PERF_SW(major-faults, PAGE_FAULTS_MAJ),
236 PERF_SW(minor-faults, PAGE_FAULTS_MIN),
237 PERF_SW(context-switches, CONTEXT_SWITCHES),
238 PERF_SW(cs, CONTEXT_SWITCHES),
239 PERF_SW(cpu-migrations, CPU_MIGRATIONS),
240 PERF_SW(migrations, CPU_MIGRATIONS),
241 PERF_SW(alignment-faults, ALIGNMENT_FAULTS),
242 PERF_SW(emulation-faults, EMULATION_FAULTS),
243 { NULL, -1 }, /* Closure */
90b9a268
DG
244};
245
b13d56d7
MD
246#undef PERF_SW
247#undef PERF_HW
248
90b9a268 249/*
b13d56d7 250 * Context type for command line option parsing.
90b9a268 251 */
b13d56d7
MD
252struct ctx_type {
253 const struct ctx_opts *opt;
254 struct cds_list_head list;
90b9a268
DG
255};
256
257/*
258 * List of context type. Use to enable multiple context on a single command
259 * line entry.
260 */
261struct ctx_type_list {
262 struct cds_list_head head;
263} ctx_type_list = {
264 .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
265};
266
90b9a268
DG
267/*
268 * Pretty print context type.
269 */
270static void print_ctx_type(FILE *ofp)
271{
b13d56d7
MD
272 const char *indent = " ";
273 int indent_len = strlen(indent);
274 int len, i = 0;
90b9a268 275
76e3c5dd 276 fprintf(ofp, "%s", indent);
b13d56d7 277 len = indent_len;
90b9a268 278 while (ctx_opts[i].symbol != NULL) {
b13d56d7
MD
279 if (len > indent_len) {
280 if (len + strlen(ctx_opts[i].symbol) + 2
281 >= PRINT_LINE_LEN) {
282 fprintf(ofp, ",\n");
76e3c5dd 283 fprintf(ofp, "%s", indent);
b13d56d7
MD
284 len = indent_len;
285 } else {
286 len += fprintf(ofp, ", ");
90b9a268
DG
287 }
288 }
b13d56d7 289 len += fprintf(ofp, "%s", ctx_opts[i].symbol);
90b9a268
DG
290 i++;
291 }
90b9a268
DG
292}
293
d65106b1
DG
294/*
295 * usage
296 */
297static void usage(FILE *ofp)
298{
32a6298d 299 fprintf(ofp, "usage: lttng add-context -t TYPE [-k|-u] [OPTIONS]\n");
d65106b1 300 fprintf(ofp, "\n");
b13d56d7 301 fprintf(ofp, "If no channel and no event is given (-c/-e), the context\n");
32a6298d
DG
302 fprintf(ofp, "is added to all events and all channels.\n");
303 fprintf(ofp, "\n");
304 fprintf(ofp, "Otherwise the context is added only to the channel (-c)\n");
af87c45a 305 fprintf(ofp, "and/or event (-e) indicated.\n");
32a6298d
DG
306 fprintf(ofp, "\n");
307 fprintf(ofp, "Exactly one domain (-k or -u) must be specified.\n");
3301e740 308 fprintf(ofp, "\n");
d65106b1
DG
309 fprintf(ofp, "Options:\n");
310 fprintf(ofp, " -h, --help Show this help\n");
679b4943 311 fprintf(ofp, " --list-options Simple listing of options\n");
5eb00805
TD
312 fprintf(ofp, " -s, --session NAME Apply to session name\n");
313 fprintf(ofp, " -c, --channel NAME Apply to channel\n");
314 fprintf(ofp, " -e, --event NAME Apply to event\n");
af87c45a 315 fprintf(ofp, " -k, --kernel Apply to the kernel tracer\n");
af87c45a 316 fprintf(ofp, " -u, --userspace Apply to the user-space tracer\n");
32a6298d
DG
317 fprintf(ofp, "\n");
318 fprintf(ofp, "Context:\n");
b13d56d7 319 fprintf(ofp, " -t, --type TYPE Context type. You can repeat that option on\n");
af87c45a
DG
320 fprintf(ofp, " the command line to specify multiple contexts at once.\n");
321 fprintf(ofp, " (--kernel preempts --userspace)\n");
b13d56d7 322 fprintf(ofp, " TYPE can be one of the strings below:\n");
90b9a268 323 print_ctx_type(ofp);
d65106b1 324 fprintf(ofp, "\n");
90b9a268 325 fprintf(ofp, "Example:\n");
b13d56d7 326 fprintf(ofp, "This command will add the context information 'prio' and two perf\n"
af87c45a 327 "counters (hardware branch misses and cache misses), to all events\n"
b13d56d7
MD
328 "in the trace data output:\n");
329 fprintf(ofp, "# lttng add-context -k -t prio -t perf:branch-misses -t perf:cache-misses\n");
d65106b1
DG
330 fprintf(ofp, "\n");
331}
332
90b9a268
DG
333/*
334 * Find context numerical value from string.
335 */
336static int find_ctx_type_idx(const char *opt)
337{
338 int ret = -1, i = 0;
339
340 while (ctx_opts[i].symbol != NULL) {
341 if (strcmp(opt, ctx_opts[i].symbol) == 0) {
342 ret = i;
343 goto end;
344 }
345 i++;
346 }
347
348end:
349 return ret;
350}
351
90b9a268
DG
352/*
353 * Add context to channel or event.
d65106b1 354 */
cd80958d 355static int add_context(char *session_name)
d65106b1 356{
d16c1a4c 357 int ret = CMD_SUCCESS, warn = 0;
7d29a247
DG
358 struct lttng_event_context context;
359 struct lttng_domain dom;
3301e740 360 struct ctx_type *type;
b13d56d7 361 char *ptr;
d65106b1 362
441c16a7
MD
363 memset(&context, 0, sizeof(context));
364 memset(&dom, 0, sizeof(dom));
365
cd80958d
DG
366 if (opt_kernel) {
367 dom.type = LTTNG_DOMAIN_KERNEL;
d78d6610 368 } else if (opt_userspace) {
55cc08a6 369 dom.type = LTTNG_DOMAIN_UST;
55cc08a6 370 } else {
e14f64a8 371 ERR("Please specify a tracer (-k/--kernel or -u/--userspace)");
d16c1a4c 372 ret = CMD_ERROR;
55cc08a6 373 goto error;
cd80958d
DG
374 }
375
376 handle = lttng_create_handle(session_name, &dom);
377 if (handle == NULL) {
af87c45a 378 ret = CMD_ERROR;
cd80958d
DG
379 goto error;
380 }
381
5eb00805 382 /* Iterate over all the context types given */
3301e740 383 cds_list_for_each_entry(type, &ctx_type_list.head, list) {
6775595e 384 context.ctx = (enum lttng_event_context_type) type->opt->ctx_type;
b13d56d7
MD
385 if (context.ctx == LTTNG_EVENT_CONTEXT_PERF_COUNTER) {
386 context.u.perf_counter.type = type->opt->u.perf.type;
387 context.u.perf_counter.config = type->opt->u.perf.config;
d7b91b3c 388 strcpy(context.u.perf_counter.name, type->opt->symbol);
b13d56d7
MD
389 /* Replace : and - by _ */
390 while ((ptr = strchr(context.u.perf_counter.name, '-')) != NULL) {
391 *ptr = '_';
3301e740 392 }
b13d56d7
MD
393 while ((ptr = strchr(context.u.perf_counter.name, ':')) != NULL) {
394 *ptr = '_';
3301e740 395 }
3301e740 396 }
55cc08a6
DG
397 DBG("Adding context...");
398
399 ret = lttng_add_context(handle, &context, opt_event_name,
400 opt_channel_name);
401 if (ret < 0) {
b58471ff 402 ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
d16c1a4c 403 warn = 1;
55cc08a6 404 continue;
d65106b1 405 } else {
b58471ff
DG
406 if (opt_channel_name && opt_event_name) {
407 MSG("%s context %s added to event %s channel %s",
408 opt_kernel ? "kernel" : "UST", type->opt->symbol,
409 opt_channel_name, opt_event_name);
410 } else if (opt_channel_name && !opt_event_name) {
411 MSG("%s context %s added to channel %s",
412 opt_kernel ? "kernel" : "UST", type->opt->symbol,
413 opt_channel_name);
414 } else if (!opt_channel_name && opt_event_name) {
415 MSG("%s context %s added to event %s",
416 opt_kernel ? "kernel" : "UST", type->opt->symbol,
417 opt_event_name);
418 } else {
419 MSG("%s context %s added to all channels",
420 opt_kernel ? "kernel" : "UST", type->opt->symbol)
421 }
d65106b1 422 }
d65106b1
DG
423 }
424
af87c45a
DG
425 ret = CMD_SUCCESS;
426
d65106b1 427error:
cd80958d
DG
428 lttng_destroy_handle(handle);
429
d16c1a4c
DG
430 /*
431 * This means that at least one add_context failed and tells the user to
432 * look on stderr for error(s).
433 */
434 if (warn) {
435 ret = CMD_WARNING;
436 }
d65106b1
DG
437 return ret;
438}
439
440/*
5eb00805 441 * Add context to channel or event.
d65106b1
DG
442 */
443int cmd_add_context(int argc, const char **argv)
444{
90b9a268 445 int index, opt, ret = CMD_SUCCESS;
d65106b1 446 static poptContext pc;
b13d56d7 447 struct ctx_type *type, *tmptype;
cd80958d 448 char *session_name = NULL;
d65106b1 449
636167b6
DG
450 if (argc < 2) {
451 usage(stderr);
5eb00805 452 ret = CMD_ERROR;
636167b6
DG
453 goto end;
454 }
455
d65106b1
DG
456 pc = poptGetContext(NULL, argc, argv, long_options, 0);
457 poptReadDefaultConfig(pc, 0);
458
459 while ((opt = poptGetNextOpt(pc)) != -1) {
460 switch (opt) {
461 case OPT_HELP:
5eb00805 462 usage(stdout);
d65106b1
DG
463 goto end;
464 case OPT_TYPE:
af87c45a
DG
465 /*
466 * Look up the index of opt_type in ctx_opts[] first, so we don't
467 * have to free(type) on failure.
468 */
6caa2bcc 469 index = find_ctx_type_idx(opt_type);
b13d56d7 470 if (index < 0) {
6caa2bcc 471 ERR("Unknown context type %s", opt_type);
5eb00805 472 ret = CMD_ERROR;
b13d56d7 473 goto end;
90b9a268 474 }
5eb00805
TD
475
476 type = malloc(sizeof(struct ctx_type));
477 if (type == NULL) {
478 perror("malloc ctx_type");
479 ret = CMD_FATAL;
480 goto end;
481 }
482
b13d56d7
MD
483 type->opt = &ctx_opts[index];
484 if (type->opt->ctx_type == -1) {
6caa2bcc 485 ERR("Unknown context type %s", opt_type);
5eb00805
TD
486 free(type);
487 ret = CMD_ERROR;
488 goto end;
90b9a268
DG
489 } else {
490 cds_list_add(&type->list, &ctx_type_list.head);
491 }
d65106b1 492 break;
eeac7d46
MD
493 case OPT_USERSPACE:
494 opt_userspace = 1;
d78d6610 495#if 0
eeac7d46 496 opt_cmd_name = poptGetOptArg(pc);
d78d6610 497#endif
eeac7d46 498 break;
679b4943
SM
499 case OPT_LIST_OPTIONS:
500 list_cmd_options(stdout, long_options);
679b4943 501 goto end;
d65106b1
DG
502 default:
503 usage(stderr);
504 ret = CMD_UNDEFINED;
505 goto end;
506 }
507 }
508
ae856491
DG
509 if (!opt_type) {
510 ERR("Missing mandatory -t TYPE");
511 usage(stderr);
512 ret = CMD_ERROR;
513 goto end;
514 }
515
cd80958d
DG
516 if (!opt_session_name) {
517 session_name = get_session_name();
518 if (session_name == NULL) {
5eb00805 519 ret = CMD_ERROR;
cd80958d
DG
520 goto end;
521 }
522 } else {
523 session_name = opt_session_name;
524 }
525
526 ret = add_context(session_name);
3301e740 527
1256f150
DT
528 if (!opt_session_name) {
529 free(session_name);
530 }
531
5eb00805 532end:
3301e740 533 /* Cleanup allocated memory */
b13d56d7 534 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
3301e740
DG
535 free(type);
536 }
537
ca1c3607 538 poptFreeContext(pc);
d65106b1
DG
539 return ret;
540}
This page took 0.0543 seconds and 4 git commands to generate.