Add CMD_WARNING error code
[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 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
82a3637f
DG
6 * as published by the Free Software Foundation; only version 2
7 * of the License.
d65106b1
DG
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19#define _GNU_SOURCE
90b9a268 20#include <ctype.h>
d65106b1
DG
21#include <popt.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28
3301e740
DG
29#include <urcu/list.h>
30
c399183f 31#include "../command.h"
d65106b1 32
b13d56d7
MD
33#define PRINT_LINE_LEN 80
34
d65106b1
DG
35static char *opt_event_name;
36static char *opt_channel_name;
5440dc42 37static char *opt_session_name;
55cc08a6 38static int opt_kernel;
d65106b1 39static int opt_userspace;
d78d6610
DG
40static char *opt_type;
41#if 0
42/* Not implemented yet */
eeac7d46 43static char *opt_cmd_name;
d65106b1 44static pid_t opt_pid;
d78d6610 45#endif
d65106b1
DG
46
47enum {
48 OPT_HELP = 1,
49 OPT_TYPE,
eeac7d46 50 OPT_USERSPACE,
679b4943 51 OPT_LIST_OPTIONS,
d65106b1
DG
52};
53
cd80958d
DG
54static struct lttng_handle *handle;
55
90b9a268
DG
56/*
57 * Taken from the LTTng ABI
58 */
59enum context_type {
60 CONTEXT_PID = 0,
61 CONTEXT_PERF_COUNTER = 1,
95da1297 62 CONTEXT_PROCNAME = 2,
90b9a268
DG
63 CONTEXT_PRIO = 3,
64 CONTEXT_NICE = 4,
65 CONTEXT_VPID = 5,
66 CONTEXT_TID = 6,
67 CONTEXT_VTID = 7,
68 CONTEXT_PPID = 8,
69 CONTEXT_VPPID = 9,
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
DG
145#if 0
146 /* Not implemented yet */
d65106b1 147 {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0},
d78d6610
DG
148 {"userspace", 'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_cmd_name, OPT_USERSPACE, 0, 0},
149#else
150 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
151#endif
6caa2bcc 152 {"type", 't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
679b4943 153 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
d65106b1
DG
154 {0, 0, 0, 0, 0, 0, 0}
155};
156
90b9a268 157/*
b13d56d7 158 * Context options
90b9a268 159 */
b13d56d7
MD
160#define PERF_HW(opt, name) \
161 { \
162 "perf:" #opt, CONTEXT_PERF_COUNTER, \
163 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
164 }
90b9a268 165
b13d56d7
MD
166#define PERF_SW(opt, name) \
167 { \
168 "perf:" #opt, CONTEXT_PERF_COUNTER, \
169 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
170 }
90b9a268 171
b13d56d7
MD
172#define _PERF_HW_CACHE(optstr, name, op, result) \
173 { \
174 "perf:" optstr, CONTEXT_PERF_COUNTER, \
175 .u.perf = { \
176 PERF_TYPE_HW_CACHE, \
177 (uint64_t) PERF_COUNT_HW_CACHE_##name \
18829107
MD
178 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
179 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
b13d56d7
MD
180 }, \
181 }
182
183#define PERF_HW_CACHE(opt, name) \
184 _PERF_HW_CACHE(#opt "-loads", name, READ, ACCESS), \
185 _PERF_HW_CACHE(#opt "-load-misses", name, READ, MISS), \
186 _PERF_HW_CACHE(#opt "-stores", name, WRITE, ACCESS), \
187 _PERF_HW_CACHE(#opt "-store-misses", name, WRITE, MISS), \
188 _PERF_HW_CACHE(#opt "-prefetches", name, PREFETCH, ACCESS), \
189 _PERF_HW_CACHE(#opt "-prefetch-misses", name, PREFETCH, MISS) \
190
191static
192const struct ctx_opts {
90b9a268 193 char *symbol;
b13d56d7
MD
194 enum context_type ctx_type;
195 union {
196 struct {
197 uint32_t type;
198 uint64_t config;
199 } perf;
200 } u;
201} ctx_opts[] = {
202 { "pid", CONTEXT_PID },
95da1297 203 { "procname", CONTEXT_PROCNAME },
b13d56d7
MD
204 { "prio", CONTEXT_PRIO },
205 { "nice", CONTEXT_NICE },
206 { "vpid", CONTEXT_VPID },
207 { "tid", CONTEXT_TID },
208 { "vtid", CONTEXT_VTID },
209 { "ppid", CONTEXT_PPID },
210 { "vppid", CONTEXT_VPPID },
211 /* Perf options */
212 PERF_HW(cpu-cycles, CPU_CYCLES),
213 PERF_HW(cycles, CPU_CYCLES),
214 PERF_HW(stalled-cycles-frontend, STALLED_CYCLES_FRONTEND),
215 PERF_HW(idle-cycles-frontend, STALLED_CYCLES_FRONTEND),
216 PERF_HW(stalled-cycles-backend, STALLED_CYCLES_BACKEND),
217 PERF_HW(idle-cycles-backend, STALLED_CYCLES_BACKEND),
218 PERF_HW(instructions, INSTRUCTIONS),
219 PERF_HW(cache-references, CACHE_REFERENCES),
220 PERF_HW(cache-misses, CACHE_MISSES),
221 PERF_HW(branch-instructions, BRANCH_INSTRUCTIONS),
222 PERF_HW(branches, BRANCH_INSTRUCTIONS),
223 PERF_HW(branch-misses, BRANCH_MISSES),
224 PERF_HW(bus-cycles, BUS_CYCLES),
225
226 PERF_HW_CACHE(L1-dcache, L1D),
227 PERF_HW_CACHE(L1-icache, L1I),
228 PERF_HW_CACHE(LLC, LL),
229 PERF_HW_CACHE(dTLB, DTLB),
230 _PERF_HW_CACHE("iTLB-loads", ITLB, READ, ACCESS),
231 _PERF_HW_CACHE("iTLB-load-misses", ITLB, READ, MISS),
232 _PERF_HW_CACHE("branch-loads", BPU, READ, ACCESS),
233 _PERF_HW_CACHE("branch-load-misses", BPU, READ, MISS),
234
235
236 PERF_SW(cpu-clock, CPU_CLOCK),
237 PERF_SW(task-clock, TASK_CLOCK),
238 PERF_SW(page-fault, PAGE_FAULTS),
239 PERF_SW(faults, PAGE_FAULTS),
240 PERF_SW(major-faults, PAGE_FAULTS_MAJ),
241 PERF_SW(minor-faults, PAGE_FAULTS_MIN),
242 PERF_SW(context-switches, CONTEXT_SWITCHES),
243 PERF_SW(cs, CONTEXT_SWITCHES),
244 PERF_SW(cpu-migrations, CPU_MIGRATIONS),
245 PERF_SW(migrations, CPU_MIGRATIONS),
246 PERF_SW(alignment-faults, ALIGNMENT_FAULTS),
247 PERF_SW(emulation-faults, EMULATION_FAULTS),
248 { NULL, -1 }, /* Closure */
90b9a268
DG
249};
250
b13d56d7
MD
251#undef PERF_SW
252#undef PERF_HW
253
90b9a268 254/*
b13d56d7 255 * Context type for command line option parsing.
90b9a268 256 */
b13d56d7
MD
257struct ctx_type {
258 const struct ctx_opts *opt;
259 struct cds_list_head list;
90b9a268
DG
260};
261
262/*
263 * List of context type. Use to enable multiple context on a single command
264 * line entry.
265 */
266struct ctx_type_list {
267 struct cds_list_head head;
268} ctx_type_list = {
269 .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
270};
271
90b9a268
DG
272/*
273 * Pretty print context type.
274 */
275static void print_ctx_type(FILE *ofp)
276{
b13d56d7
MD
277 const char *indent = " ";
278 int indent_len = strlen(indent);
279 int len, i = 0;
90b9a268 280
76e3c5dd 281 fprintf(ofp, "%s", indent);
b13d56d7 282 len = indent_len;
90b9a268 283 while (ctx_opts[i].symbol != NULL) {
b13d56d7
MD
284 if (len > indent_len) {
285 if (len + strlen(ctx_opts[i].symbol) + 2
286 >= PRINT_LINE_LEN) {
287 fprintf(ofp, ",\n");
76e3c5dd 288 fprintf(ofp, "%s", indent);
b13d56d7
MD
289 len = indent_len;
290 } else {
291 len += fprintf(ofp, ", ");
90b9a268
DG
292 }
293 }
b13d56d7 294 len += fprintf(ofp, "%s", ctx_opts[i].symbol);
90b9a268
DG
295 i++;
296 }
90b9a268
DG
297}
298
d65106b1
DG
299/*
300 * usage
301 */
302static void usage(FILE *ofp)
303{
b13d56d7 304 fprintf(ofp, "usage: lttng add-context -t TYPE\n");
d65106b1 305 fprintf(ofp, "\n");
b13d56d7 306 fprintf(ofp, "If no channel and no event is given (-c/-e), the context\n");
55cc08a6 307 fprintf(ofp, "will be added to all events and all channels.\n");
af87c45a
DG
308 fprintf(ofp, "Otherwise the context will be added only to the channel (-c)\n");
309 fprintf(ofp, "and/or event (-e) indicated.\n");
3301e740 310 fprintf(ofp, "\n");
d65106b1
DG
311 fprintf(ofp, "Options:\n");
312 fprintf(ofp, " -h, --help Show this help\n");
679b4943 313 fprintf(ofp, " --list-options Simple listing of options\n");
af87c45a 314 fprintf(ofp, " -s, --session NAME Apply on session name\n");
d65106b1
DG
315 fprintf(ofp, " -c, --channel NAME Apply on channel\n");
316 fprintf(ofp, " -e, --event NAME Apply on event\n");
af87c45a 317 fprintf(ofp, " -k, --kernel Apply to the kernel tracer\n");
d78d6610 318#if 0
af87c45a 319 fprintf(ofp, " -u, --userspace [CMD] Apply to the user-space tracer\n");
e14f64a8
DG
320 fprintf(ofp, " If no CMD, the domain used is UST global\n");
321 fprintf(ofp, " or else the domain is UST EXEC_NAME\n");
322 fprintf(ofp, " -p, --pid PID If -u, apply to specific PID (domain: UST PID)\n");
d78d6610 323#else
af87c45a 324 fprintf(ofp, " -u, --userspace Apply to the user-space tracer\n");
d78d6610 325#endif
b13d56d7 326 fprintf(ofp, " -t, --type TYPE Context type. You can repeat that option on\n");
af87c45a
DG
327 fprintf(ofp, " the command line to specify multiple contexts at once.\n");
328 fprintf(ofp, " (--kernel preempts --userspace)\n");
b13d56d7 329 fprintf(ofp, " TYPE can be one of the strings below:\n");
90b9a268 330 print_ctx_type(ofp);
d65106b1 331 fprintf(ofp, "\n");
90b9a268 332 fprintf(ofp, "Example:\n");
b13d56d7 333 fprintf(ofp, "This command will add the context information 'prio' and two perf\n"
af87c45a 334 "counters (hardware branch misses and cache misses), to all events\n"
b13d56d7
MD
335 "in the trace data output:\n");
336 fprintf(ofp, "# lttng add-context -k -t prio -t perf:branch-misses -t perf:cache-misses\n");
d65106b1
DG
337 fprintf(ofp, "\n");
338}
339
90b9a268
DG
340/*
341 * Find context numerical value from string.
342 */
343static int find_ctx_type_idx(const char *opt)
344{
345 int ret = -1, i = 0;
346
347 while (ctx_opts[i].symbol != NULL) {
348 if (strcmp(opt, ctx_opts[i].symbol) == 0) {
349 ret = i;
350 goto end;
351 }
352 i++;
353 }
354
355end:
356 return ret;
357}
358
90b9a268
DG
359/*
360 * Add context to channel or event.
d65106b1 361 */
cd80958d 362static int add_context(char *session_name)
d65106b1 363{
d16c1a4c 364 int ret = CMD_SUCCESS, warn = 0;
7d29a247
DG
365 struct lttng_event_context context;
366 struct lttng_domain dom;
3301e740 367 struct ctx_type *type;
b13d56d7 368 char *ptr;
d65106b1 369
cd80958d
DG
370 if (opt_kernel) {
371 dom.type = LTTNG_DOMAIN_KERNEL;
d78d6610 372 } else if (opt_userspace) {
55cc08a6 373 dom.type = LTTNG_DOMAIN_UST;
55cc08a6 374 } else {
e14f64a8 375 ERR("Please specify a tracer (-k/--kernel or -u/--userspace)");
d16c1a4c 376 ret = CMD_ERROR;
55cc08a6 377 goto error;
cd80958d
DG
378 }
379
380 handle = lttng_create_handle(session_name, &dom);
381 if (handle == NULL) {
af87c45a 382 ret = CMD_ERROR;
cd80958d
DG
383 goto error;
384 }
385
3301e740
DG
386 /* Iterate over all context type given */
387 cds_list_for_each_entry(type, &ctx_type_list.head, list) {
b13d56d7
MD
388 context.ctx = type->opt->ctx_type;
389 if (context.ctx == LTTNG_EVENT_CONTEXT_PERF_COUNTER) {
390 context.u.perf_counter.type = type->opt->u.perf.type;
391 context.u.perf_counter.config = type->opt->u.perf.config;
d7b91b3c 392 strcpy(context.u.perf_counter.name, type->opt->symbol);
b13d56d7
MD
393 /* Replace : and - by _ */
394 while ((ptr = strchr(context.u.perf_counter.name, '-')) != NULL) {
395 *ptr = '_';
3301e740 396 }
b13d56d7
MD
397 while ((ptr = strchr(context.u.perf_counter.name, ':')) != NULL) {
398 *ptr = '_';
3301e740 399 }
3301e740 400 }
55cc08a6
DG
401 DBG("Adding context...");
402
403 ret = lttng_add_context(handle, &context, opt_event_name,
404 opt_channel_name);
405 if (ret < 0) {
af87c45a 406 ERR("%s: ", type->opt->symbol);
d16c1a4c 407 warn = 1;
55cc08a6 408 continue;
d65106b1 409 } else {
55cc08a6
DG
410 MSG("%s context %s added to %s event in %s",
411 opt_kernel ? "kernel" : "UST", type->opt->symbol,
412 opt_event_name ? opt_event_name : "all",
413 opt_channel_name ? opt_channel_name : "all channels");
d65106b1 414 }
d65106b1
DG
415 }
416
af87c45a
DG
417 ret = CMD_SUCCESS;
418
d65106b1 419error:
cd80958d
DG
420 lttng_destroy_handle(handle);
421
d16c1a4c
DG
422 /*
423 * This means that at least one add_context failed and tells the user to
424 * look on stderr for error(s).
425 */
426 if (warn) {
427 ret = CMD_WARNING;
428 }
d65106b1
DG
429 return ret;
430}
431
432/*
90b9a268 433 * Add context on channel or event.
d65106b1
DG
434 */
435int cmd_add_context(int argc, const char **argv)
436{
90b9a268 437 int index, opt, ret = CMD_SUCCESS;
d65106b1 438 static poptContext pc;
b13d56d7 439 struct ctx_type *type, *tmptype;
cd80958d 440 char *session_name = NULL;
d65106b1 441
636167b6
DG
442 if (argc < 2) {
443 usage(stderr);
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:
453 usage(stderr);
454 ret = CMD_SUCCESS;
455 goto end;
456 case OPT_TYPE:
3301e740
DG
457 type = malloc(sizeof(struct ctx_type));
458 if (type == NULL) {
459 perror("malloc ctx_type");
460 ret = -1;
636167b6
DG
461 goto end;
462 }
af87c45a
DG
463
464 /*
465 * Look up the index of opt_type in ctx_opts[] first, so we don't
466 * have to free(type) on failure.
467 */
6caa2bcc 468 index = find_ctx_type_idx(opt_type);
b13d56d7 469 if (index < 0) {
6caa2bcc 470 ERR("Unknown context type %s", opt_type);
b13d56d7 471 goto end;
90b9a268 472 }
b13d56d7
MD
473 type->opt = &ctx_opts[index];
474 if (type->opt->ctx_type == -1) {
6caa2bcc 475 ERR("Unknown context type %s", opt_type);
90b9a268
DG
476 } else {
477 cds_list_add(&type->list, &ctx_type_list.head);
478 }
d65106b1 479 break;
eeac7d46
MD
480 case OPT_USERSPACE:
481 opt_userspace = 1;
d78d6610 482#if 0
eeac7d46 483 opt_cmd_name = poptGetOptArg(pc);
d78d6610 484#endif
eeac7d46 485 break;
679b4943
SM
486 case OPT_LIST_OPTIONS:
487 list_cmd_options(stdout, long_options);
488 ret = CMD_SUCCESS;
489 goto end;
d65106b1
DG
490 default:
491 usage(stderr);
492 ret = CMD_UNDEFINED;
493 goto end;
494 }
495 }
496
cd80958d
DG
497 if (!opt_session_name) {
498 session_name = get_session_name();
499 if (session_name == NULL) {
500 ret = -1;
501 goto end;
502 }
503 } else {
504 session_name = opt_session_name;
505 }
506
507 ret = add_context(session_name);
3301e740
DG
508
509 /* Cleanup allocated memory */
b13d56d7 510 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
3301e740
DG
511 free(type);
512 }
513
d65106b1
DG
514end:
515 return ret;
516}
This page took 0.053362 seconds and 5 git commands to generate.