Backported to glibc 2.8
[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,
7c612c2e 70 CONTEXT_IP = 12,
3301e740
DG
71};
72
90b9a268
DG
73/*
74 * Taken from the Perf ABI (all enum perf_*)
75 */
76enum perf_type {
77 PERF_TYPE_HARDWARE = 0,
78 PERF_TYPE_SOFTWARE = 1,
b13d56d7 79 PERF_TYPE_HW_CACHE = 3,
3301e740
DG
80};
81
90b9a268 82enum perf_count_hard {
b13d56d7
MD
83 PERF_COUNT_HW_CPU_CYCLES = 0,
84 PERF_COUNT_HW_INSTRUCTIONS = 1,
85 PERF_COUNT_HW_CACHE_REFERENCES = 2,
86 PERF_COUNT_HW_CACHE_MISSES = 3,
87 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
88 PERF_COUNT_HW_BRANCH_MISSES = 5,
89 PERF_COUNT_HW_BUS_CYCLES = 6,
90 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
91 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
90b9a268
DG
92};
93
94enum perf_count_soft {
95 PERF_COUNT_SW_CPU_CLOCK = 0,
96 PERF_COUNT_SW_TASK_CLOCK = 1,
97 PERF_COUNT_SW_PAGE_FAULTS = 2,
98 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
99 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
100 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
101 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
102 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
103 PERF_COUNT_SW_EMULATION_FAULTS = 8,
3301e740
DG
104};
105
b13d56d7
MD
106/*
107 * Generalized hardware cache events:
108 *
109 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
110 * { read, write, prefetch } x
111 * { accesses, misses }
112 */
113enum perf_hw_cache_id {
114 PERF_COUNT_HW_CACHE_L1D = 0,
115 PERF_COUNT_HW_CACHE_L1I = 1,
116 PERF_COUNT_HW_CACHE_LL = 2,
117 PERF_COUNT_HW_CACHE_DTLB = 3,
118 PERF_COUNT_HW_CACHE_ITLB = 4,
119 PERF_COUNT_HW_CACHE_BPU = 5,
120
121 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
122};
123
124enum perf_hw_cache_op_id {
125 PERF_COUNT_HW_CACHE_OP_READ = 0,
126 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
127 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
128
129 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
130};
131
132enum perf_hw_cache_op_result_id {
133 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
134 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
135
136 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
137};
138
d65106b1
DG
139static struct poptOption long_options[] = {
140 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
141 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
5440dc42 142 {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
d65106b1 143 {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
d65106b1 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 },
54773d68 206 { "hostname", CONTEXT_HOSTNAME },
7c612c2e 207 { "ip", CONTEXT_IP },
b13d56d7
MD
208 /* Perf options */
209 PERF_HW(cpu-cycles, CPU_CYCLES),
210 PERF_HW(cycles, CPU_CYCLES),
211 PERF_HW(stalled-cycles-frontend, STALLED_CYCLES_FRONTEND),
212 PERF_HW(idle-cycles-frontend, STALLED_CYCLES_FRONTEND),
213 PERF_HW(stalled-cycles-backend, STALLED_CYCLES_BACKEND),
214 PERF_HW(idle-cycles-backend, STALLED_CYCLES_BACKEND),
215 PERF_HW(instructions, INSTRUCTIONS),
216 PERF_HW(cache-references, CACHE_REFERENCES),
217 PERF_HW(cache-misses, CACHE_MISSES),
218 PERF_HW(branch-instructions, BRANCH_INSTRUCTIONS),
219 PERF_HW(branches, BRANCH_INSTRUCTIONS),
220 PERF_HW(branch-misses, BRANCH_MISSES),
221 PERF_HW(bus-cycles, BUS_CYCLES),
222
223 PERF_HW_CACHE(L1-dcache, L1D),
224 PERF_HW_CACHE(L1-icache, L1I),
225 PERF_HW_CACHE(LLC, LL),
226 PERF_HW_CACHE(dTLB, DTLB),
227 _PERF_HW_CACHE("iTLB-loads", ITLB, READ, ACCESS),
228 _PERF_HW_CACHE("iTLB-load-misses", ITLB, READ, MISS),
229 _PERF_HW_CACHE("branch-loads", BPU, READ, ACCESS),
230 _PERF_HW_CACHE("branch-load-misses", BPU, READ, MISS),
231
232
233 PERF_SW(cpu-clock, CPU_CLOCK),
234 PERF_SW(task-clock, TASK_CLOCK),
235 PERF_SW(page-fault, PAGE_FAULTS),
236 PERF_SW(faults, PAGE_FAULTS),
237 PERF_SW(major-faults, PAGE_FAULTS_MAJ),
238 PERF_SW(minor-faults, PAGE_FAULTS_MIN),
239 PERF_SW(context-switches, CONTEXT_SWITCHES),
240 PERF_SW(cs, CONTEXT_SWITCHES),
241 PERF_SW(cpu-migrations, CPU_MIGRATIONS),
242 PERF_SW(migrations, CPU_MIGRATIONS),
243 PERF_SW(alignment-faults, ALIGNMENT_FAULTS),
244 PERF_SW(emulation-faults, EMULATION_FAULTS),
245 { NULL, -1 }, /* Closure */
90b9a268
DG
246};
247
b13d56d7
MD
248#undef PERF_SW
249#undef PERF_HW
250
90b9a268 251/*
b13d56d7 252 * Context type for command line option parsing.
90b9a268 253 */
b13d56d7
MD
254struct ctx_type {
255 const struct ctx_opts *opt;
256 struct cds_list_head list;
90b9a268
DG
257};
258
259/*
260 * List of context type. Use to enable multiple context on a single command
261 * line entry.
262 */
263struct ctx_type_list {
264 struct cds_list_head head;
265} ctx_type_list = {
266 .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
267};
268
90b9a268
DG
269/*
270 * Pretty print context type.
271 */
272static void print_ctx_type(FILE *ofp)
273{
b13d56d7
MD
274 const char *indent = " ";
275 int indent_len = strlen(indent);
276 int len, i = 0;
90b9a268 277
76e3c5dd 278 fprintf(ofp, "%s", indent);
b13d56d7 279 len = indent_len;
90b9a268 280 while (ctx_opts[i].symbol != NULL) {
b13d56d7
MD
281 if (len > indent_len) {
282 if (len + strlen(ctx_opts[i].symbol) + 2
283 >= PRINT_LINE_LEN) {
284 fprintf(ofp, ",\n");
76e3c5dd 285 fprintf(ofp, "%s", indent);
b13d56d7
MD
286 len = indent_len;
287 } else {
288 len += fprintf(ofp, ", ");
90b9a268
DG
289 }
290 }
b13d56d7 291 len += fprintf(ofp, "%s", ctx_opts[i].symbol);
90b9a268
DG
292 i++;
293 }
90b9a268
DG
294}
295
d65106b1
DG
296/*
297 * usage
298 */
299static void usage(FILE *ofp)
300{
32a6298d 301 fprintf(ofp, "usage: lttng add-context -t TYPE [-k|-u] [OPTIONS]\n");
d65106b1 302 fprintf(ofp, "\n");
601d5acf
DG
303 fprintf(ofp, "If no channel is given (-c), the context is added to\n");
304 fprintf(ofp, "all channels.\n");
32a6298d 305 fprintf(ofp, "\n");
601d5acf 306 fprintf(ofp, "Otherwise the context is added only to the channel (-c).\n");
32a6298d
DG
307 fprintf(ofp, "\n");
308 fprintf(ofp, "Exactly one domain (-k or -u) must be specified.\n");
3301e740 309 fprintf(ofp, "\n");
d65106b1
DG
310 fprintf(ofp, "Options:\n");
311 fprintf(ofp, " -h, --help Show this help\n");
679b4943 312 fprintf(ofp, " --list-options Simple listing of options\n");
5eb00805
TD
313 fprintf(ofp, " -s, --session NAME Apply to session name\n");
314 fprintf(ofp, " -c, --channel NAME Apply to channel\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"
601d5acf 327 "counters (hardware branch misses and cache misses), to all channels\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 {
b9dfb167 371 print_missing_domain();
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;
24546386
MD
388 strncpy(context.u.perf_counter.name, type->opt->symbol,
389 LTTNG_SYMBOL_NAME_LEN);
390 context.u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
b13d56d7
MD
391 /* Replace : and - by _ */
392 while ((ptr = strchr(context.u.perf_counter.name, '-')) != NULL) {
393 *ptr = '_';
3301e740 394 }
b13d56d7
MD
395 while ((ptr = strchr(context.u.perf_counter.name, ':')) != NULL) {
396 *ptr = '_';
3301e740 397 }
3301e740 398 }
55cc08a6
DG
399 DBG("Adding context...");
400
601d5acf 401 ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
55cc08a6 402 if (ret < 0) {
b58471ff 403 ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
d16c1a4c 404 warn = 1;
55cc08a6 405 continue;
d65106b1 406 } else {
601d5acf 407 if (opt_channel_name) {
b58471ff
DG
408 MSG("%s context %s added to channel %s",
409 opt_kernel ? "kernel" : "UST", type->opt->symbol,
410 opt_channel_name);
b58471ff
DG
411 } else {
412 MSG("%s context %s added to all channels",
413 opt_kernel ? "kernel" : "UST", type->opt->symbol)
414 }
d65106b1 415 }
d65106b1
DG
416 }
417
af87c45a
DG
418 ret = CMD_SUCCESS;
419
d65106b1 420error:
cd80958d
DG
421 lttng_destroy_handle(handle);
422
d16c1a4c
DG
423 /*
424 * This means that at least one add_context failed and tells the user to
425 * look on stderr for error(s).
426 */
427 if (warn) {
428 ret = CMD_WARNING;
429 }
d65106b1
DG
430 return ret;
431}
432
433/*
5eb00805 434 * Add context to channel or event.
d65106b1
DG
435 */
436int cmd_add_context(int argc, const char **argv)
437{
90b9a268 438 int index, opt, ret = CMD_SUCCESS;
d65106b1 439 static poptContext pc;
b13d56d7 440 struct ctx_type *type, *tmptype;
cd80958d 441 char *session_name = NULL;
d65106b1 442
636167b6
DG
443 if (argc < 2) {
444 usage(stderr);
5eb00805 445 ret = CMD_ERROR;
636167b6
DG
446 goto end;
447 }
448
d65106b1
DG
449 pc = poptGetContext(NULL, argc, argv, long_options, 0);
450 poptReadDefaultConfig(pc, 0);
451
452 while ((opt = poptGetNextOpt(pc)) != -1) {
453 switch (opt) {
454 case OPT_HELP:
5eb00805 455 usage(stdout);
d65106b1
DG
456 goto end;
457 case OPT_TYPE:
af87c45a
DG
458 /*
459 * Look up the index of opt_type in ctx_opts[] first, so we don't
460 * have to free(type) on failure.
461 */
6caa2bcc 462 index = find_ctx_type_idx(opt_type);
b13d56d7 463 if (index < 0) {
6caa2bcc 464 ERR("Unknown context type %s", opt_type);
5eb00805 465 ret = CMD_ERROR;
b13d56d7 466 goto end;
90b9a268 467 }
5eb00805
TD
468
469 type = malloc(sizeof(struct ctx_type));
470 if (type == NULL) {
471 perror("malloc ctx_type");
472 ret = CMD_FATAL;
473 goto end;
474 }
475
b13d56d7 476 type->opt = &ctx_opts[index];
109be0da 477 if (type->opt->symbol == NULL) {
6caa2bcc 478 ERR("Unknown context type %s", opt_type);
5eb00805
TD
479 free(type);
480 ret = CMD_ERROR;
481 goto end;
90b9a268 482 } else {
31746f93 483 cds_list_add_tail(&type->list, &ctx_type_list.head);
90b9a268 484 }
d65106b1 485 break;
eeac7d46
MD
486 case OPT_USERSPACE:
487 opt_userspace = 1;
d78d6610 488#if 0
eeac7d46 489 opt_cmd_name = poptGetOptArg(pc);
d78d6610 490#endif
eeac7d46 491 break;
679b4943
SM
492 case OPT_LIST_OPTIONS:
493 list_cmd_options(stdout, long_options);
679b4943 494 goto end;
d65106b1
DG
495 default:
496 usage(stderr);
497 ret = CMD_UNDEFINED;
498 goto end;
499 }
500 }
501
ae856491
DG
502 if (!opt_type) {
503 ERR("Missing mandatory -t TYPE");
504 usage(stderr);
505 ret = CMD_ERROR;
506 goto end;
507 }
508
cd80958d
DG
509 if (!opt_session_name) {
510 session_name = get_session_name();
511 if (session_name == NULL) {
5eb00805 512 ret = CMD_ERROR;
cd80958d
DG
513 goto end;
514 }
515 } else {
516 session_name = opt_session_name;
517 }
518
519 ret = add_context(session_name);
3301e740 520
1256f150
DT
521 if (!opt_session_name) {
522 free(session_name);
523 }
524
5eb00805 525end:
3301e740 526 /* Cleanup allocated memory */
b13d56d7 527 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
3301e740
DG
528 free(type);
529 }
530
ca1c3607 531 poptFreeContext(pc);
d65106b1
DG
532 return ret;
533}
This page took 0.102556 seconds and 4 git commands to generate.