2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
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.
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.
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.
26 #include <sys/types.h>
30 #include <urcu/list.h>
32 #include <common/mi-lttng.h>
34 #include "../command.h"
36 #define PRINT_LINE_LEN 80
38 static char *opt_channel_name
;
39 static char *opt_session_name
;
40 static int opt_kernel
;
41 static int opt_userspace
;
44 static char *opt_type
;
55 static struct lttng_handle
*handle
;
56 static struct mi_writer
*writer
;
59 * Taken from the LTTng ABI
63 CONTEXT_PERF_COUNTER
= 1, /* Backward compat. */
72 CONTEXT_PTHREAD_ID
= 10,
73 CONTEXT_HOSTNAME
= 11,
75 CONTEXT_PERF_CPU_COUNTER
= 13,
76 CONTEXT_PERF_THREAD_COUNTER
= 14,
77 CONTEXT_APP_CONTEXT
= 15,
78 CONTEXT_INTERRUPTIBLE
= 16,
79 CONTEXT_PREEMPTIBLE
= 17,
80 CONTEXT_NEED_RESCHEDULE
= 18,
81 CONTEXT_MIGRATABLE
= 19,
85 * Taken from the Perf ABI (all enum perf_*)
88 PERF_TYPE_HARDWARE
= 0,
89 PERF_TYPE_SOFTWARE
= 1,
90 PERF_TYPE_HW_CACHE
= 3,
93 enum perf_count_hard
{
94 PERF_COUNT_HW_CPU_CYCLES
= 0,
95 PERF_COUNT_HW_INSTRUCTIONS
= 1,
96 PERF_COUNT_HW_CACHE_REFERENCES
= 2,
97 PERF_COUNT_HW_CACHE_MISSES
= 3,
98 PERF_COUNT_HW_BRANCH_INSTRUCTIONS
= 4,
99 PERF_COUNT_HW_BRANCH_MISSES
= 5,
100 PERF_COUNT_HW_BUS_CYCLES
= 6,
101 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
= 7,
102 PERF_COUNT_HW_STALLED_CYCLES_BACKEND
= 8,
105 enum perf_count_soft
{
106 PERF_COUNT_SW_CPU_CLOCK
= 0,
107 PERF_COUNT_SW_TASK_CLOCK
= 1,
108 PERF_COUNT_SW_PAGE_FAULTS
= 2,
109 PERF_COUNT_SW_CONTEXT_SWITCHES
= 3,
110 PERF_COUNT_SW_CPU_MIGRATIONS
= 4,
111 PERF_COUNT_SW_PAGE_FAULTS_MIN
= 5,
112 PERF_COUNT_SW_PAGE_FAULTS_MAJ
= 6,
113 PERF_COUNT_SW_ALIGNMENT_FAULTS
= 7,
114 PERF_COUNT_SW_EMULATION_FAULTS
= 8,
118 * Generalized hardware cache events:
120 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
121 * { read, write, prefetch } x
122 * { accesses, misses }
124 enum perf_hw_cache_id
{
125 PERF_COUNT_HW_CACHE_L1D
= 0,
126 PERF_COUNT_HW_CACHE_L1I
= 1,
127 PERF_COUNT_HW_CACHE_LL
= 2,
128 PERF_COUNT_HW_CACHE_DTLB
= 3,
129 PERF_COUNT_HW_CACHE_ITLB
= 4,
130 PERF_COUNT_HW_CACHE_BPU
= 5,
132 PERF_COUNT_HW_CACHE_MAX
, /* non-ABI */
135 enum perf_hw_cache_op_id
{
136 PERF_COUNT_HW_CACHE_OP_READ
= 0,
137 PERF_COUNT_HW_CACHE_OP_WRITE
= 1,
138 PERF_COUNT_HW_CACHE_OP_PREFETCH
= 2,
140 PERF_COUNT_HW_CACHE_OP_MAX
, /* non-ABI */
143 enum perf_hw_cache_op_result_id
{
144 PERF_COUNT_HW_CACHE_RESULT_ACCESS
= 0,
145 PERF_COUNT_HW_CACHE_RESULT_MISS
= 1,
147 PERF_COUNT_HW_CACHE_RESULT_MAX
, /* non-ABI */
150 static struct poptOption long_options
[] = {
151 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
152 {"help", 'h', POPT_ARG_NONE
, 0, OPT_HELP
, 0, 0},
153 {"session", 's', POPT_ARG_STRING
, &opt_session_name
, 0, 0, 0},
154 {"channel", 'c', POPT_ARG_STRING
, &opt_channel_name
, 0, 0, 0},
155 {"kernel", 'k', POPT_ARG_VAL
, &opt_kernel
, 1, 0, 0},
156 {"userspace", 'u', POPT_ARG_NONE
, 0, OPT_USERSPACE
, 0, 0},
157 {"jul", 'j', POPT_ARG_NONE
, 0, OPT_JUL
, 0, 0},
158 {"log4j", 'l', POPT_ARG_NONE
, 0, OPT_LOG4J
, 0, 0},
159 {"type", 't', POPT_ARG_STRING
, &opt_type
, OPT_TYPE
, 0, 0},
160 {"list-options", 0, POPT_ARG_NONE
, NULL
, OPT_LIST_OPTIONS
, NULL
, NULL
},
161 {0, 0, 0, 0, 0, 0, 0}
167 #define PERF_HW(optstr, name, type, hide) \
169 optstr, type, hide, \
170 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
173 #define PERF_SW(optstr, name, type, hide) \
175 optstr, type, hide, \
176 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
179 #define _PERF_HW_CACHE(optstr, name, type, op, result, hide) \
181 optstr, type, hide, \
183 PERF_TYPE_HW_CACHE, \
184 (uint64_t) PERF_COUNT_HW_CACHE_##name \
185 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
186 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
190 #define PERF_HW_CACHE(optstr, name, type, hide) \
191 _PERF_HW_CACHE(optstr "-loads", name, type, \
192 READ, ACCESS, hide), \
193 _PERF_HW_CACHE(optstr "-load-misses", name, type, \
195 _PERF_HW_CACHE(optstr "-stores", name, type, \
196 WRITE, ACCESS, hide), \
197 _PERF_HW_CACHE(optstr "-store-misses", name, type, \
198 WRITE, MISS, hide), \
199 _PERF_HW_CACHE(optstr "-prefetches", name, type, \
200 PREFETCH, ACCESS, hide), \
201 _PERF_HW_CACHE(optstr "-prefetch-misses", name, type, \
202 PREFETCH, MISS, hide)
205 const struct ctx_opts
{
207 enum context_type ctx_type
;
208 int hide_help
; /* Hide from --help */
220 { "pid", CONTEXT_PID
},
221 { "procname", CONTEXT_PROCNAME
},
222 { "prio", CONTEXT_PRIO
},
223 { "nice", CONTEXT_NICE
},
224 { "vpid", CONTEXT_VPID
},
225 { "tid", CONTEXT_TID
},
226 { "pthread_id", CONTEXT_PTHREAD_ID
},
227 { "vtid", CONTEXT_VTID
},
228 { "ppid", CONTEXT_PPID
},
229 { "vppid", CONTEXT_VPPID
},
230 { "hostname", CONTEXT_HOSTNAME
},
231 { "ip", CONTEXT_IP
},
232 { "interruptible", CONTEXT_INTERRUPTIBLE
},
233 { "preemptible", CONTEXT_PREEMPTIBLE
},
234 { "need_reschedule", CONTEXT_NEED_RESCHEDULE
},
235 { "migratable", CONTEXT_MIGRATABLE
},
239 /* Perf per-CPU counters */
240 PERF_HW("perf:cpu:cpu-cycles", CPU_CYCLES
,
241 CONTEXT_PERF_CPU_COUNTER
, 0),
242 PERF_HW("perf:cpu:cycles", CPU_CYCLES
,
243 CONTEXT_PERF_CPU_COUNTER
, 0),
244 PERF_HW("perf:cpu:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND
,
245 CONTEXT_PERF_CPU_COUNTER
, 0),
246 PERF_HW("perf:cpu:idle-cycles-frontend", STALLED_CYCLES_FRONTEND
,
247 CONTEXT_PERF_CPU_COUNTER
, 0),
248 PERF_HW("perf:cpu:stalled-cycles-backend", STALLED_CYCLES_BACKEND
,
249 CONTEXT_PERF_CPU_COUNTER
, 0),
250 PERF_HW("perf:cpu:idle-cycles-backend", STALLED_CYCLES_BACKEND
,
251 CONTEXT_PERF_CPU_COUNTER
, 0),
252 PERF_HW("perf:cpu:instructions", INSTRUCTIONS
,
253 CONTEXT_PERF_CPU_COUNTER
, 0),
254 PERF_HW("perf:cpu:cache-references", CACHE_REFERENCES
,
255 CONTEXT_PERF_CPU_COUNTER
, 0),
256 PERF_HW("perf:cpu:cache-misses", CACHE_MISSES
,
257 CONTEXT_PERF_CPU_COUNTER
, 0),
258 PERF_HW("perf:cpu:branch-instructions", BRANCH_INSTRUCTIONS
,
259 CONTEXT_PERF_CPU_COUNTER
, 0),
260 PERF_HW("perf:cpu:branches", BRANCH_INSTRUCTIONS
,
261 CONTEXT_PERF_CPU_COUNTER
, 0),
262 PERF_HW("perf:cpu:branch-misses", BRANCH_MISSES
,
263 CONTEXT_PERF_CPU_COUNTER
, 0),
264 PERF_HW("perf:cpu:bus-cycles", BUS_CYCLES
,
265 CONTEXT_PERF_CPU_COUNTER
, 0),
267 PERF_HW_CACHE("perf:cpu:L1-dcache", L1D
,
268 CONTEXT_PERF_CPU_COUNTER
, 0),
269 PERF_HW_CACHE("perf:cpu:L1-icache", L1I
,
270 CONTEXT_PERF_CPU_COUNTER
, 0),
271 PERF_HW_CACHE("perf:cpu:LLC", LL
,
272 CONTEXT_PERF_CPU_COUNTER
, 0),
273 PERF_HW_CACHE("perf:cpu:dTLB", DTLB
,
274 CONTEXT_PERF_CPU_COUNTER
, 0),
275 _PERF_HW_CACHE("perf:cpu:iTLB-loads", ITLB
,
276 CONTEXT_PERF_CPU_COUNTER
, READ
, ACCESS
, 0),
277 _PERF_HW_CACHE("perf:cpu:iTLB-load-misses", ITLB
,
278 CONTEXT_PERF_CPU_COUNTER
, READ
, MISS
, 0),
279 _PERF_HW_CACHE("perf:cpu:branch-loads", BPU
,
280 CONTEXT_PERF_CPU_COUNTER
, READ
, ACCESS
, 0),
281 _PERF_HW_CACHE("perf:cpu:branch-load-misses", BPU
,
282 CONTEXT_PERF_CPU_COUNTER
, READ
, MISS
, 0),
284 PERF_SW("perf:cpu:cpu-clock", CPU_CLOCK
,
285 CONTEXT_PERF_CPU_COUNTER
, 0),
286 PERF_SW("perf:cpu:task-clock", TASK_CLOCK
,
287 CONTEXT_PERF_CPU_COUNTER
, 0),
288 PERF_SW("perf:cpu:page-fault", PAGE_FAULTS
,
289 CONTEXT_PERF_CPU_COUNTER
, 0),
290 PERF_SW("perf:cpu:faults", PAGE_FAULTS
,
291 CONTEXT_PERF_CPU_COUNTER
, 0),
292 PERF_SW("perf:cpu:major-faults", PAGE_FAULTS_MAJ
,
293 CONTEXT_PERF_CPU_COUNTER
, 0),
294 PERF_SW("perf:cpu:minor-faults", PAGE_FAULTS_MIN
,
295 CONTEXT_PERF_CPU_COUNTER
, 0),
296 PERF_SW("perf:cpu:context-switches", CONTEXT_SWITCHES
,
297 CONTEXT_PERF_CPU_COUNTER
, 0),
298 PERF_SW("perf:cpu:cs", CONTEXT_SWITCHES
,
299 CONTEXT_PERF_CPU_COUNTER
, 0),
300 PERF_SW("perf:cpu:cpu-migrations", CPU_MIGRATIONS
,
301 CONTEXT_PERF_CPU_COUNTER
, 0),
302 PERF_SW("perf:cpu:migrations", CPU_MIGRATIONS
,
303 CONTEXT_PERF_CPU_COUNTER
, 0),
304 PERF_SW("perf:cpu:alignment-faults", ALIGNMENT_FAULTS
,
305 CONTEXT_PERF_CPU_COUNTER
, 0),
306 PERF_SW("perf:cpu:emulation-faults", EMULATION_FAULTS
,
307 CONTEXT_PERF_CPU_COUNTER
, 0),
309 /* Perf per-thread counters */
310 PERF_HW("perf:thread:cpu-cycles", CPU_CYCLES
,
311 CONTEXT_PERF_THREAD_COUNTER
, 0),
312 PERF_HW("perf:thread:cycles", CPU_CYCLES
,
313 CONTEXT_PERF_THREAD_COUNTER
, 0),
314 PERF_HW("perf:thread:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND
,
315 CONTEXT_PERF_THREAD_COUNTER
, 0),
316 PERF_HW("perf:thread:idle-cycles-frontend", STALLED_CYCLES_FRONTEND
,
317 CONTEXT_PERF_THREAD_COUNTER
, 0),
318 PERF_HW("perf:thread:stalled-cycles-backend", STALLED_CYCLES_BACKEND
,
319 CONTEXT_PERF_THREAD_COUNTER
, 0),
320 PERF_HW("perf:thread:idle-cycles-backend", STALLED_CYCLES_BACKEND
,
321 CONTEXT_PERF_THREAD_COUNTER
, 0),
322 PERF_HW("perf:thread:instructions", INSTRUCTIONS
,
323 CONTEXT_PERF_THREAD_COUNTER
, 0),
324 PERF_HW("perf:thread:cache-references", CACHE_REFERENCES
,
325 CONTEXT_PERF_THREAD_COUNTER
, 0),
326 PERF_HW("perf:thread:cache-misses", CACHE_MISSES
,
327 CONTEXT_PERF_THREAD_COUNTER
, 0),
328 PERF_HW("perf:thread:branch-instructions", BRANCH_INSTRUCTIONS
,
329 CONTEXT_PERF_THREAD_COUNTER
, 0),
330 PERF_HW("perf:thread:branches", BRANCH_INSTRUCTIONS
,
331 CONTEXT_PERF_THREAD_COUNTER
, 0),
332 PERF_HW("perf:thread:branch-misses", BRANCH_MISSES
,
333 CONTEXT_PERF_THREAD_COUNTER
, 0),
334 PERF_HW("perf:thread:bus-cycles", BUS_CYCLES
,
335 CONTEXT_PERF_THREAD_COUNTER
, 0),
337 PERF_HW_CACHE("perf:thread:L1-dcache", L1D
,
338 CONTEXT_PERF_THREAD_COUNTER
, 0),
339 PERF_HW_CACHE("perf:thread:L1-icache", L1I
,
340 CONTEXT_PERF_THREAD_COUNTER
, 0),
341 PERF_HW_CACHE("perf:thread:LLC", LL
,
342 CONTEXT_PERF_THREAD_COUNTER
, 0),
343 PERF_HW_CACHE("perf:thread:dTLB", DTLB
,
344 CONTEXT_PERF_THREAD_COUNTER
, 0),
345 _PERF_HW_CACHE("perf:thread:iTLB-loads", ITLB
,
346 CONTEXT_PERF_THREAD_COUNTER
, READ
, ACCESS
, 0),
347 _PERF_HW_CACHE("perf:thread:iTLB-load-misses", ITLB
,
348 CONTEXT_PERF_THREAD_COUNTER
, READ
, MISS
, 0),
349 _PERF_HW_CACHE("perf:thread:branch-loads", BPU
,
350 CONTEXT_PERF_THREAD_COUNTER
, READ
, ACCESS
, 0),
351 _PERF_HW_CACHE("perf:thread:branch-load-misses", BPU
,
352 CONTEXT_PERF_THREAD_COUNTER
, READ
, MISS
, 0),
354 PERF_SW("perf:thread:cpu-clock", CPU_CLOCK
,
355 CONTEXT_PERF_THREAD_COUNTER
, 0),
356 PERF_SW("perf:thread:task-clock", TASK_CLOCK
,
357 CONTEXT_PERF_THREAD_COUNTER
, 0),
358 PERF_SW("perf:thread:page-fault", PAGE_FAULTS
,
359 CONTEXT_PERF_THREAD_COUNTER
, 0),
360 PERF_SW("perf:thread:faults", PAGE_FAULTS
,
361 CONTEXT_PERF_THREAD_COUNTER
, 0),
362 PERF_SW("perf:thread:major-faults", PAGE_FAULTS_MAJ
,
363 CONTEXT_PERF_THREAD_COUNTER
, 0),
364 PERF_SW("perf:thread:minor-faults", PAGE_FAULTS_MIN
,
365 CONTEXT_PERF_THREAD_COUNTER
, 0),
366 PERF_SW("perf:thread:context-switches", CONTEXT_SWITCHES
,
367 CONTEXT_PERF_THREAD_COUNTER
, 0),
368 PERF_SW("perf:thread:cs", CONTEXT_SWITCHES
,
369 CONTEXT_PERF_THREAD_COUNTER
, 0),
370 PERF_SW("perf:thread:cpu-migrations", CPU_MIGRATIONS
,
371 CONTEXT_PERF_THREAD_COUNTER
, 0),
372 PERF_SW("perf:thread:migrations", CPU_MIGRATIONS
,
373 CONTEXT_PERF_THREAD_COUNTER
, 0),
374 PERF_SW("perf:thread:alignment-faults", ALIGNMENT_FAULTS
,
375 CONTEXT_PERF_THREAD_COUNTER
, 0),
376 PERF_SW("perf:thread:emulation-faults", EMULATION_FAULTS
,
377 CONTEXT_PERF_THREAD_COUNTER
, 0),
380 * Perf per-CPU counters, backward compatibilty for names.
381 * Hidden from help listing.
383 PERF_HW("perf:cpu-cycles", CPU_CYCLES
,
384 CONTEXT_PERF_COUNTER
, 1),
385 PERF_HW("perf:cycles", CPU_CYCLES
,
386 CONTEXT_PERF_COUNTER
, 1),
387 PERF_HW("perf:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND
,
388 CONTEXT_PERF_COUNTER
, 1),
389 PERF_HW("perf:idle-cycles-frontend", STALLED_CYCLES_FRONTEND
,
390 CONTEXT_PERF_COUNTER
, 1),
391 PERF_HW("perf:stalled-cycles-backend", STALLED_CYCLES_BACKEND
,
392 CONTEXT_PERF_COUNTER
, 1),
393 PERF_HW("perf:idle-cycles-backend", STALLED_CYCLES_BACKEND
,
394 CONTEXT_PERF_COUNTER
, 1),
395 PERF_HW("perf:instructions", INSTRUCTIONS
,
396 CONTEXT_PERF_COUNTER
, 1),
397 PERF_HW("perf:cache-references", CACHE_REFERENCES
,
398 CONTEXT_PERF_COUNTER
, 1),
399 PERF_HW("perf:cache-misses", CACHE_MISSES
,
400 CONTEXT_PERF_COUNTER
, 1),
401 PERF_HW("perf:branch-instructions", BRANCH_INSTRUCTIONS
,
402 CONTEXT_PERF_COUNTER
, 1),
403 PERF_HW("perf:branches", BRANCH_INSTRUCTIONS
,
404 CONTEXT_PERF_COUNTER
, 1),
405 PERF_HW("perf:branch-misses", BRANCH_MISSES
,
406 CONTEXT_PERF_COUNTER
, 1),
407 PERF_HW("perf:bus-cycles", BUS_CYCLES
,
408 CONTEXT_PERF_COUNTER
, 1),
410 PERF_HW_CACHE("perf:L1-dcache", L1D
,
411 CONTEXT_PERF_COUNTER
, 1),
412 PERF_HW_CACHE("perf:L1-icache", L1I
,
413 CONTEXT_PERF_COUNTER
, 1),
414 PERF_HW_CACHE("perf:LLC", LL
,
415 CONTEXT_PERF_COUNTER
, 1),
416 PERF_HW_CACHE("perf:dTLB", DTLB
,
417 CONTEXT_PERF_COUNTER
, 1),
418 _PERF_HW_CACHE("perf:iTLB-loads", ITLB
,
419 CONTEXT_PERF_COUNTER
, READ
, ACCESS
, 1),
420 _PERF_HW_CACHE("perf:iTLB-load-misses", ITLB
,
421 CONTEXT_PERF_COUNTER
, READ
, MISS
, 1),
422 _PERF_HW_CACHE("perf:branch-loads", BPU
,
423 CONTEXT_PERF_COUNTER
, READ
, ACCESS
, 1),
424 _PERF_HW_CACHE("perf:branch-load-misses", BPU
,
425 CONTEXT_PERF_COUNTER
, READ
, MISS
, 1),
427 PERF_SW("perf:cpu-clock", CPU_CLOCK
,
428 CONTEXT_PERF_COUNTER
, 1),
429 PERF_SW("perf:task-clock", TASK_CLOCK
,
430 CONTEXT_PERF_COUNTER
, 1),
431 PERF_SW("perf:page-fault", PAGE_FAULTS
,
432 CONTEXT_PERF_COUNTER
, 1),
433 PERF_SW("perf:faults", PAGE_FAULTS
,
434 CONTEXT_PERF_COUNTER
, 1),
435 PERF_SW("perf:major-faults", PAGE_FAULTS_MAJ
,
436 CONTEXT_PERF_COUNTER
, 1),
437 PERF_SW("perf:minor-faults", PAGE_FAULTS_MIN
,
438 CONTEXT_PERF_COUNTER
, 1),
439 PERF_SW("perf:context-switches", CONTEXT_SWITCHES
,
440 CONTEXT_PERF_COUNTER
, 1),
441 PERF_SW("perf:cs", CONTEXT_SWITCHES
,
442 CONTEXT_PERF_COUNTER
, 1),
443 PERF_SW("perf:cpu-migrations", CPU_MIGRATIONS
,
444 CONTEXT_PERF_COUNTER
, 1),
445 PERF_SW("perf:migrations", CPU_MIGRATIONS
,
446 CONTEXT_PERF_COUNTER
, 1),
447 PERF_SW("perf:alignment-faults", ALIGNMENT_FAULTS
,
448 CONTEXT_PERF_COUNTER
, 1),
449 PERF_SW("perf:emulation-faults", EMULATION_FAULTS
,
450 CONTEXT_PERF_COUNTER
, 1),
452 { NULL
, -1 }, /* Closure */
456 #undef _PERF_HW_CACHE
461 * Context type for command line option parsing.
464 struct ctx_opts
*opt
;
465 struct cds_list_head list
;
469 * List of context type. Use to enable multiple context on a single command
472 struct ctx_type_list
{
473 struct cds_list_head head
;
475 .head
= CDS_LIST_HEAD_INIT(ctx_type_list
.head
),
479 * Pretty print context type.
481 static void print_ctx_type(FILE *ofp
)
483 const char *indent
= " ";
484 int indent_len
= strlen(indent
);
487 fprintf(ofp
, "%s", indent
);
489 while (ctx_opts
[i
].symbol
!= NULL
) {
490 if (!ctx_opts
[i
].hide_help
) {
491 if (len
> indent_len
) {
492 if (len
+ strlen(ctx_opts
[i
].symbol
) + 2
495 fprintf(ofp
, "%s", indent
);
498 len
+= fprintf(ofp
, ", ");
501 len
+= fprintf(ofp
, "%s", ctx_opts
[i
].symbol
);
510 static void usage(FILE *ofp
)
512 fprintf(ofp
, "usage: lttng add-context -t TYPE [-k|-u] [OPTIONS]\n");
514 fprintf(ofp
, "If no channel is given (-c), the context is added to\n");
515 fprintf(ofp
, "all channels.\n");
517 fprintf(ofp
, "Otherwise the context is added only to the channel (-c).\n");
519 fprintf(ofp
, "Exactly one domain (-k or -u) must be specified.\n");
521 fprintf(ofp
, "Options:\n");
522 fprintf(ofp
, " -h, --help Show this help\n");
523 fprintf(ofp
, " --list-options Simple listing of options\n");
524 fprintf(ofp
, " -s, --session NAME Apply to session name\n");
525 fprintf(ofp
, " -c, --channel NAME Apply to channel\n");
526 fprintf(ofp
, " -k, --kernel Apply to the kernel tracer\n");
527 fprintf(ofp
, " -u, --userspace Apply to the user-space tracer\n");
528 fprintf(ofp
, " -j, --jul Apply to Java application using JUL\n");
529 fprintf(ofp
, " -l, --log4j Apply for Java application using LOG4j\n");
531 fprintf(ofp
, "Context:\n");
532 fprintf(ofp
, " -t, --type TYPE Context type. You can repeat that option on\n");
533 fprintf(ofp
, " the command line to specify multiple contexts at once.\n");
534 fprintf(ofp
, " (--kernel preempts --userspace)\n");
535 fprintf(ofp
, " TYPE can be one of the strings below:\n");
538 fprintf(ofp
, "Note that the vpid, vppid and vtid context types represent the virtual process id,\n"
539 "virtual parent process id and virtual thread id as seen from the current execution context\n"
540 "as opposed to the pid, ppid and tid which are kernel internal data structures.\n\n");
541 fprintf(ofp
, "Example:\n");
542 fprintf(ofp
, "This command will add the context information 'prio' and two per-cpu\n"
543 "perf counters (hardware branch misses and cache misses), to all channels\n"
544 "in the trace data output:\n");
545 fprintf(ofp
, "# lttng add-context -k -t prio -t perf:cpu:branch-misses -t perf:cpu:cache-misses\n");
550 * Find context numerical value from string.
552 * Return -1 if not found.
554 static int find_ctx_type_idx(const char *opt
)
558 while (ctx_opts
[i
].symbol
!= NULL
) {
559 if (strcmp(opt
, ctx_opts
[i
].symbol
) == 0) {
572 enum lttng_domain_type
get_domain(void)
575 return LTTNG_DOMAIN_KERNEL
;
576 } else if (opt_userspace
) {
577 return LTTNG_DOMAIN_UST
;
578 } else if (opt_jul
) {
579 return LTTNG_DOMAIN_JUL
;
580 } else if (opt_log4j
) {
581 return LTTNG_DOMAIN_LOG4J
;
588 * Add context to channel or event.
590 static int add_context(char *session_name
)
592 int ret
= CMD_SUCCESS
, warn
= 0, success
= 0;
593 struct lttng_event_context context
;
594 struct lttng_domain dom
;
595 struct ctx_type
*type
;
598 memset(&context
, 0, sizeof(context
));
599 memset(&dom
, 0, sizeof(dom
));
601 dom
.type
= get_domain();
602 handle
= lttng_create_handle(session_name
, &dom
);
603 if (handle
== NULL
) {
609 /* Open a contexts element */
610 ret
= mi_lttng_writer_open_element(writer
, config_element_contexts
);
616 /* Iterate over all the context types given */
617 cds_list_for_each_entry(type
, &ctx_type_list
.head
, list
) {
618 context
.ctx
= (enum lttng_event_context_type
) type
->opt
->ctx_type
;
619 switch (context
.ctx
) {
620 case LTTNG_EVENT_CONTEXT_PERF_COUNTER
:
621 case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER
:
622 case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER
:
623 context
.u
.perf_counter
.type
= type
->opt
->u
.perf
.type
;
624 context
.u
.perf_counter
.config
= type
->opt
->u
.perf
.config
;
625 strncpy(context
.u
.perf_counter
.name
, type
->opt
->symbol
,
626 LTTNG_SYMBOL_NAME_LEN
);
627 context
.u
.perf_counter
.name
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
628 /* Replace : and - by _ */
629 while ((ptr
= strchr(context
.u
.perf_counter
.name
, '-')) != NULL
) {
632 while ((ptr
= strchr(context
.u
.perf_counter
.name
, ':')) != NULL
) {
636 case LTTNG_EVENT_CONTEXT_APP_CONTEXT
:
637 context
.u
.app_ctx
.provider_name
=
638 type
->opt
->u
.app_ctx
.provider_name
;
639 context
.u
.app_ctx
.ctx_name
=
640 type
->opt
->u
.app_ctx
.ctx_name
;
645 DBG("Adding context...");
648 /* We leave context open the update the success of the command */
649 ret
= mi_lttng_context(writer
, &context
, 1);
656 ret
= lttng_add_context(handle
, &context
, NULL
, opt_channel_name
);
658 ERR("%s: %s", type
->opt
->symbol
, lttng_strerror(ret
));
662 if (opt_channel_name
) {
663 MSG("%s context %s added to channel %s",
664 opt_kernel
? "kernel" : "UST", type
->opt
->symbol
,
667 MSG("%s context %s added to all channels",
668 opt_kernel
? "kernel" : "UST", type
->opt
->symbol
)
674 /* Is the single operation a success ? */
675 ret
= mi_lttng_writer_write_element_bool(writer
,
676 mi_lttng_element_success
, success
);
682 /* Close the context element */
683 ret
= mi_lttng_writer_close_element(writer
);
692 /* Close contexts element */
693 ret
= mi_lttng_writer_close_element(writer
);
702 lttng_destroy_handle(handle
);
705 * This means that at least one add_context failed and tells the user to
706 * look on stderr for error(s).
715 void destroy_ctx_type(struct ctx_type
*type
)
720 free(type
->opt
->symbol
);
726 struct ctx_type
*create_ctx_type(void)
728 struct ctx_type
*type
= zmalloc(sizeof(*type
));
731 PERROR("malloc ctx_type");
735 type
->opt
= zmalloc(sizeof(*type
->opt
));
737 PERROR("malloc ctx_type options");
738 destroy_ctx_type(type
);
747 struct ctx_type
*get_context_type(const char *ctx
)
750 struct ctx_type
*type
= NULL
;
751 const char app_ctx_prefix
[] = "$app.";
752 char *provider_name
= NULL
, *ctx_name
= NULL
;
753 size_t i
, len
, colon_pos
= 0, provider_name_len
, ctx_name_len
;
759 type
= create_ctx_type();
764 /* Check if ctx matches a known static context. */
765 opt_index
= find_ctx_type_idx(ctx
);
766 if (opt_index
>= 0) {
767 *type
->opt
= ctx_opts
[opt_index
];
768 type
->opt
->symbol
= strdup(ctx_opts
[opt_index
].symbol
);
773 * No match found against static contexts; check if it is an app
777 if (len
<= sizeof(app_ctx_prefix
) - 1) {
781 /* String starts with $app. */
782 if (strncmp(ctx
, app_ctx_prefix
, sizeof(app_ctx_prefix
) - 1)) {
786 /* Validate that the ':' separator is present. */
787 for (i
= sizeof(app_ctx_prefix
); i
< len
; i
++) {
788 const char c
= ctx
[i
];
797 * No colon found or no ctx name ("$app.provider:") or no provider name
798 * given ("$app.:..."), which is invalid.
800 if (!colon_pos
|| colon_pos
== len
||
801 colon_pos
== sizeof(app_ctx_prefix
)) {
802 ERR("Invalid application context provided: no provider or context name provided.");
806 provider_name_len
= colon_pos
- sizeof(app_ctx_prefix
) + 2;
807 provider_name
= zmalloc(provider_name_len
);
808 if (!provider_name
) {
809 PERROR("malloc provider_name");
812 strncpy(provider_name
, ctx
+ sizeof(app_ctx_prefix
) - 1,
813 provider_name_len
- 1);
814 type
->opt
->u
.app_ctx
.provider_name
= provider_name
;
816 ctx_name_len
= len
- colon_pos
;
817 ctx_name
= zmalloc(ctx_name_len
);
819 PERROR("malloc ctx_name");
822 strncpy(ctx_name
, ctx
+ colon_pos
+ 1, ctx_name_len
- 1);
823 type
->opt
->u
.app_ctx
.ctx_name
= ctx_name
;
824 type
->opt
->ctx_type
= CONTEXT_APP_CONTEXT
;
825 type
->opt
->symbol
= strdup(ctx
);
831 destroy_ctx_type(type
);
836 * Add context to channel or event.
838 int cmd_add_context(int argc
, const char **argv
)
840 int opt
, ret
= CMD_SUCCESS
, command_ret
= CMD_SUCCESS
;
842 static poptContext pc
;
843 struct ctx_type
*type
, *tmptype
;
844 char *session_name
= NULL
;
852 pc
= poptGetContext(NULL
, argc
, argv
, long_options
, 0);
853 poptReadDefaultConfig(pc
, 0);
855 while ((opt
= poptGetNextOpt(pc
)) != -1) {
862 type
= get_context_type(opt_type
);
864 ERR("Unknown context type %s", opt_type
);
868 cds_list_add_tail(&type
->list
, &ctx_type_list
.head
);
880 case OPT_LIST_OPTIONS
:
881 list_cmd_options(stdout
, long_options
);
890 ret
= print_missing_or_multiple_domains(opt_kernel
+ opt_userspace
+
891 opt_jul
+ opt_log4j
);
898 ERR("Missing mandatory -t TYPE");
904 if (!opt_session_name
) {
905 session_name
= get_session_name();
906 if (session_name
== NULL
) {
911 session_name
= opt_session_name
;
916 writer
= mi_lttng_writer_create(fileno(stdout
), lttng_opt_mi
);
918 ret
= -LTTNG_ERR_NOMEM
;
922 /* Open command element */
923 ret
= mi_lttng_writer_command_open(writer
,
924 mi_lttng_element_command_add_context
);
930 /* Open output element */
931 ret
= mi_lttng_writer_open_element(writer
,
932 mi_lttng_element_command_output
);
939 command_ret
= add_context(session_name
);
946 /* Close output element */
947 ret
= mi_lttng_writer_close_element(writer
);
954 ret
= mi_lttng_writer_write_element_bool(writer
,
955 mi_lttng_element_command_success
, success
);
961 /* Command element close */
962 ret
= mi_lttng_writer_command_close(writer
);
970 if (!opt_session_name
) {
975 if (writer
&& mi_lttng_writer_destroy(writer
)) {
976 /* Preserve original error code */
977 ret
= ret
? ret
: LTTNG_ERR_MI_IO_FAIL
;
980 /* Cleanup allocated memory */
981 cds_list_for_each_entry_safe(type
, tmptype
, &ctx_type_list
.head
, list
) {
982 destroy_ctx_type(type
);
985 /* Overwrite ret if an error occurred during add_context() */
986 ret
= command_ret
? command_ret
: ret
;