Fix: possible consumer sockets double close on cleanup
[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;
24546386
MD
386 strncpy(context.u.perf_counter.name, type->opt->symbol,
387 LTTNG_SYMBOL_NAME_LEN);
388 context.u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
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
601d5acf 399 ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
55cc08a6 400 if (ret < 0) {
b58471ff 401 ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
d16c1a4c 402 warn = 1;
55cc08a6 403 continue;
d65106b1 404 } else {
601d5acf 405 if (opt_channel_name) {
b58471ff
DG
406 MSG("%s context %s added to channel %s",
407 opt_kernel ? "kernel" : "UST", type->opt->symbol,
408 opt_channel_name);
b58471ff
DG
409 } else {
410 MSG("%s context %s added to all channels",
411 opt_kernel ? "kernel" : "UST", type->opt->symbol)
412 }
d65106b1 413 }
d65106b1
DG
414 }
415
af87c45a
DG
416 ret = CMD_SUCCESS;
417
d65106b1 418error:
cd80958d
DG
419 lttng_destroy_handle(handle);
420
d16c1a4c
DG
421 /*
422 * This means that at least one add_context failed and tells the user to
423 * look on stderr for error(s).
424 */
425 if (warn) {
426 ret = CMD_WARNING;
427 }
d65106b1
DG
428 return ret;
429}
430
431/*
5eb00805 432 * Add context to channel or event.
d65106b1
DG
433 */
434int cmd_add_context(int argc, const char **argv)
435{
90b9a268 436 int index, opt, ret = CMD_SUCCESS;
d65106b1 437 static poptContext pc;
b13d56d7 438 struct ctx_type *type, *tmptype;
cd80958d 439 char *session_name = NULL;
d65106b1 440
636167b6
DG
441 if (argc < 2) {
442 usage(stderr);
5eb00805 443 ret = CMD_ERROR;
636167b6
DG
444 goto end;
445 }
446
d65106b1
DG
447 pc = poptGetContext(NULL, argc, argv, long_options, 0);
448 poptReadDefaultConfig(pc, 0);
449
450 while ((opt = poptGetNextOpt(pc)) != -1) {
451 switch (opt) {
452 case OPT_HELP:
5eb00805 453 usage(stdout);
d65106b1
DG
454 goto end;
455 case OPT_TYPE:
af87c45a
DG
456 /*
457 * Look up the index of opt_type in ctx_opts[] first, so we don't
458 * have to free(type) on failure.
459 */
6caa2bcc 460 index = find_ctx_type_idx(opt_type);
b13d56d7 461 if (index < 0) {
6caa2bcc 462 ERR("Unknown context type %s", opt_type);
5eb00805 463 ret = CMD_ERROR;
b13d56d7 464 goto end;
90b9a268 465 }
5eb00805
TD
466
467 type = malloc(sizeof(struct ctx_type));
468 if (type == NULL) {
469 perror("malloc ctx_type");
470 ret = CMD_FATAL;
471 goto end;
472 }
473
b13d56d7
MD
474 type->opt = &ctx_opts[index];
475 if (type->opt->ctx_type == -1) {
6caa2bcc 476 ERR("Unknown context type %s", opt_type);
5eb00805
TD
477 free(type);
478 ret = CMD_ERROR;
479 goto end;
90b9a268
DG
480 } else {
481 cds_list_add(&type->list, &ctx_type_list.head);
482 }
d65106b1 483 break;
eeac7d46
MD
484 case OPT_USERSPACE:
485 opt_userspace = 1;
d78d6610 486#if 0
eeac7d46 487 opt_cmd_name = poptGetOptArg(pc);
d78d6610 488#endif
eeac7d46 489 break;
679b4943
SM
490 case OPT_LIST_OPTIONS:
491 list_cmd_options(stdout, long_options);
679b4943 492 goto end;
d65106b1
DG
493 default:
494 usage(stderr);
495 ret = CMD_UNDEFINED;
496 goto end;
497 }
498 }
499
ae856491
DG
500 if (!opt_type) {
501 ERR("Missing mandatory -t TYPE");
502 usage(stderr);
503 ret = CMD_ERROR;
504 goto end;
505 }
506
cd80958d
DG
507 if (!opt_session_name) {
508 session_name = get_session_name();
509 if (session_name == NULL) {
5eb00805 510 ret = CMD_ERROR;
cd80958d
DG
511 goto end;
512 }
513 } else {
514 session_name = opt_session_name;
515 }
516
517 ret = add_context(session_name);
3301e740 518
1256f150
DT
519 if (!opt_session_name) {
520 free(session_name);
521 }
522
5eb00805 523end:
3301e740 524 /* Cleanup allocated memory */
b13d56d7 525 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
3301e740
DG
526 free(type);
527 }
528
ca1c3607 529 poptFreeContext(pc);
d65106b1
DG
530 return ret;
531}
This page took 0.064717 seconds and 5 git commands to generate.