2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
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.
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.
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.
25 #include <sys/types.h>
29 #include <urcu/list.h>
31 #include <common/mi-lttng.h>
33 #include "../command.h"
35 #define PRINT_LINE_LEN 80
37 static char *opt_channel_name
;
38 static char *opt_session_name
;
39 static int opt_kernel
;
40 static int opt_userspace
;
41 static char *opt_type
;
44 /* Not implemented yet */
45 static char *opt_cmd_name
;
56 static struct lttng_handle
*handle
;
57 static struct mi_writer
*writer
;
60 * Taken from the LTTng ABI
64 CONTEXT_PERF_COUNTER
= 1, /* Backward compat. */
73 CONTEXT_PTHREAD_ID
= 10,
74 CONTEXT_HOSTNAME
= 11,
76 CONTEXT_PERF_CPU_COUNTER
= 13,
77 CONTEXT_PERF_THREAD_COUNTER
= 14,
81 * Taken from the Perf ABI (all enum perf_*)
84 PERF_TYPE_HARDWARE
= 0,
85 PERF_TYPE_SOFTWARE
= 1,
86 PERF_TYPE_HW_CACHE
= 3,
89 enum perf_count_hard
{
90 PERF_COUNT_HW_CPU_CYCLES
= 0,
91 PERF_COUNT_HW_INSTRUCTIONS
= 1,
92 PERF_COUNT_HW_CACHE_REFERENCES
= 2,
93 PERF_COUNT_HW_CACHE_MISSES
= 3,
94 PERF_COUNT_HW_BRANCH_INSTRUCTIONS
= 4,
95 PERF_COUNT_HW_BRANCH_MISSES
= 5,
96 PERF_COUNT_HW_BUS_CYCLES
= 6,
97 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
= 7,
98 PERF_COUNT_HW_STALLED_CYCLES_BACKEND
= 8,
101 enum perf_count_soft
{
102 PERF_COUNT_SW_CPU_CLOCK
= 0,
103 PERF_COUNT_SW_TASK_CLOCK
= 1,
104 PERF_COUNT_SW_PAGE_FAULTS
= 2,
105 PERF_COUNT_SW_CONTEXT_SWITCHES
= 3,
106 PERF_COUNT_SW_CPU_MIGRATIONS
= 4,
107 PERF_COUNT_SW_PAGE_FAULTS_MIN
= 5,
108 PERF_COUNT_SW_PAGE_FAULTS_MAJ
= 6,
109 PERF_COUNT_SW_ALIGNMENT_FAULTS
= 7,
110 PERF_COUNT_SW_EMULATION_FAULTS
= 8,
114 * Generalized hardware cache events:
116 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
117 * { read, write, prefetch } x
118 * { accesses, misses }
120 enum perf_hw_cache_id
{
121 PERF_COUNT_HW_CACHE_L1D
= 0,
122 PERF_COUNT_HW_CACHE_L1I
= 1,
123 PERF_COUNT_HW_CACHE_LL
= 2,
124 PERF_COUNT_HW_CACHE_DTLB
= 3,
125 PERF_COUNT_HW_CACHE_ITLB
= 4,
126 PERF_COUNT_HW_CACHE_BPU
= 5,
128 PERF_COUNT_HW_CACHE_MAX
, /* non-ABI */
131 enum perf_hw_cache_op_id
{
132 PERF_COUNT_HW_CACHE_OP_READ
= 0,
133 PERF_COUNT_HW_CACHE_OP_WRITE
= 1,
134 PERF_COUNT_HW_CACHE_OP_PREFETCH
= 2,
136 PERF_COUNT_HW_CACHE_OP_MAX
, /* non-ABI */
139 enum perf_hw_cache_op_result_id
{
140 PERF_COUNT_HW_CACHE_RESULT_ACCESS
= 0,
141 PERF_COUNT_HW_CACHE_RESULT_MISS
= 1,
143 PERF_COUNT_HW_CACHE_RESULT_MAX
, /* non-ABI */
146 static struct poptOption long_options
[] = {
147 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
148 {"help", 'h', POPT_ARG_NONE
, 0, OPT_HELP
, 0, 0},
149 {"session", 's', POPT_ARG_STRING
, &opt_session_name
, 0, 0, 0},
150 {"channel", 'c', POPT_ARG_STRING
, &opt_channel_name
, 0, 0, 0},
151 {"kernel", 'k', POPT_ARG_VAL
, &opt_kernel
, 1, 0, 0},
152 {"userspace", 'u', POPT_ARG_NONE
, 0, OPT_USERSPACE
, 0, 0},
153 {"type", 't', POPT_ARG_STRING
, &opt_type
, OPT_TYPE
, 0, 0},
154 {"list-options", 0, POPT_ARG_NONE
, NULL
, OPT_LIST_OPTIONS
, NULL
, NULL
},
155 {0, 0, 0, 0, 0, 0, 0}
161 #define PERF_HW(optstr, name, type, hide) \
163 optstr, type, hide, \
164 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
167 #define PERF_SW(optstr, name, type, hide) \
169 optstr, type, hide, \
170 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
173 #define _PERF_HW_CACHE(optstr, name, type, op, result, hide) \
175 optstr, type, hide, \
177 PERF_TYPE_HW_CACHE, \
178 (uint64_t) PERF_COUNT_HW_CACHE_##name \
179 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
180 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
184 #define PERF_HW_CACHE(optstr, name, type, hide) \
185 _PERF_HW_CACHE(optstr "-loads", name, type, \
186 READ, ACCESS, hide), \
187 _PERF_HW_CACHE(optstr "-load-misses", name, type, \
189 _PERF_HW_CACHE(optstr "-stores", name, type, \
190 WRITE, ACCESS, hide), \
191 _PERF_HW_CACHE(optstr "-store-misses", name, type, \
192 WRITE, MISS, hide), \
193 _PERF_HW_CACHE(optstr "-prefetches", name, type, \
194 PREFETCH, ACCESS, hide), \
195 _PERF_HW_CACHE(optstr "-prefetch-misses", name, type, \
196 PREFETCH, MISS, hide)
199 const struct ctx_opts
{
201 enum context_type ctx_type
;
202 int hide_help
; /* Hide from --help */
210 { "pid", CONTEXT_PID
},
211 { "procname", CONTEXT_PROCNAME
},
212 { "prio", CONTEXT_PRIO
},
213 { "nice", CONTEXT_NICE
},
214 { "vpid", CONTEXT_VPID
},
215 { "tid", CONTEXT_TID
},
216 { "pthread_id", CONTEXT_PTHREAD_ID
},
217 { "vtid", CONTEXT_VTID
},
218 { "ppid", CONTEXT_PPID
},
219 { "vppid", CONTEXT_VPPID
},
220 { "hostname", CONTEXT_HOSTNAME
},
221 { "ip", CONTEXT_IP
},
225 /* Perf per-CPU counters */
226 PERF_HW("perf:cpu:cpu-cycles", CPU_CYCLES
,
227 CONTEXT_PERF_CPU_COUNTER
, 0),
228 PERF_HW("perf:cpu:cycles", CPU_CYCLES
,
229 CONTEXT_PERF_CPU_COUNTER
, 0),
230 PERF_HW("perf:cpu:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND
,
231 CONTEXT_PERF_CPU_COUNTER
, 0),
232 PERF_HW("perf:cpu:idle-cycles-frontend", STALLED_CYCLES_FRONTEND
,
233 CONTEXT_PERF_CPU_COUNTER
, 0),
234 PERF_HW("perf:cpu:stalled-cycles-backend", STALLED_CYCLES_BACKEND
,
235 CONTEXT_PERF_CPU_COUNTER
, 0),
236 PERF_HW("perf:cpu:idle-cycles-backend", STALLED_CYCLES_BACKEND
,
237 CONTEXT_PERF_CPU_COUNTER
, 0),
238 PERF_HW("perf:cpu:instructions", INSTRUCTIONS
,
239 CONTEXT_PERF_CPU_COUNTER
, 0),
240 PERF_HW("perf:cpu:cache-references", CACHE_REFERENCES
,
241 CONTEXT_PERF_CPU_COUNTER
, 0),
242 PERF_HW("perf:cpu:cache-misses", CACHE_MISSES
,
243 CONTEXT_PERF_CPU_COUNTER
, 0),
244 PERF_HW("perf:cpu:branch-instructions", BRANCH_INSTRUCTIONS
,
245 CONTEXT_PERF_CPU_COUNTER
, 0),
246 PERF_HW("perf:cpu:branches", BRANCH_INSTRUCTIONS
,
247 CONTEXT_PERF_CPU_COUNTER
, 0),
248 PERF_HW("perf:cpu:branch-misses", BRANCH_MISSES
,
249 CONTEXT_PERF_CPU_COUNTER
, 0),
250 PERF_HW("perf:cpu:bus-cycles", BUS_CYCLES
,
251 CONTEXT_PERF_CPU_COUNTER
, 0),
253 PERF_HW_CACHE("perf:cpu:L1-dcache", L1D
,
254 CONTEXT_PERF_CPU_COUNTER
, 0),
255 PERF_HW_CACHE("perf:cpu:L1-icache", L1I
,
256 CONTEXT_PERF_CPU_COUNTER
, 0),
257 PERF_HW_CACHE("perf:cpu:LLC", LL
,
258 CONTEXT_PERF_CPU_COUNTER
, 0),
259 PERF_HW_CACHE("perf:cpu:dTLB", DTLB
,
260 CONTEXT_PERF_CPU_COUNTER
, 0),
261 _PERF_HW_CACHE("perf:cpu:iTLB-loads", ITLB
,
262 CONTEXT_PERF_CPU_COUNTER
, READ
, ACCESS
, 0),
263 _PERF_HW_CACHE("perf:cpu:iTLB-load-misses", ITLB
,
264 CONTEXT_PERF_CPU_COUNTER
, READ
, MISS
, 0),
265 _PERF_HW_CACHE("perf:cpu:branch-loads", BPU
,
266 CONTEXT_PERF_CPU_COUNTER
, READ
, ACCESS
, 0),
267 _PERF_HW_CACHE("perf:cpu:branch-load-misses", BPU
,
268 CONTEXT_PERF_CPU_COUNTER
, READ
, MISS
, 0),
270 PERF_SW("perf:cpu:cpu-clock", CPU_CLOCK
,
271 CONTEXT_PERF_CPU_COUNTER
, 0),
272 PERF_SW("perf:cpu:task-clock", TASK_CLOCK
,
273 CONTEXT_PERF_CPU_COUNTER
, 0),
274 PERF_SW("perf:cpu:page-fault", PAGE_FAULTS
,
275 CONTEXT_PERF_CPU_COUNTER
, 0),
276 PERF_SW("perf:cpu:faults", PAGE_FAULTS
,
277 CONTEXT_PERF_CPU_COUNTER
, 0),
278 PERF_SW("perf:cpu:major-faults", PAGE_FAULTS_MAJ
,
279 CONTEXT_PERF_CPU_COUNTER
, 0),
280 PERF_SW("perf:cpu:minor-faults", PAGE_FAULTS_MIN
,
281 CONTEXT_PERF_CPU_COUNTER
, 0),
282 PERF_SW("perf:cpu:context-switches", CONTEXT_SWITCHES
,
283 CONTEXT_PERF_CPU_COUNTER
, 0),
284 PERF_SW("perf:cpu:cs", CONTEXT_SWITCHES
,
285 CONTEXT_PERF_CPU_COUNTER
, 0),
286 PERF_SW("perf:cpu:cpu-migrations", CPU_MIGRATIONS
,
287 CONTEXT_PERF_CPU_COUNTER
, 0),
288 PERF_SW("perf:cpu:migrations", CPU_MIGRATIONS
,
289 CONTEXT_PERF_CPU_COUNTER
, 0),
290 PERF_SW("perf:cpu:alignment-faults", ALIGNMENT_FAULTS
,
291 CONTEXT_PERF_CPU_COUNTER
, 0),
292 PERF_SW("perf:cpu:emulation-faults", EMULATION_FAULTS
,
293 CONTEXT_PERF_CPU_COUNTER
, 0),
295 /* Perf per-thread counters */
296 PERF_HW("perf:thread:cpu-cycles", CPU_CYCLES
,
297 CONTEXT_PERF_THREAD_COUNTER
, 0),
298 PERF_HW("perf:thread:cycles", CPU_CYCLES
,
299 CONTEXT_PERF_THREAD_COUNTER
, 0),
300 PERF_HW("perf:thread:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND
,
301 CONTEXT_PERF_THREAD_COUNTER
, 0),
302 PERF_HW("perf:thread:idle-cycles-frontend", STALLED_CYCLES_FRONTEND
,
303 CONTEXT_PERF_THREAD_COUNTER
, 0),
304 PERF_HW("perf:thread:stalled-cycles-backend", STALLED_CYCLES_BACKEND
,
305 CONTEXT_PERF_THREAD_COUNTER
, 0),
306 PERF_HW("perf:thread:idle-cycles-backend", STALLED_CYCLES_BACKEND
,
307 CONTEXT_PERF_THREAD_COUNTER
, 0),
308 PERF_HW("perf:thread:instructions", INSTRUCTIONS
,
309 CONTEXT_PERF_THREAD_COUNTER
, 0),
310 PERF_HW("perf:thread:cache-references", CACHE_REFERENCES
,
311 CONTEXT_PERF_THREAD_COUNTER
, 0),
312 PERF_HW("perf:thread:cache-misses", CACHE_MISSES
,
313 CONTEXT_PERF_THREAD_COUNTER
, 0),
314 PERF_HW("perf:thread:branch-instructions", BRANCH_INSTRUCTIONS
,
315 CONTEXT_PERF_THREAD_COUNTER
, 0),
316 PERF_HW("perf:thread:branches", BRANCH_INSTRUCTIONS
,
317 CONTEXT_PERF_THREAD_COUNTER
, 0),
318 PERF_HW("perf:thread:branch-misses", BRANCH_MISSES
,
319 CONTEXT_PERF_THREAD_COUNTER
, 0),
320 PERF_HW("perf:thread:bus-cycles", BUS_CYCLES
,
321 CONTEXT_PERF_THREAD_COUNTER
, 0),
323 PERF_HW_CACHE("perf:thread:L1-dcache", L1D
,
324 CONTEXT_PERF_THREAD_COUNTER
, 0),
325 PERF_HW_CACHE("perf:thread:L1-icache", L1I
,
326 CONTEXT_PERF_THREAD_COUNTER
, 0),
327 PERF_HW_CACHE("perf:thread:LLC", LL
,
328 CONTEXT_PERF_THREAD_COUNTER
, 0),
329 PERF_HW_CACHE("perf:thread:dTLB", DTLB
,
330 CONTEXT_PERF_THREAD_COUNTER
, 0),
331 _PERF_HW_CACHE("perf:thread:iTLB-loads", ITLB
,
332 CONTEXT_PERF_THREAD_COUNTER
, READ
, ACCESS
, 0),
333 _PERF_HW_CACHE("perf:thread:iTLB-load-misses", ITLB
,
334 CONTEXT_PERF_THREAD_COUNTER
, READ
, MISS
, 0),
335 _PERF_HW_CACHE("perf:thread:branch-loads", BPU
,
336 CONTEXT_PERF_THREAD_COUNTER
, READ
, ACCESS
, 0),
337 _PERF_HW_CACHE("perf:thread:branch-load-misses", BPU
,
338 CONTEXT_PERF_THREAD_COUNTER
, READ
, MISS
, 0),
340 PERF_SW("perf:thread:cpu-clock", CPU_CLOCK
,
341 CONTEXT_PERF_THREAD_COUNTER
, 0),
342 PERF_SW("perf:thread:task-clock", TASK_CLOCK
,
343 CONTEXT_PERF_THREAD_COUNTER
, 0),
344 PERF_SW("perf:thread:page-fault", PAGE_FAULTS
,
345 CONTEXT_PERF_THREAD_COUNTER
, 0),
346 PERF_SW("perf:thread:faults", PAGE_FAULTS
,
347 CONTEXT_PERF_THREAD_COUNTER
, 0),
348 PERF_SW("perf:thread:major-faults", PAGE_FAULTS_MAJ
,
349 CONTEXT_PERF_THREAD_COUNTER
, 0),
350 PERF_SW("perf:thread:minor-faults", PAGE_FAULTS_MIN
,
351 CONTEXT_PERF_THREAD_COUNTER
, 0),
352 PERF_SW("perf:thread:context-switches", CONTEXT_SWITCHES
,
353 CONTEXT_PERF_THREAD_COUNTER
, 0),
354 PERF_SW("perf:thread:cs", CONTEXT_SWITCHES
,
355 CONTEXT_PERF_THREAD_COUNTER
, 0),
356 PERF_SW("perf:thread:cpu-migrations", CPU_MIGRATIONS
,
357 CONTEXT_PERF_THREAD_COUNTER
, 0),
358 PERF_SW("perf:thread:migrations", CPU_MIGRATIONS
,
359 CONTEXT_PERF_THREAD_COUNTER
, 0),
360 PERF_SW("perf:thread:alignment-faults", ALIGNMENT_FAULTS
,
361 CONTEXT_PERF_THREAD_COUNTER
, 0),
362 PERF_SW("perf:thread:emulation-faults", EMULATION_FAULTS
,
363 CONTEXT_PERF_THREAD_COUNTER
, 0),
366 * Perf per-CPU counters, backward compatibilty for names.
367 * Hidden from help listing.
369 PERF_HW("perf:cpu-cycles", CPU_CYCLES
,
370 CONTEXT_PERF_COUNTER
, 1),
371 PERF_HW("perf:cycles", CPU_CYCLES
,
372 CONTEXT_PERF_COUNTER
, 1),
373 PERF_HW("perf:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND
,
374 CONTEXT_PERF_COUNTER
, 1),
375 PERF_HW("perf:idle-cycles-frontend", STALLED_CYCLES_FRONTEND
,
376 CONTEXT_PERF_COUNTER
, 1),
377 PERF_HW("perf:stalled-cycles-backend", STALLED_CYCLES_BACKEND
,
378 CONTEXT_PERF_COUNTER
, 1),
379 PERF_HW("perf:idle-cycles-backend", STALLED_CYCLES_BACKEND
,
380 CONTEXT_PERF_COUNTER
, 1),
381 PERF_HW("perf:instructions", INSTRUCTIONS
,
382 CONTEXT_PERF_COUNTER
, 1),
383 PERF_HW("perf:cache-references", CACHE_REFERENCES
,
384 CONTEXT_PERF_COUNTER
, 1),
385 PERF_HW("perf:cache-misses", CACHE_MISSES
,
386 CONTEXT_PERF_COUNTER
, 1),
387 PERF_HW("perf:branch-instructions", BRANCH_INSTRUCTIONS
,
388 CONTEXT_PERF_COUNTER
, 1),
389 PERF_HW("perf:branches", BRANCH_INSTRUCTIONS
,
390 CONTEXT_PERF_COUNTER
, 1),
391 PERF_HW("perf:branch-misses", BRANCH_MISSES
,
392 CONTEXT_PERF_COUNTER
, 1),
393 PERF_HW("perf:bus-cycles", BUS_CYCLES
,
394 CONTEXT_PERF_COUNTER
, 1),
396 PERF_HW_CACHE("perf:L1-dcache", L1D
,
397 CONTEXT_PERF_COUNTER
, 1),
398 PERF_HW_CACHE("perf:L1-icache", L1I
,
399 CONTEXT_PERF_COUNTER
, 1),
400 PERF_HW_CACHE("perf:LLC", LL
,
401 CONTEXT_PERF_COUNTER
, 1),
402 PERF_HW_CACHE("perf:dTLB", DTLB
,
403 CONTEXT_PERF_COUNTER
, 1),
404 _PERF_HW_CACHE("perf:iTLB-loads", ITLB
,
405 CONTEXT_PERF_COUNTER
, READ
, ACCESS
, 1),
406 _PERF_HW_CACHE("perf:iTLB-load-misses", ITLB
,
407 CONTEXT_PERF_COUNTER
, READ
, MISS
, 1),
408 _PERF_HW_CACHE("perf:branch-loads", BPU
,
409 CONTEXT_PERF_COUNTER
, READ
, ACCESS
, 1),
410 _PERF_HW_CACHE("perf:branch-load-misses", BPU
,
411 CONTEXT_PERF_COUNTER
, READ
, MISS
, 1),
413 PERF_SW("perf:cpu-clock", CPU_CLOCK
,
414 CONTEXT_PERF_COUNTER
, 1),
415 PERF_SW("perf:task-clock", TASK_CLOCK
,
416 CONTEXT_PERF_COUNTER
, 1),
417 PERF_SW("perf:page-fault", PAGE_FAULTS
,
418 CONTEXT_PERF_COUNTER
, 1),
419 PERF_SW("perf:faults", PAGE_FAULTS
,
420 CONTEXT_PERF_COUNTER
, 1),
421 PERF_SW("perf:major-faults", PAGE_FAULTS_MAJ
,
422 CONTEXT_PERF_COUNTER
, 1),
423 PERF_SW("perf:minor-faults", PAGE_FAULTS_MIN
,
424 CONTEXT_PERF_COUNTER
, 1),
425 PERF_SW("perf:context-switches", CONTEXT_SWITCHES
,
426 CONTEXT_PERF_COUNTER
, 1),
427 PERF_SW("perf:cs", CONTEXT_SWITCHES
,
428 CONTEXT_PERF_COUNTER
, 1),
429 PERF_SW("perf:cpu-migrations", CPU_MIGRATIONS
,
430 CONTEXT_PERF_COUNTER
, 1),
431 PERF_SW("perf:migrations", CPU_MIGRATIONS
,
432 CONTEXT_PERF_COUNTER
, 1),
433 PERF_SW("perf:alignment-faults", ALIGNMENT_FAULTS
,
434 CONTEXT_PERF_COUNTER
, 1),
435 PERF_SW("perf:emulation-faults", EMULATION_FAULTS
,
436 CONTEXT_PERF_COUNTER
, 1),
438 { NULL
, -1 }, /* Closure */
442 #undef _PERF_HW_CACHE
447 * Context type for command line option parsing.
450 const struct ctx_opts
*opt
;
451 struct cds_list_head list
;
455 * List of context type. Use to enable multiple context on a single command
458 struct ctx_type_list
{
459 struct cds_list_head head
;
461 .head
= CDS_LIST_HEAD_INIT(ctx_type_list
.head
),
465 * Pretty print context type.
467 static void print_ctx_type(FILE *ofp
)
469 const char *indent
= " ";
470 int indent_len
= strlen(indent
);
473 fprintf(ofp
, "%s", indent
);
475 while (ctx_opts
[i
].symbol
!= NULL
) {
476 if (!ctx_opts
[i
].hide_help
) {
477 if (len
> indent_len
) {
478 if (len
+ strlen(ctx_opts
[i
].symbol
) + 2
481 fprintf(ofp
, "%s", indent
);
484 len
+= fprintf(ofp
, ", ");
487 len
+= fprintf(ofp
, "%s", ctx_opts
[i
].symbol
);
496 static void usage(FILE *ofp
)
498 fprintf(ofp
, "usage: lttng add-context -t TYPE [-k|-u] [OPTIONS]\n");
500 fprintf(ofp
, "If no channel is given (-c), the context is added to\n");
501 fprintf(ofp
, "all channels.\n");
503 fprintf(ofp
, "Otherwise the context is added only to the channel (-c).\n");
505 fprintf(ofp
, "Exactly one domain (-k or -u) must be specified.\n");
507 fprintf(ofp
, "Options:\n");
508 fprintf(ofp
, " -h, --help Show this help\n");
509 fprintf(ofp
, " --list-options Simple listing of options\n");
510 fprintf(ofp
, " -s, --session NAME Apply to session name\n");
511 fprintf(ofp
, " -c, --channel NAME Apply to channel\n");
512 fprintf(ofp
, " -k, --kernel Apply to the kernel tracer\n");
513 fprintf(ofp
, " -u, --userspace Apply to the user-space tracer\n");
515 fprintf(ofp
, "Context:\n");
516 fprintf(ofp
, " -t, --type TYPE Context type. You can repeat that option on\n");
517 fprintf(ofp
, " the command line to specify multiple contexts at once.\n");
518 fprintf(ofp
, " (--kernel preempts --userspace)\n");
519 fprintf(ofp
, " TYPE can be one of the strings below:\n");
522 fprintf(ofp
, "Note that the vpid, vppid and vtid context types represent the virtual process id,\n"
523 "virtual parent process id and virtual thread id as seen from the current execution context\n"
524 "as opposed to the pid, ppid and tid which are kernel internal data structures.\n\n");
525 fprintf(ofp
, "Example:\n");
526 fprintf(ofp
, "This command will add the context information 'prio' and two per-cpu\n"
527 "perf counters (hardware branch misses and cache misses), to all channels\n"
528 "in the trace data output:\n");
529 fprintf(ofp
, "# lttng add-context -k -t prio -t perf:cpu:branch-misses -t perf:cpu:cache-misses\n");
534 * Find context numerical value from string.
536 static int find_ctx_type_idx(const char *opt
)
540 while (ctx_opts
[i
].symbol
!= NULL
) {
541 if (strcmp(opt
, ctx_opts
[i
].symbol
) == 0) {
553 * Add context to channel or event.
555 static int add_context(char *session_name
)
557 int ret
= CMD_SUCCESS
, warn
= 0, success
= 0;
558 struct lttng_event_context context
;
559 struct lttng_domain dom
;
560 struct ctx_type
*type
;
563 memset(&context
, 0, sizeof(context
));
564 memset(&dom
, 0, sizeof(dom
));
567 dom
.type
= LTTNG_DOMAIN_KERNEL
;
568 } else if (opt_userspace
) {
569 dom
.type
= LTTNG_DOMAIN_UST
;
574 handle
= lttng_create_handle(session_name
, &dom
);
575 if (handle
== NULL
) {
581 /* Open a contexts element */
582 ret
= mi_lttng_writer_open_element(writer
, config_element_contexts
);
588 /* Iterate over all the context types given */
589 cds_list_for_each_entry(type
, &ctx_type_list
.head
, list
) {
590 context
.ctx
= (enum lttng_event_context_type
) type
->opt
->ctx_type
;
591 switch (context
.ctx
) {
592 case LTTNG_EVENT_CONTEXT_PERF_COUNTER
:
593 case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER
:
594 case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER
:
595 context
.u
.perf_counter
.type
= type
->opt
->u
.perf
.type
;
596 context
.u
.perf_counter
.config
= type
->opt
->u
.perf
.config
;
597 strncpy(context
.u
.perf_counter
.name
, type
->opt
->symbol
,
598 LTTNG_SYMBOL_NAME_LEN
);
599 context
.u
.perf_counter
.name
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
600 /* Replace : and - by _ */
601 while ((ptr
= strchr(context
.u
.perf_counter
.name
, '-')) != NULL
) {
604 while ((ptr
= strchr(context
.u
.perf_counter
.name
, ':')) != NULL
) {
611 DBG("Adding context...");
614 /* We leave context open the update the success of the command */
615 ret
= mi_lttng_context(writer
, &context
, 1);
622 ret
= lttng_add_context(handle
, &context
, NULL
, opt_channel_name
);
624 ERR("%s: %s", type
->opt
->symbol
, lttng_strerror(ret
));
628 if (opt_channel_name
) {
629 MSG("%s context %s added to channel %s",
630 get_domain_str(dom
.type
), type
->opt
->symbol
,
633 MSG("%s context %s added to all channels",
634 get_domain_str(dom
.type
), type
->opt
->symbol
);
640 /* Is the single operation a success ? */
641 ret
= mi_lttng_writer_write_element_bool(writer
,
642 mi_lttng_element_success
, success
);
648 /* Close the context element */
649 ret
= mi_lttng_writer_close_element(writer
);
658 /* Close contexts element */
659 ret
= mi_lttng_writer_close_element(writer
);
668 lttng_destroy_handle(handle
);
671 * This means that at least one add_context failed and tells the user to
672 * look on stderr for error(s).
681 * Add context to channel or event.
683 int cmd_add_context(int argc
, const char **argv
)
685 int index
, opt
, ret
= CMD_SUCCESS
, command_ret
= CMD_SUCCESS
;
687 static poptContext pc
;
688 struct ctx_type
*type
, *tmptype
;
689 char *session_name
= NULL
;
697 pc
= poptGetContext(NULL
, argc
, argv
, long_options
, 0);
698 poptReadDefaultConfig(pc
, 0);
700 while ((opt
= poptGetNextOpt(pc
)) != -1) {
707 * Look up the index of opt_type in ctx_opts[] first, so we don't
708 * have to free(type) on failure.
710 index
= find_ctx_type_idx(opt_type
);
712 ERR("Unknown context type %s", opt_type
);
717 type
= zmalloc(sizeof(struct ctx_type
));
719 perror("malloc ctx_type");
724 type
->opt
= &ctx_opts
[index
];
725 if (type
->opt
->symbol
== NULL
) {
726 ERR("Unknown context type %s", opt_type
);
731 cds_list_add_tail(&type
->list
, &ctx_type_list
.head
);
737 opt_cmd_name
= poptGetOptArg(pc
);
740 case OPT_LIST_OPTIONS
:
741 list_cmd_options(stdout
, long_options
);
750 ret
= print_missing_or_multiple_domains(opt_kernel
+ opt_userspace
);
758 ERR("Missing mandatory -t TYPE");
764 if (!opt_session_name
) {
765 session_name
= get_session_name();
766 if (session_name
== NULL
) {
771 session_name
= opt_session_name
;
776 writer
= mi_lttng_writer_create(fileno(stdout
), lttng_opt_mi
);
778 ret
= -LTTNG_ERR_NOMEM
;
782 /* Open command element */
783 ret
= mi_lttng_writer_command_open(writer
,
784 mi_lttng_element_command_add_context
);
790 /* Open output element */
791 ret
= mi_lttng_writer_open_element(writer
,
792 mi_lttng_element_command_output
);
799 command_ret
= add_context(session_name
);
806 /* Close output element */
807 ret
= mi_lttng_writer_close_element(writer
);
814 ret
= mi_lttng_writer_write_element_bool(writer
,
815 mi_lttng_element_command_success
, success
);
821 /* Command element close */
822 ret
= mi_lttng_writer_command_close(writer
);
830 if (!opt_session_name
) {
835 if (writer
&& mi_lttng_writer_destroy(writer
)) {
836 /* Preserve original error code */
837 ret
= ret
? ret
: LTTNG_ERR_MI_IO_FAIL
;
840 /* Cleanup allocated memory */
841 cds_list_for_each_entry_safe(type
, tmptype
, &ctx_type_list
.head
, list
) {
845 /* Overwrite ret if an error occurred during add_context() */
846 ret
= command_ret
? command_ret
: ret
;