1 // SPDX-License-Identifier: GPL-2.0
5 * Builtin list command: list all event types
7 * Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de>
8 * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
9 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
13 #include "util/print-events.h"
14 #include "util/pmus.h"
16 #include "util/debug.h"
17 #include "util/metricgroup.h"
19 #include "util/string2.h"
20 #include "util/strlist.h"
21 #include "util/strbuf.h"
22 #include "util/tool_pmu.h"
23 #include <subcmd/pager.h>
24 #include <subcmd/parse-options.h>
25 #include <linux/zalloc.h>
31 * struct print_state - State and configuration passed to the default_print
35 /** @fp: File to write output to. */
38 * @pmu_glob: Optionally restrict PMU and metric matching to PMU or
39 * debugfs subsystem name.
42 /** @event_glob: Optional pattern matching glob. */
44 /** @name_only: Print event or metric names only. */
46 /** @desc: Print the event or metric description. */
48 /** @long_desc: Print longer event or metric description. */
50 /** @deprecated: Print deprecated events or metrics. */
53 * @detailed: Print extra information on the perf event such as names
54 * and expressions used internally by events.
57 /** @metrics: Controls printing of metric and metric groups. */
59 /** @metricgroups: Controls printing of metric and metric groups. */
61 /** @last_topic: The last printed event topic. */
63 /** @last_metricgroups: The last printed metric group. */
64 char *last_metricgroups
;
65 /** @visited_metrics: Metrics that are printed to avoid duplicates. */
66 struct strlist
*visited_metrics
;
69 static void default_print_start(void *ps
)
71 struct print_state
*print_state
= ps
;
73 if (!print_state
->name_only
&& pager_in_use()) {
74 fprintf(print_state
->fp
,
75 "\nList of pre-defined events (to be used in -e or -M):\n\n");
79 static void default_print_end(void *print_state __maybe_unused
) {}
81 static const char *skip_spaces_or_commas(const char *str
)
83 while (isspace(*str
) || *str
== ',')
88 static void wordwrap(FILE *fp
, const char *s
, int start
, int max
, int corr
)
92 bool saw_newline
= false;
96 int wlen
= strcspn(s
, " ,\t\n");
97 const char *sep
= comma
? "," : " ";
99 if ((column
+ wlen
>= max
&& column
> start
) || saw_newline
) {
100 fprintf(fp
, comma
? ",\n%*s" : "\n%*s", start
, "");
101 column
= start
+ corr
;
105 n
= fprintf(fp
, "%s%.*s", sep
, wlen
, s
);
108 saw_newline
= s
[wlen
] == '\n';
112 s
= skip_spaces_or_commas(s
);
116 static void default_print_event(void *ps
, const char *topic
, const char *pmu_name
,
117 const char *event_name
, const char *event_alias
,
118 const char *scale_unit __maybe_unused
,
119 bool deprecated
, const char *event_type_desc
,
120 const char *desc
, const char *long_desc
,
121 const char *encoding_desc
)
123 struct print_state
*print_state
= ps
;
125 FILE *fp
= print_state
->fp
;
127 if (deprecated
&& !print_state
->deprecated
)
130 if (print_state
->pmu_glob
&& pmu_name
&& !strglobmatch(pmu_name
, print_state
->pmu_glob
))
133 if (print_state
->event_glob
&&
134 (!event_name
|| !strglobmatch(event_name
, print_state
->event_glob
)) &&
135 (!event_alias
|| !strglobmatch(event_alias
, print_state
->event_glob
)) &&
136 (!topic
|| !strglobmatch_nocase(topic
, print_state
->event_glob
)))
139 if (print_state
->name_only
) {
140 if (event_alias
&& strlen(event_alias
))
141 fprintf(fp
, "%s ", event_alias
);
143 fprintf(fp
, "%s ", event_name
);
147 if (strcmp(print_state
->last_topic
, topic
?: "")) {
149 fprintf(fp
, "\n%s:\n", topic
);
150 zfree(&print_state
->last_topic
);
151 print_state
->last_topic
= strdup(topic
?: "");
154 if (event_alias
&& strlen(event_alias
))
155 pos
= fprintf(fp
, " %s OR %s", event_name
, event_alias
);
157 pos
= fprintf(fp
, " %s", event_name
);
159 if (!topic
&& event_type_desc
) {
160 for (; pos
< 53; pos
++)
162 fprintf(fp
, "[%s]\n", event_type_desc
);
166 if (long_desc
&& print_state
->long_desc
) {
167 fprintf(fp
, "%*s", 8, "[");
168 wordwrap(fp
, long_desc
, 8, pager_get_columns(), 0);
170 } else if (desc
&& print_state
->desc
) {
171 char *desc_with_unit
= NULL
;
174 if (pmu_name
&& strcmp(pmu_name
, "default_core")) {
175 desc_len
= strlen(desc
);
176 desc_len
= asprintf(&desc_with_unit
,
177 desc_len
> 0 && desc
[desc_len
- 1] != '.'
178 ? "%s. Unit: %s" : "%s Unit: %s",
181 fprintf(fp
, "%*s", 8, "[");
182 wordwrap(fp
, desc_len
> 0 ? desc_with_unit
: desc
, 8, pager_get_columns(), 0);
184 free(desc_with_unit
);
187 if (print_state
->detailed
&& encoding_desc
) {
188 fprintf(fp
, "%*s", 8, "");
189 wordwrap(fp
, encoding_desc
, 8, pager_get_columns(), 0);
194 static void default_print_metric(void *ps
,
198 const char *long_desc
,
200 const char *threshold
,
201 const char *unit __maybe_unused
)
203 struct print_state
*print_state
= ps
;
204 FILE *fp
= print_state
->fp
;
206 if (print_state
->event_glob
&&
207 (!print_state
->metrics
|| !name
|| !strglobmatch(name
, print_state
->event_glob
)) &&
208 (!print_state
->metricgroups
|| !group
|| !strglobmatch(group
, print_state
->event_glob
)))
211 if (!print_state
->name_only
&& !print_state
->last_metricgroups
) {
212 if (print_state
->metricgroups
) {
213 fprintf(fp
, "\nMetric Groups:\n");
214 if (!print_state
->metrics
)
217 fprintf(fp
, "\nMetrics:\n\n");
220 if (!print_state
->last_metricgroups
||
221 strcmp(print_state
->last_metricgroups
, group
?: "")) {
222 if (group
&& print_state
->metricgroups
) {
223 if (print_state
->name_only
) {
224 fprintf(fp
, "%s ", group
);
226 const char *gdesc
= print_state
->desc
227 ? describe_metricgroup(group
)
229 const char *print_colon
= "";
231 if (print_state
->metrics
) {
237 fprintf(fp
, "%s%s [%s]\n", group
, print_colon
, gdesc
);
239 fprintf(fp
, "%s%s\n", group
, print_colon
);
242 zfree(&print_state
->last_metricgroups
);
243 print_state
->last_metricgroups
= strdup(group
?: "");
245 if (!print_state
->metrics
)
248 if (print_state
->name_only
) {
249 if (print_state
->metrics
&&
250 !strlist__has_entry(print_state
->visited_metrics
, name
)) {
251 fprintf(fp
, "%s ", name
);
252 strlist__add(print_state
->visited_metrics
, name
);
256 fprintf(fp
, " %s\n", name
);
258 if (long_desc
&& print_state
->long_desc
) {
259 fprintf(fp
, "%*s", 8, "[");
260 wordwrap(fp
, long_desc
, 8, pager_get_columns(), 0);
262 } else if (desc
&& print_state
->desc
) {
263 fprintf(fp
, "%*s", 8, "[");
264 wordwrap(fp
, desc
, 8, pager_get_columns(), 0);
267 if (expr
&& print_state
->detailed
) {
268 fprintf(fp
, "%*s", 8, "[");
269 wordwrap(fp
, expr
, 8, pager_get_columns(), 0);
272 if (threshold
&& print_state
->detailed
) {
273 fprintf(fp
, "%*s", 8, "[");
274 wordwrap(fp
, threshold
, 8, pager_get_columns(), 0);
279 struct json_print_state
{
280 /** @fp: File to write output to. */
282 /** Should a separator be printed prior to the next item? */
286 static void json_print_start(void *ps
)
288 struct json_print_state
*print_state
= ps
;
289 FILE *fp
= print_state
->fp
;
294 static void json_print_end(void *ps
)
296 struct json_print_state
*print_state
= ps
;
297 FILE *fp
= print_state
->fp
;
299 fprintf(fp
, "%s]\n", print_state
->need_sep
? "\n" : "");
302 static void fix_escape_fprintf(FILE *fp
, struct strbuf
*buf
, const char *fmt
, ...)
307 strbuf_setlen(buf
, 0);
308 for (size_t fmt_pos
= 0; fmt_pos
< strlen(fmt
); fmt_pos
++) {
309 switch (fmt
[fmt_pos
]) {
312 switch (fmt
[fmt_pos
]) {
314 const char *s
= va_arg(args
, const char*);
316 strbuf_addstr(buf
, s
);
320 const char *s
= va_arg(args
, const char*);
322 for (size_t s_pos
= 0; s_pos
< strlen(s
); s_pos
++) {
325 strbuf_addstr(buf
, "\\n");
328 strbuf_addstr(buf
, "\\r");
333 strbuf_addch(buf
, '\\');
336 strbuf_addch(buf
, s
[s_pos
]);
343 pr_err("Unexpected format character '%c'\n", fmt
[fmt_pos
]);
344 strbuf_addch(buf
, '%');
345 strbuf_addch(buf
, fmt
[fmt_pos
]);
349 strbuf_addch(buf
, fmt
[fmt_pos
]);
357 static void json_print_event(void *ps
, const char *topic
, const char *pmu_name
,
358 const char *event_name
, const char *event_alias
,
359 const char *scale_unit
,
360 bool deprecated
, const char *event_type_desc
,
361 const char *desc
, const char *long_desc
,
362 const char *encoding_desc
)
364 struct json_print_state
*print_state
= ps
;
365 bool need_sep
= false;
366 FILE *fp
= print_state
->fp
;
369 strbuf_init(&buf
, 0);
370 fprintf(fp
, "%s{\n", print_state
->need_sep
? ",\n" : "");
371 print_state
->need_sep
= true;
373 fix_escape_fprintf(fp
, &buf
, "\t\"Unit\": \"%S\"", pmu_name
);
377 fix_escape_fprintf(fp
, &buf
, "%s\t\"Topic\": \"%S\"",
378 need_sep
? ",\n" : "",
383 fix_escape_fprintf(fp
, &buf
, "%s\t\"EventName\": \"%S\"",
384 need_sep
? ",\n" : "",
388 if (event_alias
&& strlen(event_alias
)) {
389 fix_escape_fprintf(fp
, &buf
, "%s\t\"EventAlias\": \"%S\"",
390 need_sep
? ",\n" : "",
394 if (scale_unit
&& strlen(scale_unit
)) {
395 fix_escape_fprintf(fp
, &buf
, "%s\t\"ScaleUnit\": \"%S\"",
396 need_sep
? ",\n" : "",
400 if (event_type_desc
) {
401 fix_escape_fprintf(fp
, &buf
, "%s\t\"EventType\": \"%S\"",
402 need_sep
? ",\n" : "",
407 fix_escape_fprintf(fp
, &buf
, "%s\t\"Deprecated\": \"%S\"",
408 need_sep
? ",\n" : "",
409 deprecated
? "1" : "0");
413 fix_escape_fprintf(fp
, &buf
, "%s\t\"BriefDescription\": \"%S\"",
414 need_sep
? ",\n" : "",
419 fix_escape_fprintf(fp
, &buf
, "%s\t\"PublicDescription\": \"%S\"",
420 need_sep
? ",\n" : "",
425 fix_escape_fprintf(fp
, &buf
, "%s\t\"Encoding\": \"%S\"",
426 need_sep
? ",\n" : "",
430 fprintf(fp
, "%s}", need_sep
? "\n" : "");
431 strbuf_release(&buf
);
434 static void json_print_metric(void *ps __maybe_unused
, const char *group
,
435 const char *name
, const char *desc
,
436 const char *long_desc
, const char *expr
,
437 const char *threshold
, const char *unit
)
439 struct json_print_state
*print_state
= ps
;
440 bool need_sep
= false;
441 FILE *fp
= print_state
->fp
;
444 strbuf_init(&buf
, 0);
445 fprintf(fp
, "%s{\n", print_state
->need_sep
? ",\n" : "");
446 print_state
->need_sep
= true;
448 fix_escape_fprintf(fp
, &buf
, "\t\"MetricGroup\": \"%S\"", group
);
452 fix_escape_fprintf(fp
, &buf
, "%s\t\"MetricName\": \"%S\"",
453 need_sep
? ",\n" : "",
458 fix_escape_fprintf(fp
, &buf
, "%s\t\"MetricExpr\": \"%S\"",
459 need_sep
? ",\n" : "",
464 fix_escape_fprintf(fp
, &buf
, "%s\t\"MetricThreshold\": \"%S\"",
465 need_sep
? ",\n" : "",
470 fix_escape_fprintf(fp
, &buf
, "%s\t\"ScaleUnit\": \"%S\"",
471 need_sep
? ",\n" : "",
476 fix_escape_fprintf(fp
, &buf
, "%s\t\"BriefDescription\": \"%S\"",
477 need_sep
? ",\n" : "",
482 fix_escape_fprintf(fp
, &buf
, "%s\t\"PublicDescription\": \"%S\"",
483 need_sep
? ",\n" : "",
487 fprintf(fp
, "%s}", need_sep
? "\n" : "");
488 strbuf_release(&buf
);
491 static bool json_skip_duplicate_pmus(void *ps __maybe_unused
)
496 static bool default_skip_duplicate_pmus(void *ps
)
498 struct print_state
*print_state
= ps
;
500 return !print_state
->long_desc
;
503 int cmd_list(int argc
, const char **argv
)
506 struct print_state default_ps
= {
510 struct print_state json_ps
= {
513 void *ps
= &default_ps
;
514 struct print_callbacks print_cb
= {
515 .print_start
= default_print_start
,
516 .print_end
= default_print_end
,
517 .print_event
= default_print_event
,
518 .print_metric
= default_print_metric
,
519 .skip_duplicate_pmus
= default_skip_duplicate_pmus
,
521 const char *cputype
= NULL
;
522 const char *unit_name
= NULL
;
523 const char *output_path
= NULL
;
525 struct option list_options
[] = {
526 OPT_BOOLEAN(0, "raw-dump", &default_ps
.name_only
, "Dump raw events"),
527 OPT_BOOLEAN('j', "json", &json
, "JSON encode events and metrics"),
528 OPT_BOOLEAN('d', "desc", &default_ps
.desc
,
529 "Print extra event descriptions. --no-desc to not print."),
530 OPT_BOOLEAN('v', "long-desc", &default_ps
.long_desc
,
531 "Print longer event descriptions."),
532 OPT_BOOLEAN(0, "details", &default_ps
.detailed
,
533 "Print information on the perf event names and expressions used internally by events."),
534 OPT_STRING('o', "output", &output_path
, "file", "output file name"),
535 OPT_BOOLEAN(0, "deprecated", &default_ps
.deprecated
,
536 "Print deprecated events."),
537 OPT_STRING(0, "cputype", &cputype
, "cpu type",
538 "Limit PMU or metric printing to the given PMU (e.g. cpu, core or atom)."),
539 OPT_STRING(0, "unit", &unit_name
, "PMU name",
540 "Limit PMU or metric printing to the specified PMU."),
541 OPT_INCR(0, "debug", &verbose
,
542 "Enable debugging output"),
545 const char * const list_usage
[] = {
547 "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob|pfm]",
549 "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]",
554 set_option_flag(list_options
, 0, "raw-dump", PARSE_OPT_HIDDEN
);
555 /* Hide hybrid flag for the more generic 'unit' flag. */
556 set_option_flag(list_options
, 0, "cputype", PARSE_OPT_HIDDEN
);
558 argc
= parse_options(argc
, argv
, list_options
, list_usage
,
559 PARSE_OPT_STOP_AT_NON_OPTION
);
562 default_ps
.fp
= fopen(output_path
, "w");
563 json_ps
.fp
= default_ps
.fp
;
568 if (!default_ps
.name_only
)
572 print_cb
= (struct print_callbacks
){
573 .print_start
= json_print_start
,
574 .print_end
= json_print_end
,
575 .print_event
= json_print_event
,
576 .print_metric
= json_print_metric
,
577 .skip_duplicate_pmus
= json_skip_duplicate_pmus
,
581 default_ps
.last_topic
= strdup("");
582 assert(default_ps
.last_topic
);
583 default_ps
.visited_metrics
= strlist__new(NULL
, NULL
);
584 assert(default_ps
.visited_metrics
);
586 default_ps
.pmu_glob
= strdup(unit_name
);
588 const struct perf_pmu
*pmu
= perf_pmus__pmu_for_pmu_filter(cputype
);
591 pr_err("ERROR: cputype is not supported!\n");
595 default_ps
.pmu_glob
= strdup(pmu
->name
);
598 print_cb
.print_start(ps
);
601 default_ps
.metrics
= true;
602 default_ps
.metricgroups
= true;
603 print_events(&print_cb
, ps
);
607 for (i
= 0; i
< argc
; ++i
) {
610 if (strcmp(argv
[i
], "tracepoint") == 0)
611 print_tracepoint_events(&print_cb
, ps
);
612 else if (strcmp(argv
[i
], "hw") == 0 ||
613 strcmp(argv
[i
], "hardware") == 0)
614 print_symbol_events(&print_cb
, ps
, PERF_TYPE_HARDWARE
,
615 event_symbols_hw
, PERF_COUNT_HW_MAX
);
616 else if (strcmp(argv
[i
], "sw") == 0 ||
617 strcmp(argv
[i
], "software") == 0) {
618 char *old_pmu_glob
= default_ps
.pmu_glob
;
620 print_symbol_events(&print_cb
, ps
, PERF_TYPE_SOFTWARE
,
621 event_symbols_sw
, PERF_COUNT_SW_MAX
);
622 default_ps
.pmu_glob
= strdup("tool");
623 if (!default_ps
.pmu_glob
) {
627 perf_pmus__print_pmu_events(&print_cb
, ps
);
628 zfree(&default_ps
.pmu_glob
);
629 default_ps
.pmu_glob
= old_pmu_glob
;
630 } else if (strcmp(argv
[i
], "cache") == 0 ||
631 strcmp(argv
[i
], "hwcache") == 0)
632 print_hwcache_events(&print_cb
, ps
);
633 else if (strcmp(argv
[i
], "pmu") == 0)
634 perf_pmus__print_pmu_events(&print_cb
, ps
);
635 else if (strcmp(argv
[i
], "sdt") == 0)
636 print_sdt_events(&print_cb
, ps
);
637 else if (strcmp(argv
[i
], "metric") == 0 || strcmp(argv
[i
], "metrics") == 0) {
638 default_ps
.metricgroups
= false;
639 default_ps
.metrics
= true;
640 metricgroup__print(&print_cb
, ps
);
641 } else if (strcmp(argv
[i
], "metricgroup") == 0 ||
642 strcmp(argv
[i
], "metricgroups") == 0) {
643 default_ps
.metricgroups
= true;
644 default_ps
.metrics
= false;
645 metricgroup__print(&print_cb
, ps
);
648 else if (strcmp(argv
[i
], "pfm") == 0)
649 print_libpfm_events(&print_cb
, ps
);
651 else if ((sep
= strchr(argv
[i
], ':')) != NULL
) {
652 char *old_pmu_glob
= default_ps
.pmu_glob
;
654 default_ps
.event_glob
= strdup(argv
[i
]);
655 if (!default_ps
.event_glob
) {
660 print_tracepoint_events(&print_cb
, ps
);
661 print_sdt_events(&print_cb
, ps
);
662 default_ps
.metrics
= true;
663 default_ps
.metricgroups
= true;
664 metricgroup__print(&print_cb
, ps
);
665 zfree(&default_ps
.event_glob
);
666 default_ps
.pmu_glob
= old_pmu_glob
;
668 if (asprintf(&s
, "*%s*", argv
[i
]) < 0) {
669 printf("Critical: Not enough memory! Trying to continue...\n");
672 default_ps
.event_glob
= s
;
673 print_symbol_events(&print_cb
, ps
, PERF_TYPE_HARDWARE
,
674 event_symbols_hw
, PERF_COUNT_HW_MAX
);
675 print_symbol_events(&print_cb
, ps
, PERF_TYPE_SOFTWARE
,
676 event_symbols_sw
, PERF_COUNT_SW_MAX
);
677 print_hwcache_events(&print_cb
, ps
);
678 perf_pmus__print_pmu_events(&print_cb
, ps
);
679 print_tracepoint_events(&print_cb
, ps
);
680 print_sdt_events(&print_cb
, ps
);
681 default_ps
.metrics
= true;
682 default_ps
.metricgroups
= true;
683 metricgroup__print(&print_cb
, ps
);
689 print_cb
.print_end(ps
);
690 free(default_ps
.pmu_glob
);
691 free(default_ps
.last_topic
);
692 free(default_ps
.last_metricgroups
);
693 strlist__delete(default_ps
.visited_metrics
);
695 fclose(default_ps
.fp
);