Update version to v2.2.0-rc2
[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 34static char *opt_channel_name;
5440dc42 35static char *opt_session_name;
55cc08a6 36static int opt_kernel;
d65106b1 37static int opt_userspace;
d78d6610
DG
38static char *opt_type;
39#if 0
40/* Not implemented yet */
eeac7d46 41static char *opt_cmd_name;
d65106b1 42static pid_t opt_pid;
d78d6610 43#endif
d65106b1
DG
44
45enum {
46 OPT_HELP = 1,
47 OPT_TYPE,
eeac7d46 48 OPT_USERSPACE,
679b4943 49 OPT_LIST_OPTIONS,
d65106b1
DG
50};
51
cd80958d
DG
52static struct lttng_handle *handle;
53
90b9a268
DG
54/*
55 * Taken from the LTTng ABI
56 */
57enum context_type {
58 CONTEXT_PID = 0,
59 CONTEXT_PERF_COUNTER = 1,
95da1297 60 CONTEXT_PROCNAME = 2,
90b9a268
DG
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,
9197c5c4 68 CONTEXT_PTHREAD_ID = 10,
54773d68 69 CONTEXT_HOSTNAME = 11,
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 142 {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
d65106b1 143 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
d78d6610 144 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
6caa2bcc 145 {"type", 't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
679b4943 146 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
d65106b1
DG
147 {0, 0, 0, 0, 0, 0, 0}
148};
149
90b9a268 150/*
b13d56d7 151 * Context options
90b9a268 152 */
b13d56d7
MD
153#define PERF_HW(opt, name) \
154 { \
155 "perf:" #opt, CONTEXT_PERF_COUNTER, \
156 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
157 }
90b9a268 158
b13d56d7
MD
159#define PERF_SW(opt, name) \
160 { \
161 "perf:" #opt, CONTEXT_PERF_COUNTER, \
162 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
163 }
90b9a268 164
b13d56d7
MD
165#define _PERF_HW_CACHE(optstr, name, op, result) \
166 { \
167 "perf:" optstr, CONTEXT_PERF_COUNTER, \
168 .u.perf = { \
169 PERF_TYPE_HW_CACHE, \
170 (uint64_t) PERF_COUNT_HW_CACHE_##name \
18829107
MD
171 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
172 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
b13d56d7
MD
173 }, \
174 }
175
176#define PERF_HW_CACHE(opt, name) \
177 _PERF_HW_CACHE(#opt "-loads", name, READ, ACCESS), \
178 _PERF_HW_CACHE(#opt "-load-misses", name, READ, MISS), \
179 _PERF_HW_CACHE(#opt "-stores", name, WRITE, ACCESS), \
180 _PERF_HW_CACHE(#opt "-store-misses", name, WRITE, MISS), \
181 _PERF_HW_CACHE(#opt "-prefetches", name, PREFETCH, ACCESS), \
182 _PERF_HW_CACHE(#opt "-prefetch-misses", name, PREFETCH, MISS) \
183
184static
185const struct ctx_opts {
90b9a268 186 char *symbol;
b13d56d7
MD
187 enum context_type ctx_type;
188 union {
189 struct {
190 uint32_t type;
191 uint64_t config;
192 } perf;
193 } u;
194} ctx_opts[] = {
195 { "pid", CONTEXT_PID },
95da1297 196 { "procname", CONTEXT_PROCNAME },
b13d56d7
MD
197 { "prio", CONTEXT_PRIO },
198 { "nice", CONTEXT_NICE },
199 { "vpid", CONTEXT_VPID },
200 { "tid", CONTEXT_TID },
9197c5c4 201 { "pthread_id", CONTEXT_PTHREAD_ID },
b13d56d7
MD
202 { "vtid", CONTEXT_VTID },
203 { "ppid", CONTEXT_PPID },
204 { "vppid", CONTEXT_VPPID },
54773d68 205 { "hostname", CONTEXT_HOSTNAME },
b13d56d7
MD
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");
601d5acf
DG
301 fprintf(ofp, "If no channel is given (-c), the context is added to\n");
302 fprintf(ofp, "all channels.\n");
32a6298d 303 fprintf(ofp, "\n");
601d5acf 304 fprintf(ofp, "Otherwise the context is added only to the channel (-c).\n");
32a6298d
DG
305 fprintf(ofp, "\n");
306 fprintf(ofp, "Exactly one domain (-k or -u) must be specified.\n");
3301e740 307 fprintf(ofp, "\n");
d65106b1
DG
308 fprintf(ofp, "Options:\n");
309 fprintf(ofp, " -h, --help Show this help\n");
679b4943 310 fprintf(ofp, " --list-options Simple listing of options\n");
5eb00805
TD
311 fprintf(ofp, " -s, --session NAME Apply to session name\n");
312 fprintf(ofp, " -c, --channel NAME Apply to channel\n");
af87c45a 313 fprintf(ofp, " -k, --kernel Apply to the kernel tracer\n");
af87c45a 314 fprintf(ofp, " -u, --userspace Apply to the user-space tracer\n");
32a6298d
DG
315 fprintf(ofp, "\n");
316 fprintf(ofp, "Context:\n");
b13d56d7 317 fprintf(ofp, " -t, --type TYPE Context type. You can repeat that option on\n");
af87c45a
DG
318 fprintf(ofp, " the command line to specify multiple contexts at once.\n");
319 fprintf(ofp, " (--kernel preempts --userspace)\n");
b13d56d7 320 fprintf(ofp, " TYPE can be one of the strings below:\n");
90b9a268 321 print_ctx_type(ofp);
d65106b1 322 fprintf(ofp, "\n");
90b9a268 323 fprintf(ofp, "Example:\n");
b13d56d7 324 fprintf(ofp, "This command will add the context information 'prio' and two perf\n"
601d5acf 325 "counters (hardware branch misses and cache misses), to all channels\n"
b13d56d7
MD
326 "in the trace data output:\n");
327 fprintf(ofp, "# lttng add-context -k -t prio -t perf:branch-misses -t perf:cache-misses\n");
d65106b1
DG
328 fprintf(ofp, "\n");
329}
330
90b9a268
DG
331/*
332 * Find context numerical value from string.
333 */
334static int find_ctx_type_idx(const char *opt)
335{
336 int ret = -1, i = 0;
337
338 while (ctx_opts[i].symbol != NULL) {
339 if (strcmp(opt, ctx_opts[i].symbol) == 0) {
340 ret = i;
341 goto end;
342 }
343 i++;
344 }
345
346end:
347 return ret;
348}
349
90b9a268
DG
350/*
351 * Add context to channel or event.
d65106b1 352 */
cd80958d 353static int add_context(char *session_name)
d65106b1 354{
d16c1a4c 355 int ret = CMD_SUCCESS, warn = 0;
7d29a247
DG
356 struct lttng_event_context context;
357 struct lttng_domain dom;
3301e740 358 struct ctx_type *type;
b13d56d7 359 char *ptr;
d65106b1 360
441c16a7
MD
361 memset(&context, 0, sizeof(context));
362 memset(&dom, 0, sizeof(dom));
363
cd80958d
DG
364 if (opt_kernel) {
365 dom.type = LTTNG_DOMAIN_KERNEL;
d78d6610 366 } else if (opt_userspace) {
55cc08a6 367 dom.type = LTTNG_DOMAIN_UST;
55cc08a6 368 } else {
e14f64a8 369 ERR("Please specify a tracer (-k/--kernel or -u/--userspace)");
d16c1a4c 370 ret = CMD_ERROR;
55cc08a6 371 goto error;
cd80958d
DG
372 }
373
374 handle = lttng_create_handle(session_name, &dom);
375 if (handle == NULL) {
af87c45a 376 ret = CMD_ERROR;
cd80958d
DG
377 goto error;
378 }
379
5eb00805 380 /* Iterate over all the context types given */
3301e740 381 cds_list_for_each_entry(type, &ctx_type_list.head, list) {
6775595e 382 context.ctx = (enum lttng_event_context_type) type->opt->ctx_type;
b13d56d7
MD
383 if (context.ctx == LTTNG_EVENT_CONTEXT_PERF_COUNTER) {
384 context.u.perf_counter.type = type->opt->u.perf.type;
385 context.u.perf_counter.config = type->opt->u.perf.config;
d7b91b3c 386 strcpy(context.u.perf_counter.name, type->opt->symbol);
b13d56d7
MD
387 /* Replace : and - by _ */
388 while ((ptr = strchr(context.u.perf_counter.name, '-')) != NULL) {
389 *ptr = '_';
3301e740 390 }
b13d56d7
MD
391 while ((ptr = strchr(context.u.perf_counter.name, ':')) != NULL) {
392 *ptr = '_';
3301e740 393 }
3301e740 394 }
55cc08a6
DG
395 DBG("Adding context...");
396
601d5acf 397 ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
55cc08a6 398 if (ret < 0) {
b58471ff 399 ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
d16c1a4c 400 warn = 1;
55cc08a6 401 continue;
d65106b1 402 } else {
601d5acf 403 if (opt_channel_name) {
b58471ff
DG
404 MSG("%s context %s added to channel %s",
405 opt_kernel ? "kernel" : "UST", type->opt->symbol,
406 opt_channel_name);
b58471ff
DG
407 } else {
408 MSG("%s context %s added to all channels",
409 opt_kernel ? "kernel" : "UST", type->opt->symbol)
410 }
d65106b1 411 }
d65106b1
DG
412 }
413
af87c45a
DG
414 ret = CMD_SUCCESS;
415
d65106b1 416error:
cd80958d
DG
417 lttng_destroy_handle(handle);
418
d16c1a4c
DG
419 /*
420 * This means that at least one add_context failed and tells the user to
421 * look on stderr for error(s).
422 */
423 if (warn) {
424 ret = CMD_WARNING;
425 }
d65106b1
DG
426 return ret;
427}
428
429/*
5eb00805 430 * Add context to channel or event.
d65106b1
DG
431 */
432int cmd_add_context(int argc, const char **argv)
433{
90b9a268 434 int index, opt, ret = CMD_SUCCESS;
d65106b1 435 static poptContext pc;
b13d56d7 436 struct ctx_type *type, *tmptype;
cd80958d 437 char *session_name = NULL;
d65106b1 438
636167b6
DG
439 if (argc < 2) {
440 usage(stderr);
5eb00805 441 ret = CMD_ERROR;
636167b6
DG
442 goto end;
443 }
444
d65106b1
DG
445 pc = poptGetContext(NULL, argc, argv, long_options, 0);
446 poptReadDefaultConfig(pc, 0);
447
448 while ((opt = poptGetNextOpt(pc)) != -1) {
449 switch (opt) {
450 case OPT_HELP:
5eb00805 451 usage(stdout);
d65106b1
DG
452 goto end;
453 case OPT_TYPE:
af87c45a
DG
454 /*
455 * Look up the index of opt_type in ctx_opts[] first, so we don't
456 * have to free(type) on failure.
457 */
6caa2bcc 458 index = find_ctx_type_idx(opt_type);
b13d56d7 459 if (index < 0) {
6caa2bcc 460 ERR("Unknown context type %s", opt_type);
5eb00805 461 ret = CMD_ERROR;
b13d56d7 462 goto end;
90b9a268 463 }
5eb00805
TD
464
465 type = malloc(sizeof(struct ctx_type));
466 if (type == NULL) {
467 perror("malloc ctx_type");
468 ret = CMD_FATAL;
469 goto end;
470 }
471
b13d56d7
MD
472 type->opt = &ctx_opts[index];
473 if (type->opt->ctx_type == -1) {
6caa2bcc 474 ERR("Unknown context type %s", opt_type);
5eb00805
TD
475 free(type);
476 ret = CMD_ERROR;
477 goto end;
90b9a268
DG
478 } else {
479 cds_list_add(&type->list, &ctx_type_list.head);
480 }
d65106b1 481 break;
eeac7d46
MD
482 case OPT_USERSPACE:
483 opt_userspace = 1;
d78d6610 484#if 0
eeac7d46 485 opt_cmd_name = poptGetOptArg(pc);
d78d6610 486#endif
eeac7d46 487 break;
679b4943
SM
488 case OPT_LIST_OPTIONS:
489 list_cmd_options(stdout, long_options);
679b4943 490 goto end;
d65106b1
DG
491 default:
492 usage(stderr);
493 ret = CMD_UNDEFINED;
494 goto end;
495 }
496 }
497
ae856491
DG
498 if (!opt_type) {
499 ERR("Missing mandatory -t TYPE");
500 usage(stderr);
501 ret = CMD_ERROR;
502 goto end;
503 }
504
cd80958d
DG
505 if (!opt_session_name) {
506 session_name = get_session_name();
507 if (session_name == NULL) {
5eb00805 508 ret = CMD_ERROR;
cd80958d
DG
509 goto end;
510 }
511 } else {
512 session_name = opt_session_name;
513 }
514
515 ret = add_context(session_name);
3301e740 516
1256f150
DT
517 if (!opt_session_name) {
518 free(session_name);
519 }
520
5eb00805 521end:
3301e740 522 /* Cleanup allocated memory */
b13d56d7 523 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
3301e740
DG
524 free(type);
525 }
526
ca1c3607 527 poptFreeContext(pc);
d65106b1
DG
528 return ret;
529}
This page took 0.080853 seconds and 4 git commands to generate.