Refactoring: use an opaque lttng_tracker_id type
[lttng-tools.git] / src / bin / lttng / commands / add_context.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
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 along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _LGPL_SOURCE
20 #include <ctype.h>
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 #include <assert.h>
29
30 #include <urcu/list.h>
31
32 #include <common/mi-lttng.h>
33
34 #include "../command.h"
35
36 static char *opt_channel_name;
37 static char *opt_session_name;
38 static int opt_kernel;
39 static int opt_userspace;
40 static int opt_jul;
41 static int opt_log4j;
42 static char *opt_type;
43
44 #ifdef LTTNG_EMBED_HELP
45 static const char help_msg[] =
46 #include <lttng-add-context.1.h>
47 ;
48 #endif
49
50 enum {
51 OPT_HELP = 1,
52 OPT_TYPE,
53 OPT_USERSPACE,
54 OPT_JUL,
55 OPT_LOG4J,
56 OPT_LIST_OPTIONS,
57 OPT_LIST,
58 };
59
60 static struct lttng_handle *handle;
61 static struct mi_writer *writer;
62
63 /*
64 * Taken from the LTTng ABI
65 */
66 enum context_type {
67 CONTEXT_PID = 0,
68 CONTEXT_PERF_COUNTER = 1, /* Backward compat. */
69 CONTEXT_PROCNAME = 2,
70 CONTEXT_PRIO = 3,
71 CONTEXT_NICE = 4,
72 CONTEXT_VPID = 5,
73 CONTEXT_TID = 6,
74 CONTEXT_VTID = 7,
75 CONTEXT_PPID = 8,
76 CONTEXT_VPPID = 9,
77 CONTEXT_PTHREAD_ID = 10,
78 CONTEXT_HOSTNAME = 11,
79 CONTEXT_IP = 12,
80 CONTEXT_PERF_CPU_COUNTER = 13,
81 CONTEXT_PERF_THREAD_COUNTER = 14,
82 CONTEXT_APP_CONTEXT = 15,
83 CONTEXT_INTERRUPTIBLE = 16,
84 CONTEXT_PREEMPTIBLE = 17,
85 CONTEXT_NEED_RESCHEDULE = 18,
86 CONTEXT_MIGRATABLE = 19,
87 CONTEXT_CALLSTACK_KERNEL = 20,
88 CONTEXT_CALLSTACK_USER = 21,
89 CONTEXT_CGROUP_NS = 22,
90 CONTEXT_IPC_NS = 23,
91 CONTEXT_MNT_NS = 24,
92 CONTEXT_NET_NS = 25,
93 CONTEXT_PID_NS = 26,
94 CONTEXT_USER_NS = 27,
95 CONTEXT_UTS_NS = 28,
96 CONTEXT_UID = 29,
97 CONTEXT_EUID = 30,
98 CONTEXT_SUID = 31,
99 CONTEXT_GID = 32,
100 CONTEXT_EGID = 33,
101 CONTEXT_SGID = 34,
102 CONTEXT_VUID = 35,
103 CONTEXT_VEUID = 36,
104 CONTEXT_VSUID = 37,
105 CONTEXT_VGID = 38,
106 CONTEXT_VEGID = 39,
107 CONTEXT_VSGID = 40,
108 };
109
110 /*
111 * Taken from the Perf ABI (all enum perf_*)
112 */
113 enum perf_type {
114 PERF_TYPE_HARDWARE = 0,
115 PERF_TYPE_SOFTWARE = 1,
116 PERF_TYPE_HW_CACHE = 3,
117 PERF_TYPE_RAW = 4,
118 };
119
120 enum perf_count_hard {
121 PERF_COUNT_HW_CPU_CYCLES = 0,
122 PERF_COUNT_HW_INSTRUCTIONS = 1,
123 PERF_COUNT_HW_CACHE_REFERENCES = 2,
124 PERF_COUNT_HW_CACHE_MISSES = 3,
125 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
126 PERF_COUNT_HW_BRANCH_MISSES = 5,
127 PERF_COUNT_HW_BUS_CYCLES = 6,
128 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
129 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
130 };
131
132 enum perf_count_soft {
133 PERF_COUNT_SW_CPU_CLOCK = 0,
134 PERF_COUNT_SW_TASK_CLOCK = 1,
135 PERF_COUNT_SW_PAGE_FAULTS = 2,
136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
137 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
139 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
140 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
141 PERF_COUNT_SW_EMULATION_FAULTS = 8,
142 };
143
144 /*
145 * Generalized hardware cache events:
146 *
147 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
148 * { read, write, prefetch } x
149 * { accesses, misses }
150 */
151 enum perf_hw_cache_id {
152 PERF_COUNT_HW_CACHE_L1D = 0,
153 PERF_COUNT_HW_CACHE_L1I = 1,
154 PERF_COUNT_HW_CACHE_LL = 2,
155 PERF_COUNT_HW_CACHE_DTLB = 3,
156 PERF_COUNT_HW_CACHE_ITLB = 4,
157 PERF_COUNT_HW_CACHE_BPU = 5,
158
159 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
160 };
161
162 enum perf_hw_cache_op_id {
163 PERF_COUNT_HW_CACHE_OP_READ = 0,
164 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
165 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
166
167 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
168 };
169
170 enum perf_hw_cache_op_result_id {
171 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
172 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
173
174 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
175 };
176
177 static struct poptOption long_options[] = {
178 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
179 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
180 {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
181 {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
182 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
183 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
184 {"jul", 'j', POPT_ARG_NONE, 0, OPT_JUL, 0, 0},
185 {"log4j", 'l', POPT_ARG_NONE, 0, OPT_LOG4J, 0, 0},
186 {"type", 't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
187 {"list", 0, POPT_ARG_NONE, NULL, OPT_LIST, NULL, NULL},
188 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
189 {0, 0, 0, 0, 0, 0, 0}
190 };
191
192 /*
193 * Context options
194 */
195 #define PERF_HW(optstr, name, type, hide) \
196 { \
197 optstr, type, hide, \
198 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
199 }
200
201 #define PERF_SW(optstr, name, type, hide) \
202 { \
203 optstr, type, hide, \
204 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
205 }
206
207 #define _PERF_HW_CACHE(optstr, name, type, op, result, hide) \
208 { \
209 optstr, type, hide, \
210 .u.perf = { \
211 PERF_TYPE_HW_CACHE, \
212 (uint64_t) PERF_COUNT_HW_CACHE_##name \
213 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
214 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
215 }, \
216 }
217
218 #define PERF_HW_CACHE(optstr, name, type, hide) \
219 _PERF_HW_CACHE(optstr "-loads", name, type, \
220 READ, ACCESS, hide), \
221 _PERF_HW_CACHE(optstr "-load-misses", name, type, \
222 READ, MISS, hide), \
223 _PERF_HW_CACHE(optstr "-stores", name, type, \
224 WRITE, ACCESS, hide), \
225 _PERF_HW_CACHE(optstr "-store-misses", name, type, \
226 WRITE, MISS, hide), \
227 _PERF_HW_CACHE(optstr "-prefetches", name, type, \
228 PREFETCH, ACCESS, hide), \
229 _PERF_HW_CACHE(optstr "-prefetch-misses", name, type, \
230 PREFETCH, MISS, hide)
231
232 static
233 const struct ctx_opts {
234 char *symbol;
235 enum context_type ctx_type;
236 int hide_help; /* Hide from --help */
237 union {
238 struct {
239 uint32_t type;
240 uint64_t config;
241 } perf;
242 struct {
243 char *provider_name;
244 char *ctx_name;
245 } app_ctx;
246 } u;
247 } ctx_opts[] = {
248 { "pid", CONTEXT_PID },
249 { "procname", CONTEXT_PROCNAME },
250 { "prio", CONTEXT_PRIO },
251 { "nice", CONTEXT_NICE },
252 { "vpid", CONTEXT_VPID },
253 { "tid", CONTEXT_TID },
254 { "pthread_id", CONTEXT_PTHREAD_ID },
255 { "vtid", CONTEXT_VTID },
256 { "ppid", CONTEXT_PPID },
257 { "vppid", CONTEXT_VPPID },
258 { "hostname", CONTEXT_HOSTNAME },
259 { "ip", CONTEXT_IP },
260 { "interruptible", CONTEXT_INTERRUPTIBLE },
261 { "preemptible", CONTEXT_PREEMPTIBLE },
262 { "need_reschedule", CONTEXT_NEED_RESCHEDULE },
263 { "migratable", CONTEXT_MIGRATABLE },
264 { "callstack-kernel", CONTEXT_CALLSTACK_KERNEL },
265 #if HAVE_MODULES_USERSPACE_CALLSTACK_CONTEXT
266 { "callstack-user", CONTEXT_CALLSTACK_USER },
267 #endif
268 { "cgroup_ns", CONTEXT_CGROUP_NS },
269 { "ipc_ns", CONTEXT_IPC_NS },
270 { "mnt_ns", CONTEXT_MNT_NS },
271 { "net_ns", CONTEXT_NET_NS },
272 { "pid_ns", CONTEXT_PID_NS },
273 { "user_ns", CONTEXT_USER_NS },
274 { "uts_ns", CONTEXT_UTS_NS },
275 { "uid", CONTEXT_UID },
276 { "euid", CONTEXT_EUID },
277 { "suid", CONTEXT_SUID },
278 { "gid", CONTEXT_GID },
279 { "egid", CONTEXT_EGID },
280 { "sgid", CONTEXT_SGID },
281 { "vuid", CONTEXT_VUID },
282 { "veuid", CONTEXT_VEUID },
283 { "vsuid", CONTEXT_VSUID },
284 { "vgid", CONTEXT_VGID },
285 { "vegid", CONTEXT_VEGID },
286 { "vsgid", CONTEXT_VSGID },
287
288 /* Perf options */
289
290 /* Perf per-CPU counters */
291 PERF_HW("perf:cpu:cpu-cycles", CPU_CYCLES,
292 CONTEXT_PERF_CPU_COUNTER, 0),
293 PERF_HW("perf:cpu:cycles", CPU_CYCLES,
294 CONTEXT_PERF_CPU_COUNTER, 0),
295 PERF_HW("perf:cpu:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
296 CONTEXT_PERF_CPU_COUNTER, 0),
297 PERF_HW("perf:cpu:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
298 CONTEXT_PERF_CPU_COUNTER, 0),
299 PERF_HW("perf:cpu:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
300 CONTEXT_PERF_CPU_COUNTER, 0),
301 PERF_HW("perf:cpu:idle-cycles-backend", STALLED_CYCLES_BACKEND,
302 CONTEXT_PERF_CPU_COUNTER, 0),
303 PERF_HW("perf:cpu:instructions", INSTRUCTIONS,
304 CONTEXT_PERF_CPU_COUNTER, 0),
305 PERF_HW("perf:cpu:cache-references", CACHE_REFERENCES,
306 CONTEXT_PERF_CPU_COUNTER, 0),
307 PERF_HW("perf:cpu:cache-misses", CACHE_MISSES,
308 CONTEXT_PERF_CPU_COUNTER, 0),
309 PERF_HW("perf:cpu:branch-instructions", BRANCH_INSTRUCTIONS,
310 CONTEXT_PERF_CPU_COUNTER, 0),
311 PERF_HW("perf:cpu:branches", BRANCH_INSTRUCTIONS,
312 CONTEXT_PERF_CPU_COUNTER, 0),
313 PERF_HW("perf:cpu:branch-misses", BRANCH_MISSES,
314 CONTEXT_PERF_CPU_COUNTER, 0),
315 PERF_HW("perf:cpu:bus-cycles", BUS_CYCLES,
316 CONTEXT_PERF_CPU_COUNTER, 0),
317
318 PERF_HW_CACHE("perf:cpu:L1-dcache", L1D,
319 CONTEXT_PERF_CPU_COUNTER, 0),
320 PERF_HW_CACHE("perf:cpu:L1-icache", L1I,
321 CONTEXT_PERF_CPU_COUNTER, 0),
322 PERF_HW_CACHE("perf:cpu:LLC", LL,
323 CONTEXT_PERF_CPU_COUNTER, 0),
324 PERF_HW_CACHE("perf:cpu:dTLB", DTLB,
325 CONTEXT_PERF_CPU_COUNTER, 0),
326 _PERF_HW_CACHE("perf:cpu:iTLB-loads", ITLB,
327 CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
328 _PERF_HW_CACHE("perf:cpu:iTLB-load-misses", ITLB,
329 CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
330 _PERF_HW_CACHE("perf:cpu:branch-loads", BPU,
331 CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
332 _PERF_HW_CACHE("perf:cpu:branch-load-misses", BPU,
333 CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
334
335 PERF_SW("perf:cpu:cpu-clock", CPU_CLOCK,
336 CONTEXT_PERF_CPU_COUNTER, 0),
337 PERF_SW("perf:cpu:task-clock", TASK_CLOCK,
338 CONTEXT_PERF_CPU_COUNTER, 0),
339 PERF_SW("perf:cpu:page-fault", PAGE_FAULTS,
340 CONTEXT_PERF_CPU_COUNTER, 0),
341 PERF_SW("perf:cpu:faults", PAGE_FAULTS,
342 CONTEXT_PERF_CPU_COUNTER, 0),
343 PERF_SW("perf:cpu:major-faults", PAGE_FAULTS_MAJ,
344 CONTEXT_PERF_CPU_COUNTER, 0),
345 PERF_SW("perf:cpu:minor-faults", PAGE_FAULTS_MIN,
346 CONTEXT_PERF_CPU_COUNTER, 0),
347 PERF_SW("perf:cpu:context-switches", CONTEXT_SWITCHES,
348 CONTEXT_PERF_CPU_COUNTER, 0),
349 PERF_SW("perf:cpu:cs", CONTEXT_SWITCHES,
350 CONTEXT_PERF_CPU_COUNTER, 0),
351 PERF_SW("perf:cpu:cpu-migrations", CPU_MIGRATIONS,
352 CONTEXT_PERF_CPU_COUNTER, 0),
353 PERF_SW("perf:cpu:migrations", CPU_MIGRATIONS,
354 CONTEXT_PERF_CPU_COUNTER, 0),
355 PERF_SW("perf:cpu:alignment-faults", ALIGNMENT_FAULTS,
356 CONTEXT_PERF_CPU_COUNTER, 0),
357 PERF_SW("perf:cpu:emulation-faults", EMULATION_FAULTS,
358 CONTEXT_PERF_CPU_COUNTER, 0),
359
360 /* Perf per-thread counters */
361 PERF_HW("perf:thread:cpu-cycles", CPU_CYCLES,
362 CONTEXT_PERF_THREAD_COUNTER, 0),
363 PERF_HW("perf:thread:cycles", CPU_CYCLES,
364 CONTEXT_PERF_THREAD_COUNTER, 0),
365 PERF_HW("perf:thread:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
366 CONTEXT_PERF_THREAD_COUNTER, 0),
367 PERF_HW("perf:thread:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
368 CONTEXT_PERF_THREAD_COUNTER, 0),
369 PERF_HW("perf:thread:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
370 CONTEXT_PERF_THREAD_COUNTER, 0),
371 PERF_HW("perf:thread:idle-cycles-backend", STALLED_CYCLES_BACKEND,
372 CONTEXT_PERF_THREAD_COUNTER, 0),
373 PERF_HW("perf:thread:instructions", INSTRUCTIONS,
374 CONTEXT_PERF_THREAD_COUNTER, 0),
375 PERF_HW("perf:thread:cache-references", CACHE_REFERENCES,
376 CONTEXT_PERF_THREAD_COUNTER, 0),
377 PERF_HW("perf:thread:cache-misses", CACHE_MISSES,
378 CONTEXT_PERF_THREAD_COUNTER, 0),
379 PERF_HW("perf:thread:branch-instructions", BRANCH_INSTRUCTIONS,
380 CONTEXT_PERF_THREAD_COUNTER, 0),
381 PERF_HW("perf:thread:branches", BRANCH_INSTRUCTIONS,
382 CONTEXT_PERF_THREAD_COUNTER, 0),
383 PERF_HW("perf:thread:branch-misses", BRANCH_MISSES,
384 CONTEXT_PERF_THREAD_COUNTER, 0),
385 PERF_HW("perf:thread:bus-cycles", BUS_CYCLES,
386 CONTEXT_PERF_THREAD_COUNTER, 0),
387
388 PERF_HW_CACHE("perf:thread:L1-dcache", L1D,
389 CONTEXT_PERF_THREAD_COUNTER, 0),
390 PERF_HW_CACHE("perf:thread:L1-icache", L1I,
391 CONTEXT_PERF_THREAD_COUNTER, 0),
392 PERF_HW_CACHE("perf:thread:LLC", LL,
393 CONTEXT_PERF_THREAD_COUNTER, 0),
394 PERF_HW_CACHE("perf:thread:dTLB", DTLB,
395 CONTEXT_PERF_THREAD_COUNTER, 0),
396 _PERF_HW_CACHE("perf:thread:iTLB-loads", ITLB,
397 CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
398 _PERF_HW_CACHE("perf:thread:iTLB-load-misses", ITLB,
399 CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
400 _PERF_HW_CACHE("perf:thread:branch-loads", BPU,
401 CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
402 _PERF_HW_CACHE("perf:thread:branch-load-misses", BPU,
403 CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
404
405 PERF_SW("perf:thread:cpu-clock", CPU_CLOCK,
406 CONTEXT_PERF_THREAD_COUNTER, 0),
407 PERF_SW("perf:thread:task-clock", TASK_CLOCK,
408 CONTEXT_PERF_THREAD_COUNTER, 0),
409 PERF_SW("perf:thread:page-fault", PAGE_FAULTS,
410 CONTEXT_PERF_THREAD_COUNTER, 0),
411 PERF_SW("perf:thread:faults", PAGE_FAULTS,
412 CONTEXT_PERF_THREAD_COUNTER, 0),
413 PERF_SW("perf:thread:major-faults", PAGE_FAULTS_MAJ,
414 CONTEXT_PERF_THREAD_COUNTER, 0),
415 PERF_SW("perf:thread:minor-faults", PAGE_FAULTS_MIN,
416 CONTEXT_PERF_THREAD_COUNTER, 0),
417 PERF_SW("perf:thread:context-switches", CONTEXT_SWITCHES,
418 CONTEXT_PERF_THREAD_COUNTER, 0),
419 PERF_SW("perf:thread:cs", CONTEXT_SWITCHES,
420 CONTEXT_PERF_THREAD_COUNTER, 0),
421 PERF_SW("perf:thread:cpu-migrations", CPU_MIGRATIONS,
422 CONTEXT_PERF_THREAD_COUNTER, 0),
423 PERF_SW("perf:thread:migrations", CPU_MIGRATIONS,
424 CONTEXT_PERF_THREAD_COUNTER, 0),
425 PERF_SW("perf:thread:alignment-faults", ALIGNMENT_FAULTS,
426 CONTEXT_PERF_THREAD_COUNTER, 0),
427 PERF_SW("perf:thread:emulation-faults", EMULATION_FAULTS,
428 CONTEXT_PERF_THREAD_COUNTER, 0),
429
430 /*
431 * Perf per-CPU counters, backward compatibilty for names.
432 * Hidden from help listing.
433 */
434 PERF_HW("perf:cpu-cycles", CPU_CYCLES,
435 CONTEXT_PERF_COUNTER, 1),
436 PERF_HW("perf:cycles", CPU_CYCLES,
437 CONTEXT_PERF_COUNTER, 1),
438 PERF_HW("perf:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
439 CONTEXT_PERF_COUNTER, 1),
440 PERF_HW("perf:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
441 CONTEXT_PERF_COUNTER, 1),
442 PERF_HW("perf:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
443 CONTEXT_PERF_COUNTER, 1),
444 PERF_HW("perf:idle-cycles-backend", STALLED_CYCLES_BACKEND,
445 CONTEXT_PERF_COUNTER, 1),
446 PERF_HW("perf:instructions", INSTRUCTIONS,
447 CONTEXT_PERF_COUNTER, 1),
448 PERF_HW("perf:cache-references", CACHE_REFERENCES,
449 CONTEXT_PERF_COUNTER, 1),
450 PERF_HW("perf:cache-misses", CACHE_MISSES,
451 CONTEXT_PERF_COUNTER, 1),
452 PERF_HW("perf:branch-instructions", BRANCH_INSTRUCTIONS,
453 CONTEXT_PERF_COUNTER, 1),
454 PERF_HW("perf:branches", BRANCH_INSTRUCTIONS,
455 CONTEXT_PERF_COUNTER, 1),
456 PERF_HW("perf:branch-misses", BRANCH_MISSES,
457 CONTEXT_PERF_COUNTER, 1),
458 PERF_HW("perf:bus-cycles", BUS_CYCLES,
459 CONTEXT_PERF_COUNTER, 1),
460
461 PERF_HW_CACHE("perf:L1-dcache", L1D,
462 CONTEXT_PERF_COUNTER, 1),
463 PERF_HW_CACHE("perf:L1-icache", L1I,
464 CONTEXT_PERF_COUNTER, 1),
465 PERF_HW_CACHE("perf:LLC", LL,
466 CONTEXT_PERF_COUNTER, 1),
467 PERF_HW_CACHE("perf:dTLB", DTLB,
468 CONTEXT_PERF_COUNTER, 1),
469 _PERF_HW_CACHE("perf:iTLB-loads", ITLB,
470 CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
471 _PERF_HW_CACHE("perf:iTLB-load-misses", ITLB,
472 CONTEXT_PERF_COUNTER, READ, MISS, 1),
473 _PERF_HW_CACHE("perf:branch-loads", BPU,
474 CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
475 _PERF_HW_CACHE("perf:branch-load-misses", BPU,
476 CONTEXT_PERF_COUNTER, READ, MISS, 1),
477
478 PERF_SW("perf:cpu-clock", CPU_CLOCK,
479 CONTEXT_PERF_COUNTER, 1),
480 PERF_SW("perf:task-clock", TASK_CLOCK,
481 CONTEXT_PERF_COUNTER, 1),
482 PERF_SW("perf:page-fault", PAGE_FAULTS,
483 CONTEXT_PERF_COUNTER, 1),
484 PERF_SW("perf:faults", PAGE_FAULTS,
485 CONTEXT_PERF_COUNTER, 1),
486 PERF_SW("perf:major-faults", PAGE_FAULTS_MAJ,
487 CONTEXT_PERF_COUNTER, 1),
488 PERF_SW("perf:minor-faults", PAGE_FAULTS_MIN,
489 CONTEXT_PERF_COUNTER, 1),
490 PERF_SW("perf:context-switches", CONTEXT_SWITCHES,
491 CONTEXT_PERF_COUNTER, 1),
492 PERF_SW("perf:cs", CONTEXT_SWITCHES,
493 CONTEXT_PERF_COUNTER, 1),
494 PERF_SW("perf:cpu-migrations", CPU_MIGRATIONS,
495 CONTEXT_PERF_COUNTER, 1),
496 PERF_SW("perf:migrations", CPU_MIGRATIONS,
497 CONTEXT_PERF_COUNTER, 1),
498 PERF_SW("perf:alignment-faults", ALIGNMENT_FAULTS,
499 CONTEXT_PERF_COUNTER, 1),
500 PERF_SW("perf:emulation-faults", EMULATION_FAULTS,
501 CONTEXT_PERF_COUNTER, 1),
502
503 { NULL, -1 }, /* Closure */
504 };
505
506 #undef PERF_HW_CACHE
507 #undef _PERF_HW_CACHE
508 #undef PERF_SW
509 #undef PERF_HW
510
511 /*
512 * Context type for command line option parsing.
513 */
514 struct ctx_type {
515 struct ctx_opts *opt;
516 struct cds_list_head list;
517 };
518
519 /*
520 * List of context type. Use to enable multiple context on a single command
521 * line entry.
522 */
523 struct ctx_type_list {
524 struct cds_list_head head;
525 } ctx_type_list = {
526 .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
527 };
528
529
530
531 /*
532 * Find context numerical value from string.
533 *
534 * Return -1 if not found.
535 */
536 static int find_ctx_type_idx(const char *opt)
537 {
538 int ret, i = 0;
539
540 while (ctx_opts[i].symbol != NULL) {
541 if (strcmp(opt, ctx_opts[i].symbol) == 0) {
542 ret = i;
543 goto end;
544 }
545 i++;
546 }
547
548 ret = -1;
549 end:
550 return ret;
551 }
552
553 static
554 enum lttng_domain_type get_domain(void)
555 {
556 if (opt_kernel) {
557 return LTTNG_DOMAIN_KERNEL;
558 } else if (opt_userspace) {
559 return LTTNG_DOMAIN_UST;
560 } else if (opt_jul) {
561 return LTTNG_DOMAIN_JUL;
562 } else if (opt_log4j) {
563 return LTTNG_DOMAIN_LOG4J;
564 } else {
565 assert(0);
566 }
567 }
568
569 static
570 int mi_open(void)
571 {
572 int ret;
573
574 /* MI check */
575 if (!lttng_opt_mi) {
576 ret = 0;
577 goto end;
578 }
579
580 ret = fileno(stdout);
581 if (ret < 0) {
582 PERROR("Unable to retrieve fileno of stdout");
583 ret = CMD_ERROR;
584 goto end;
585 }
586
587 writer = mi_lttng_writer_create(ret, lttng_opt_mi);
588 if (!writer) {
589 ret = CMD_ERROR;
590 goto end;
591 }
592
593 /* Open command element */
594 ret = mi_lttng_writer_command_open(writer,
595 mi_lttng_element_command_add_context);
596 if (ret) {
597 ret = CMD_ERROR;
598 goto end;
599 }
600
601 /* Open output element */
602 ret = mi_lttng_writer_open_element(writer,
603 mi_lttng_element_command_output);
604 if (ret) {
605 ret = CMD_ERROR;
606 goto end;
607 }
608 end:
609 return ret;
610 }
611
612 static
613 int mi_close(enum cmd_error_code success)
614 {
615 int ret;
616
617 /* MI closing */
618 if (!lttng_opt_mi) {
619 ret = 0;
620 goto end;
621 }
622 /* Close output element */
623 ret = mi_lttng_writer_close_element(writer);
624 if (ret) {
625 ret = CMD_ERROR;
626 goto end;
627 }
628
629 /* Success ? */
630 ret = mi_lttng_writer_write_element_bool(writer,
631 mi_lttng_element_command_success, !success);
632 if (ret) {
633 ret = CMD_ERROR;
634 goto end;
635 }
636
637 /* Command element close */
638 ret = mi_lttng_writer_command_close(writer);
639 if (ret) {
640 ret = CMD_ERROR;
641 goto end;
642 }
643 end:
644 return ret;
645 }
646
647 static
648 void populate_context(struct lttng_event_context *context,
649 const struct ctx_opts *opt)
650 {
651 char *ptr;
652
653 context->ctx = (enum lttng_event_context_type) opt->ctx_type;
654 switch (context->ctx) {
655 case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
656 case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
657 case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
658 context->u.perf_counter.type = opt->u.perf.type;
659 context->u.perf_counter.config = opt->u.perf.config;
660 strncpy(context->u.perf_counter.name, opt->symbol,
661 LTTNG_SYMBOL_NAME_LEN);
662 context->u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
663 /* Replace : and - by _ */
664 while ((ptr = strchr(context->u.perf_counter.name, '-')) != NULL) {
665 *ptr = '_';
666 }
667 while ((ptr = strchr(context->u.perf_counter.name, ':')) != NULL) {
668 *ptr = '_';
669 }
670 break;
671 case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
672 context->u.app_ctx.provider_name =
673 opt->u.app_ctx.provider_name;
674 context->u.app_ctx.ctx_name =
675 opt->u.app_ctx.ctx_name;
676 break;
677 default:
678 break;
679 }
680 }
681
682 /*
683 * Pretty print context type.
684 */
685 static
686 int print_ctx_type(void)
687 {
688
689 FILE *ofp = stdout;
690 int i = 0;
691 int ret;
692 struct lttng_event_context context;
693
694 memset(&context, 0, sizeof(context));
695
696 ret = mi_open();
697 if (ret) {
698 ret = CMD_ERROR;
699 goto end;
700 }
701
702 if (lttng_opt_mi) {
703 /* Open a contexts element */
704 ret = mi_lttng_writer_open_element(writer, config_element_contexts);
705 if (ret) {
706 ret = CMD_ERROR;
707 goto end;
708 }
709 }
710
711 while (ctx_opts[i].symbol != NULL) {
712 if (!ctx_opts[i].hide_help) {
713 if (lttng_opt_mi) {
714 populate_context(&context, &ctx_opts[i]);
715 ret = mi_lttng_context(writer, &context, 1);
716 if (ret) {
717 ret = CMD_ERROR;
718 goto end;
719 }
720
721 ret = mi_lttng_writer_write_element_string(
722 writer,
723 mi_lttng_element_context_symbol,
724 ctx_opts[i].symbol);
725 if (ret) {
726 ret = CMD_ERROR;
727 goto end;
728 }
729
730 ret = mi_lttng_writer_close_element(writer);
731 if (ret) {
732 ret = CMD_ERROR;
733 goto end;
734 }
735 } else {
736 fprintf(ofp, "%s\n", ctx_opts[i].symbol);
737 }
738 }
739 i++;
740 }
741
742 if (lttng_opt_mi) {
743 /* Close contexts element */
744 ret = mi_lttng_writer_close_element(writer);
745 if (ret) {
746 goto end;
747 }
748 }
749
750 end:
751 ret = mi_close(ret);
752 if (ret) {
753 ret = CMD_ERROR;
754 }
755 return ret;
756 }
757
758 /*
759 * Add context to channel or event.
760 */
761 static int add_context(char *session_name)
762 {
763 int ret = CMD_SUCCESS, warn = 0, success = 0;
764 struct lttng_event_context context;
765 struct lttng_domain dom;
766 struct ctx_type *type;
767
768 memset(&context, 0, sizeof(context));
769 memset(&dom, 0, sizeof(dom));
770
771 dom.type = get_domain();
772 handle = lttng_create_handle(session_name, &dom);
773 if (handle == NULL) {
774 ret = CMD_ERROR;
775 goto error;
776 }
777
778 if (lttng_opt_mi) {
779 /* Open a contexts element */
780 ret = mi_lttng_writer_open_element(writer, config_element_contexts);
781 if (ret) {
782 goto error;
783 }
784 }
785
786 /* Iterate over all the context types given */
787 cds_list_for_each_entry(type, &ctx_type_list.head, list) {
788 DBG("Adding context...");
789
790 populate_context(&context, type->opt);
791
792 if (lttng_opt_mi) {
793 /* We leave context open the update the success of the command */
794 ret = mi_lttng_context(writer, &context, 1);
795 if (ret) {
796 ret = CMD_ERROR;
797 goto error;
798 }
799
800 ret = mi_lttng_writer_write_element_string(writer,
801 mi_lttng_element_context_symbol,
802 type->opt->symbol);
803 if (ret) {
804 ret = CMD_ERROR;
805 goto error;
806 }
807 }
808
809 ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
810 if (ret < 0) {
811 ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
812 warn = 1;
813 success = 0;
814 } else {
815 if (opt_channel_name) {
816 MSG("%s context %s added to channel %s",
817 get_domain_str(dom.type), type->opt->symbol,
818 opt_channel_name);
819 } else {
820 MSG("%s context %s added to all channels",
821 get_domain_str(dom.type), type->opt->symbol);
822 }
823 success = 1;
824 }
825
826 if (lttng_opt_mi) {
827 /* Is the single operation a success ? */
828 ret = mi_lttng_writer_write_element_bool(writer,
829 mi_lttng_element_success, success);
830 if (ret) {
831 ret = CMD_ERROR;
832 goto error;
833 }
834
835 /* Close the context element */
836 ret = mi_lttng_writer_close_element(writer);
837 if (ret) {
838 ret = CMD_ERROR;
839 goto error;
840 }
841 }
842 }
843
844 if (lttng_opt_mi) {
845 /* Close contexts element */
846 ret = mi_lttng_writer_close_element(writer);
847 if (ret) {
848 goto error;
849 }
850 }
851
852 ret = CMD_SUCCESS;
853
854 error:
855 lttng_destroy_handle(handle);
856
857 /*
858 * This means that at least one add_context failed and tells the user to
859 * look on stderr for error(s).
860 */
861 if (!ret && warn) {
862 ret = CMD_WARNING;
863 }
864 return ret;
865 }
866
867 static
868 void destroy_ctx_type(struct ctx_type *type)
869 {
870 if (!type) {
871 return;
872 }
873 if (type->opt) {
874 free(type->opt->symbol);
875 }
876 free(type->opt);
877 free(type);
878 }
879
880 static
881 struct ctx_type *create_ctx_type(void)
882 {
883 struct ctx_type *type = zmalloc(sizeof(*type));
884
885 if (!type) {
886 PERROR("malloc ctx_type");
887 goto end;
888 }
889
890 type->opt = zmalloc(sizeof(*type->opt));
891 if (!type->opt) {
892 PERROR("malloc ctx_type options");
893 destroy_ctx_type(type);
894 type = NULL;
895 goto end;
896 }
897 end:
898 return type;
899 }
900
901 static
902 int find_ctx_type_perf_raw(const char *ctx, struct ctx_type *type)
903 {
904 int ret;
905 int field_pos = 0;
906 char *tmp_list, *cur_list;
907
908 cur_list = tmp_list = strdup(ctx);
909 if (!tmp_list) {
910 PERROR("strdup temp list");
911 ret = -ENOMEM;
912 goto end;
913 }
914
915 /* Looking for "perf:[cpu|thread]:raw:<mask>:<name>". */
916 for (;;) {
917 char *next;
918
919 next = strtok(cur_list, ":");
920 if (!next) {
921 break;
922 }
923 cur_list = NULL;
924 switch (field_pos) {
925 case 0:
926 if (strncmp(next, "perf", 4) != 0) {
927 ret = -1;
928 goto end;
929 }
930 break;
931 case 1:
932 if (strncmp(next, "cpu", 3) == 0) {
933 type->opt->ctx_type = CONTEXT_PERF_CPU_COUNTER;
934 } else if (strncmp(next, "thread", 4) == 0) {
935 type->opt->ctx_type = CONTEXT_PERF_THREAD_COUNTER;
936 } else {
937 ret = -1;
938 goto end;
939 }
940 break;
941 case 2:
942 if (strncmp(next, "raw", 3) != 0) {
943 ret = -1;
944 goto end;
945 }
946 break;
947 case 3:
948 {
949 char *endptr;
950
951 if (strlen(next) < 2 || next[0] != 'r') {
952 ERR("Wrong perf raw mask format: expected rNNN");
953 ret = -1;
954 goto end;
955 }
956 errno = 0;
957 type->opt->u.perf.config = strtoll(next + 1, &endptr, 16);
958 if (errno != 0 || !endptr || *endptr) {
959 ERR("Wrong perf raw mask format: expected rNNN");
960 ret = -1;
961 goto end;
962 }
963 break;
964 }
965 case 4:
966 /* name */
967 break;
968 case 5:
969 ERR("Too many ':' in perf raw format");
970 ret = -1;
971 goto end;
972 };
973 field_pos++;
974 }
975
976 if (field_pos < 5) {
977 ERR("Invalid perf counter specifier, expected a specifier of "
978 "the form perf:cpu:raw:rNNN:<name> or "
979 "perf:thread:raw:rNNN:<name>");
980 ret = -1;
981 goto end;
982 }
983
984 ret = 0;
985 goto end;
986
987 end:
988 free(tmp_list);
989 return ret;
990 }
991
992 static
993 struct ctx_type *get_context_type(const char *ctx)
994 {
995 int opt_index, ret;
996 struct ctx_type *type = NULL;
997 const char app_ctx_prefix[] = "$app.";
998 char *provider_name = NULL, *ctx_name = NULL;
999 size_t i, len, colon_pos = 0, provider_name_len, ctx_name_len;
1000
1001 if (!ctx) {
1002 goto not_found;
1003 }
1004
1005 type = create_ctx_type();
1006 if (!type) {
1007 goto not_found;
1008 }
1009
1010 /* Check if ctx matches a known static context. */
1011 opt_index = find_ctx_type_idx(ctx);
1012 if (opt_index >= 0) {
1013 *type->opt = ctx_opts[opt_index];
1014 type->opt->symbol = strdup(ctx_opts[opt_index].symbol);
1015 goto found;
1016 }
1017
1018 /* Check if ctx is a raw perf context. */
1019 ret = find_ctx_type_perf_raw(ctx, type);
1020 if (ret == 0) {
1021 type->opt->u.perf.type = PERF_TYPE_RAW;
1022 type->opt->symbol = strdup(ctx);
1023 if (!type->opt->symbol) {
1024 PERROR("Copy perf field name");
1025 goto not_found;
1026 }
1027 goto found;
1028 }
1029
1030 /*
1031 * No match found against static contexts; check if it is an app
1032 * context.
1033 */
1034 len = strlen(ctx);
1035 if (len <= sizeof(app_ctx_prefix) - 1) {
1036 goto not_found;
1037 }
1038
1039 /* String starts with $app. */
1040 if (strncmp(ctx, app_ctx_prefix, sizeof(app_ctx_prefix) - 1)) {
1041 goto not_found;
1042 }
1043
1044 /* Validate that the ':' separator is present. */
1045 for (i = sizeof(app_ctx_prefix); i < len; i++) {
1046 const char c = ctx[i];
1047
1048 if (c == ':') {
1049 colon_pos = i;
1050 break;
1051 }
1052 }
1053
1054 /*
1055 * No colon found or no ctx name ("$app.provider:") or no provider name
1056 * given ("$app.:..."), which is invalid.
1057 */
1058 if (!colon_pos || colon_pos == len ||
1059 colon_pos == sizeof(app_ctx_prefix)) {
1060 ERR("Invalid application context provided: no provider or context name provided.");
1061 goto not_found;
1062 }
1063
1064 provider_name_len = colon_pos - sizeof(app_ctx_prefix) + 2;
1065 provider_name = zmalloc(provider_name_len);
1066 if (!provider_name) {
1067 PERROR("malloc provider_name");
1068 goto not_found;
1069 }
1070 strncpy(provider_name, ctx + sizeof(app_ctx_prefix) - 1,
1071 provider_name_len - 1);
1072 type->opt->u.app_ctx.provider_name = provider_name;
1073
1074 ctx_name_len = len - colon_pos;
1075 ctx_name = zmalloc(ctx_name_len);
1076 if (!ctx_name) {
1077 PERROR("malloc ctx_name");
1078 goto not_found;
1079 }
1080 strncpy(ctx_name, ctx + colon_pos + 1, ctx_name_len - 1);
1081 type->opt->u.app_ctx.ctx_name = ctx_name;
1082 type->opt->ctx_type = CONTEXT_APP_CONTEXT;
1083 type->opt->symbol = strdup(ctx);
1084 found:
1085 return type;
1086 not_found:
1087 free(provider_name);
1088 free(ctx_name);
1089 destroy_ctx_type(type);
1090 return NULL;
1091 }
1092
1093 /*
1094 * Add context to channel or event.
1095 */
1096 int cmd_add_context(int argc, const char **argv)
1097 {
1098 int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
1099 static poptContext pc;
1100 struct ctx_type *type, *tmptype;
1101 char *session_name = NULL;
1102 const char *leftover = NULL;
1103
1104 if (argc < 2) {
1105 ret = CMD_ERROR;
1106 goto end;
1107 }
1108
1109 pc = poptGetContext(NULL, argc, argv, long_options, 0);
1110 poptReadDefaultConfig(pc, 0);
1111
1112 while ((opt = poptGetNextOpt(pc)) != -1) {
1113 switch (opt) {
1114 case OPT_HELP:
1115 SHOW_HELP();
1116 goto end;
1117 case OPT_LIST:
1118 ret = print_ctx_type();
1119 goto end;
1120 case OPT_TYPE:
1121 {
1122 type = get_context_type(opt_type);
1123 if (!type) {
1124 ERR("Unknown context type %s", opt_type);
1125 ret = CMD_FATAL;
1126 goto end;
1127 }
1128 cds_list_add_tail(&type->list, &ctx_type_list.head);
1129 break;
1130 }
1131 case OPT_USERSPACE:
1132 opt_userspace = 1;
1133 break;
1134 case OPT_JUL:
1135 opt_jul = 1;
1136 break;
1137 case OPT_LOG4J:
1138 opt_log4j = 1;
1139 break;
1140 case OPT_LIST_OPTIONS:
1141 list_cmd_options(stdout, long_options);
1142 goto end;
1143 default:
1144 ret = CMD_UNDEFINED;
1145 goto end;
1146 }
1147 }
1148
1149 leftover = poptGetArg(pc);
1150 if (leftover) {
1151 ERR("Unknown argument: %s", leftover);
1152 ret = CMD_ERROR;
1153 goto end;
1154 }
1155
1156 ret = print_missing_or_multiple_domains(opt_kernel + opt_userspace +
1157 opt_jul + opt_log4j);
1158 if (ret) {
1159 ret = CMD_ERROR;
1160 goto end;
1161 }
1162
1163 if (!opt_type) {
1164 ERR("Missing mandatory -t TYPE");
1165 ret = CMD_ERROR;
1166 goto end;
1167 }
1168
1169 if (!opt_session_name) {
1170 session_name = get_session_name();
1171 if (session_name == NULL) {
1172 ret = CMD_ERROR;
1173 goto end;
1174 }
1175 } else {
1176 session_name = opt_session_name;
1177 }
1178
1179 ret = mi_open();
1180 if (ret) {
1181 goto end;
1182 }
1183
1184 command_ret = add_context(session_name);
1185 ret = mi_close(command_ret);
1186 if (ret) {
1187 goto end;
1188 }
1189
1190 end:
1191 if (!opt_session_name) {
1192 free(session_name);
1193 }
1194
1195 /* Mi clean-up */
1196 if (writer && mi_lttng_writer_destroy(writer)) {
1197 /* Preserve original error code */
1198 ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
1199 }
1200
1201 /* Cleanup allocated memory */
1202 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
1203 destroy_ctx_type(type);
1204 }
1205
1206 /* Overwrite ret if an error occurred during add_context() */
1207 ret = command_ret ? command_ret : ret;
1208
1209 poptFreeContext(pc);
1210 return ret;
1211 }
This page took 0.089283 seconds and 4 git commands to generate.