1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
286470930SIngo Molnar /*
386470930SIngo Molnar * builtin-list.c
486470930SIngo Molnar *
586470930SIngo Molnar * Builtin list command: list all event types
686470930SIngo Molnar *
786470930SIngo Molnar * Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de>
886470930SIngo Molnar * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
9668b8788SArnaldo Carvalho de Melo * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
1086470930SIngo Molnar */
1186470930SIngo Molnar #include "builtin.h"
1286470930SIngo Molnar
139b7c7728SIan Rogers #include "util/print-events.h"
14003be8c4SIan Rogers #include "util/pmus.h"
15dc098b35SAndi Kleen #include "util/pmu.h"
16f2361024SAndi Kleen #include "util/debug.h"
1771b0acceSAndi Kleen #include "util/metricgroup.h"
18cc3d139bSIan Rogers #include "util/pfm.h"
19e5c6109fSIan Rogers #include "util/string2.h"
20e5c6109fSIan Rogers #include "util/strlist.h"
211284ded7SIan Rogers #include "util/strbuf.h"
22fa0d9846SArnaldo Carvalho de Melo #include <subcmd/pager.h>
234b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
246ed24944SIan Rogers #include <linux/zalloc.h>
256ed24944SIan Rogers #include <stdarg.h>
268520a98dSArnaldo Carvalho de Melo #include <stdio.h>
2786470930SIngo Molnar
28e5c6109fSIan Rogers /**
29e5c6109fSIan Rogers * struct print_state - State and configuration passed to the default_print
30e5c6109fSIan Rogers * functions.
31e5c6109fSIan Rogers */
32e5c6109fSIan Rogers struct print_state {
33e5c6109fSIan Rogers /**
34e5c6109fSIan Rogers * @pmu_glob: Optionally restrict PMU and metric matching to PMU or
35e5c6109fSIan Rogers * debugfs subsystem name.
36e5c6109fSIan Rogers */
37e5c6109fSIan Rogers char *pmu_glob;
38e5c6109fSIan Rogers /** @event_glob: Optional pattern matching glob. */
39e5c6109fSIan Rogers char *event_glob;
40e5c6109fSIan Rogers /** @name_only: Print event or metric names only. */
41e5c6109fSIan Rogers bool name_only;
42e5c6109fSIan Rogers /** @desc: Print the event or metric description. */
43e5c6109fSIan Rogers bool desc;
44e5c6109fSIan Rogers /** @long_desc: Print longer event or metric description. */
45e5c6109fSIan Rogers bool long_desc;
46e5c6109fSIan Rogers /** @deprecated: Print deprecated events or metrics. */
47e5c6109fSIan Rogers bool deprecated;
48e5c6109fSIan Rogers /**
49e5c6109fSIan Rogers * @detailed: Print extra information on the perf event such as names
50e5c6109fSIan Rogers * and expressions used internally by events.
51e5c6109fSIan Rogers */
52e5c6109fSIan Rogers bool detailed;
53e5c6109fSIan Rogers /** @metrics: Controls printing of metric and metric groups. */
54e5c6109fSIan Rogers bool metrics;
55e5c6109fSIan Rogers /** @metricgroups: Controls printing of metric and metric groups. */
56e5c6109fSIan Rogers bool metricgroups;
57e5c6109fSIan Rogers /** @last_topic: The last printed event topic. */
58e5c6109fSIan Rogers char *last_topic;
59e5c6109fSIan Rogers /** @last_metricgroups: The last printed metric group. */
60e5c6109fSIan Rogers char *last_metricgroups;
61e5c6109fSIan Rogers /** @visited_metrics: Metrics that are printed to avoid duplicates. */
62e5c6109fSIan Rogers struct strlist *visited_metrics;
63e5c6109fSIan Rogers };
64e5c6109fSIan Rogers
default_print_start(void * ps)65e5c6109fSIan Rogers static void default_print_start(void *ps)
66e5c6109fSIan Rogers {
67e5c6109fSIan Rogers struct print_state *print_state = ps;
68e5c6109fSIan Rogers
69e5c6109fSIan Rogers if (!print_state->name_only && pager_in_use())
70e5c6109fSIan Rogers printf("\nList of pre-defined events (to be used in -e or -M):\n\n");
71e5c6109fSIan Rogers }
72e5c6109fSIan Rogers
default_print_end(void * print_state __maybe_unused)73e5c6109fSIan Rogers static void default_print_end(void *print_state __maybe_unused) {}
74e5c6109fSIan Rogers
wordwrap(const char * s,int start,int max,int corr)75e5c6109fSIan Rogers static void wordwrap(const char *s, int start, int max, int corr)
76e5c6109fSIan Rogers {
77e5c6109fSIan Rogers int column = start;
78e5c6109fSIan Rogers int n;
791a9c20b4SIan Rogers bool saw_newline = false;
80e5c6109fSIan Rogers
81e5c6109fSIan Rogers while (*s) {
821a9c20b4SIan Rogers int wlen = strcspn(s, " \t\n");
83e5c6109fSIan Rogers
841a9c20b4SIan Rogers if ((column + wlen >= max && column > start) || saw_newline) {
85e5c6109fSIan Rogers printf("\n%*s", start, "");
86e5c6109fSIan Rogers column = start + corr;
87e5c6109fSIan Rogers }
88e5c6109fSIan Rogers n = printf("%s%.*s", column > start ? " " : "", wlen, s);
89e5c6109fSIan Rogers if (n <= 0)
90e5c6109fSIan Rogers break;
911a9c20b4SIan Rogers saw_newline = s[wlen] == '\n';
92e5c6109fSIan Rogers s += wlen;
93e5c6109fSIan Rogers column += n;
94e5c6109fSIan Rogers s = skip_spaces(s);
95e5c6109fSIan Rogers }
96e5c6109fSIan Rogers }
97e5c6109fSIan Rogers
default_print_event(void * ps,const char * topic,const char * pmu_name,const char * event_name,const char * event_alias,const char * scale_unit __maybe_unused,bool deprecated,const char * event_type_desc,const char * desc,const char * long_desc,const char * encoding_desc)98*f38ab496SJean-Philippe Romain static void default_print_event(void *ps, const char *topic, const char *pmu_name,
99e5c6109fSIan Rogers const char *event_name, const char *event_alias,
100e5c6109fSIan Rogers const char *scale_unit __maybe_unused,
101e5c6109fSIan Rogers bool deprecated, const char *event_type_desc,
102e5c6109fSIan Rogers const char *desc, const char *long_desc,
103d9dc8874SIan Rogers const char *encoding_desc)
104e5c6109fSIan Rogers {
105e5c6109fSIan Rogers struct print_state *print_state = ps;
106e5c6109fSIan Rogers int pos;
107e5c6109fSIan Rogers
108e5c6109fSIan Rogers if (deprecated && !print_state->deprecated)
109e5c6109fSIan Rogers return;
110e5c6109fSIan Rogers
111e5c6109fSIan Rogers if (print_state->pmu_glob && pmu_name && !strglobmatch(pmu_name, print_state->pmu_glob))
112e5c6109fSIan Rogers return;
113e5c6109fSIan Rogers
114e5c6109fSIan Rogers if (print_state->event_glob &&
115e5c6109fSIan Rogers (!event_name || !strglobmatch(event_name, print_state->event_glob)) &&
116e5c6109fSIan Rogers (!event_alias || !strglobmatch(event_alias, print_state->event_glob)) &&
117e5c6109fSIan Rogers (!topic || !strglobmatch_nocase(topic, print_state->event_glob)))
118e5c6109fSIan Rogers return;
119e5c6109fSIan Rogers
120e5c6109fSIan Rogers if (print_state->name_only) {
121e5c6109fSIan Rogers if (event_alias && strlen(event_alias))
122e5c6109fSIan Rogers printf("%s ", event_alias);
123e5c6109fSIan Rogers else
124e5c6109fSIan Rogers printf("%s ", event_name);
125e5c6109fSIan Rogers return;
126e5c6109fSIan Rogers }
127e5c6109fSIan Rogers
128e5c6109fSIan Rogers if (strcmp(print_state->last_topic, topic ?: "")) {
129e5c6109fSIan Rogers if (topic)
130e5c6109fSIan Rogers printf("\n%s:\n", topic);
131b20c6308SArnaldo Carvalho de Melo zfree(&print_state->last_topic);
132e5c6109fSIan Rogers print_state->last_topic = strdup(topic ?: "");
133e5c6109fSIan Rogers }
134e5c6109fSIan Rogers
135e5c6109fSIan Rogers if (event_alias && strlen(event_alias))
136e5c6109fSIan Rogers pos = printf(" %s OR %s", event_name, event_alias);
137e5c6109fSIan Rogers else
138e5c6109fSIan Rogers pos = printf(" %s", event_name);
139e5c6109fSIan Rogers
140e5c6109fSIan Rogers if (!topic && event_type_desc) {
141e5c6109fSIan Rogers for (; pos < 53; pos++)
142e5c6109fSIan Rogers putchar(' ');
143e5c6109fSIan Rogers printf("[%s]\n", event_type_desc);
144e5c6109fSIan Rogers } else
145e5c6109fSIan Rogers putchar('\n');
146e5c6109fSIan Rogers
147e5c6109fSIan Rogers if (desc && print_state->desc) {
148eeb6b129SIan Rogers char *desc_with_unit = NULL;
149eeb6b129SIan Rogers int desc_len = -1;
150eeb6b129SIan Rogers
151478c3f5dSIan Rogers if (pmu_name && strcmp(pmu_name, "default_core")) {
152eeb6b129SIan Rogers desc_len = strlen(desc);
153eeb6b129SIan Rogers desc_len = asprintf(&desc_with_unit,
154eeb6b129SIan Rogers desc[desc_len - 1] != '.'
155eeb6b129SIan Rogers ? "%s. Unit: %s" : "%s Unit: %s",
156eeb6b129SIan Rogers desc, pmu_name);
157eeb6b129SIan Rogers }
158e5c6109fSIan Rogers printf("%*s", 8, "[");
159eeb6b129SIan Rogers wordwrap(desc_len > 0 ? desc_with_unit : desc, 8, pager_get_columns(), 0);
160e5c6109fSIan Rogers printf("]\n");
161eeb6b129SIan Rogers free(desc_with_unit);
162e5c6109fSIan Rogers }
1631a9c20b4SIan Rogers long_desc = long_desc ?: desc;
164e5c6109fSIan Rogers if (long_desc && print_state->long_desc) {
165e5c6109fSIan Rogers printf("%*s", 8, "[");
166e5c6109fSIan Rogers wordwrap(long_desc, 8, pager_get_columns(), 0);
167e5c6109fSIan Rogers printf("]\n");
168e5c6109fSIan Rogers }
169e5c6109fSIan Rogers
170e5c6109fSIan Rogers if (print_state->detailed && encoding_desc) {
1711a9c20b4SIan Rogers printf("%*s", 8, "");
1721a9c20b4SIan Rogers wordwrap(encoding_desc, 8, pager_get_columns(), 0);
173e5c6109fSIan Rogers putchar('\n');
174e5c6109fSIan Rogers }
175e5c6109fSIan Rogers }
176e5c6109fSIan Rogers
default_print_metric(void * ps,const char * group,const char * name,const char * desc,const char * long_desc,const char * expr,const char * threshold,const char * unit __maybe_unused)177e5c6109fSIan Rogers static void default_print_metric(void *ps,
178e5c6109fSIan Rogers const char *group,
179e5c6109fSIan Rogers const char *name,
180e5c6109fSIan Rogers const char *desc,
181e5c6109fSIan Rogers const char *long_desc,
182e5c6109fSIan Rogers const char *expr,
183c7551a2eSIan Rogers const char *threshold,
184e5c6109fSIan Rogers const char *unit __maybe_unused)
185e5c6109fSIan Rogers {
186e5c6109fSIan Rogers struct print_state *print_state = ps;
187e5c6109fSIan Rogers
188e5c6109fSIan Rogers if (print_state->event_glob &&
189e5c6109fSIan Rogers (!print_state->metrics || !name || !strglobmatch(name, print_state->event_glob)) &&
190e5c6109fSIan Rogers (!print_state->metricgroups || !group || !strglobmatch(group, print_state->event_glob)))
191e5c6109fSIan Rogers return;
192e5c6109fSIan Rogers
193e5c6109fSIan Rogers if (!print_state->name_only && !print_state->last_metricgroups) {
194e5c6109fSIan Rogers if (print_state->metricgroups) {
195e5c6109fSIan Rogers printf("\nMetric Groups:\n");
196e5c6109fSIan Rogers if (!print_state->metrics)
197e5c6109fSIan Rogers putchar('\n');
198e5c6109fSIan Rogers } else {
199e5c6109fSIan Rogers printf("\nMetrics:\n\n");
200e5c6109fSIan Rogers }
201e5c6109fSIan Rogers }
202e5c6109fSIan Rogers if (!print_state->last_metricgroups ||
203e5c6109fSIan Rogers strcmp(print_state->last_metricgroups, group ?: "")) {
204e5c6109fSIan Rogers if (group && print_state->metricgroups) {
205e5c6109fSIan Rogers if (print_state->name_only)
206e5c6109fSIan Rogers printf("%s ", group);
20766c6e0c1SIan Rogers else if (print_state->metrics) {
20866c6e0c1SIan Rogers const char *gdesc = describe_metricgroup(group);
20966c6e0c1SIan Rogers
21066c6e0c1SIan Rogers if (gdesc)
21166c6e0c1SIan Rogers printf("\n%s: [%s]\n", group, gdesc);
212e5c6109fSIan Rogers else
21366c6e0c1SIan Rogers printf("\n%s:\n", group);
21466c6e0c1SIan Rogers } else
215e5c6109fSIan Rogers printf("%s\n", group);
216e5c6109fSIan Rogers }
217b20c6308SArnaldo Carvalho de Melo zfree(&print_state->last_metricgroups);
218e5c6109fSIan Rogers print_state->last_metricgroups = strdup(group ?: "");
219e5c6109fSIan Rogers }
220e5c6109fSIan Rogers if (!print_state->metrics)
221e5c6109fSIan Rogers return;
222e5c6109fSIan Rogers
223e5c6109fSIan Rogers if (print_state->name_only) {
224e5c6109fSIan Rogers if (print_state->metrics &&
225e5c6109fSIan Rogers !strlist__has_entry(print_state->visited_metrics, name)) {
226e5c6109fSIan Rogers printf("%s ", name);
227e5c6109fSIan Rogers strlist__add(print_state->visited_metrics, name);
228e5c6109fSIan Rogers }
229e5c6109fSIan Rogers return;
230e5c6109fSIan Rogers }
231e5c6109fSIan Rogers printf(" %s\n", name);
232e5c6109fSIan Rogers
233e5c6109fSIan Rogers if (desc && print_state->desc) {
234e5c6109fSIan Rogers printf("%*s", 8, "[");
235e5c6109fSIan Rogers wordwrap(desc, 8, pager_get_columns(), 0);
236e5c6109fSIan Rogers printf("]\n");
237e5c6109fSIan Rogers }
238e5c6109fSIan Rogers if (long_desc && print_state->long_desc) {
239e5c6109fSIan Rogers printf("%*s", 8, "[");
240e5c6109fSIan Rogers wordwrap(long_desc, 8, pager_get_columns(), 0);
241e5c6109fSIan Rogers printf("]\n");
242e5c6109fSIan Rogers }
243e5c6109fSIan Rogers if (expr && print_state->detailed) {
244e5c6109fSIan Rogers printf("%*s", 8, "[");
245e5c6109fSIan Rogers wordwrap(expr, 8, pager_get_columns(), 0);
246e5c6109fSIan Rogers printf("]\n");
247e5c6109fSIan Rogers }
248c7551a2eSIan Rogers if (threshold && print_state->detailed) {
249c7551a2eSIan Rogers printf("%*s", 8, "[");
250c7551a2eSIan Rogers wordwrap(threshold, 8, pager_get_columns(), 0);
251c7551a2eSIan Rogers printf("]\n");
252c7551a2eSIan Rogers }
253e5c6109fSIan Rogers }
2541c5f01feSAndi Kleen
2556ed24944SIan Rogers struct json_print_state {
2566ed24944SIan Rogers /** Should a separator be printed prior to the next item? */
2576ed24944SIan Rogers bool need_sep;
2586ed24944SIan Rogers };
2596ed24944SIan Rogers
json_print_start(void * print_state __maybe_unused)2606ed24944SIan Rogers static void json_print_start(void *print_state __maybe_unused)
2616ed24944SIan Rogers {
2626ed24944SIan Rogers printf("[\n");
2636ed24944SIan Rogers }
2646ed24944SIan Rogers
json_print_end(void * ps)2656ed24944SIan Rogers static void json_print_end(void *ps)
2666ed24944SIan Rogers {
2676ed24944SIan Rogers struct json_print_state *print_state = ps;
2686ed24944SIan Rogers
2696ed24944SIan Rogers printf("%s]\n", print_state->need_sep ? "\n" : "");
2706ed24944SIan Rogers }
2716ed24944SIan Rogers
fix_escape_printf(struct strbuf * buf,const char * fmt,...)2721284ded7SIan Rogers static void fix_escape_printf(struct strbuf *buf, const char *fmt, ...)
2736ed24944SIan Rogers {
2746ed24944SIan Rogers va_list args;
2756ed24944SIan Rogers
2766ed24944SIan Rogers va_start(args, fmt);
2771284ded7SIan Rogers strbuf_setlen(buf, 0);
2786ed24944SIan Rogers for (size_t fmt_pos = 0; fmt_pos < strlen(fmt); fmt_pos++) {
2796ed24944SIan Rogers switch (fmt[fmt_pos]) {
2801284ded7SIan Rogers case '%':
2811284ded7SIan Rogers fmt_pos++;
2821284ded7SIan Rogers switch (fmt[fmt_pos]) {
2831284ded7SIan Rogers case 's': {
2846ed24944SIan Rogers const char *s = va_arg(args, const char*);
2856ed24944SIan Rogers
2861284ded7SIan Rogers strbuf_addstr(buf, s);
2871284ded7SIan Rogers break;
2881284ded7SIan Rogers }
2891284ded7SIan Rogers case 'S': {
2901284ded7SIan Rogers const char *s = va_arg(args, const char*);
2911284ded7SIan Rogers
2926ed24944SIan Rogers for (size_t s_pos = 0; s_pos < strlen(s); s_pos++) {
2936ed24944SIan Rogers switch (s[s_pos]) {
2941284ded7SIan Rogers case '\n':
2951284ded7SIan Rogers strbuf_addstr(buf, "\\n");
2961284ded7SIan Rogers break;
2976ed24944SIan Rogers case '\\':
298f7a858bfSLiam Howlett fallthrough;
2996ed24944SIan Rogers case '\"':
3001284ded7SIan Rogers strbuf_addch(buf, '\\');
301f7a858bfSLiam Howlett fallthrough;
3026ed24944SIan Rogers default:
3031284ded7SIan Rogers strbuf_addch(buf, s[s_pos]);
3046ed24944SIan Rogers break;
3056ed24944SIan Rogers }
3066ed24944SIan Rogers }
3076ed24944SIan Rogers break;
3086ed24944SIan Rogers }
3096ed24944SIan Rogers default:
3101284ded7SIan Rogers pr_err("Unexpected format character '%c'\n", fmt[fmt_pos]);
3111284ded7SIan Rogers strbuf_addch(buf, '%');
3121284ded7SIan Rogers strbuf_addch(buf, fmt[fmt_pos]);
3131284ded7SIan Rogers }
3141284ded7SIan Rogers break;
3151284ded7SIan Rogers default:
3161284ded7SIan Rogers strbuf_addch(buf, fmt[fmt_pos]);
3176ed24944SIan Rogers break;
3186ed24944SIan Rogers }
3196ed24944SIan Rogers }
3206ed24944SIan Rogers va_end(args);
3211284ded7SIan Rogers fputs(buf->buf, stdout);
3226ed24944SIan Rogers }
3236ed24944SIan Rogers
json_print_event(void * ps,const char * topic,const char * pmu_name,const char * event_name,const char * event_alias,const char * scale_unit,bool deprecated,const char * event_type_desc,const char * desc,const char * long_desc,const char * encoding_desc)324*f38ab496SJean-Philippe Romain static void json_print_event(void *ps, const char *topic, const char *pmu_name,
3256ed24944SIan Rogers const char *event_name, const char *event_alias,
3266ed24944SIan Rogers const char *scale_unit,
3276ed24944SIan Rogers bool deprecated, const char *event_type_desc,
3286ed24944SIan Rogers const char *desc, const char *long_desc,
329d9dc8874SIan Rogers const char *encoding_desc)
3306ed24944SIan Rogers {
3316ed24944SIan Rogers struct json_print_state *print_state = ps;
3326ed24944SIan Rogers bool need_sep = false;
3331284ded7SIan Rogers struct strbuf buf;
3346ed24944SIan Rogers
3351284ded7SIan Rogers strbuf_init(&buf, 0);
3366ed24944SIan Rogers printf("%s{\n", print_state->need_sep ? ",\n" : "");
3376ed24944SIan Rogers print_state->need_sep = true;
3386ed24944SIan Rogers if (pmu_name) {
3391284ded7SIan Rogers fix_escape_printf(&buf, "\t\"Unit\": \"%S\"", pmu_name);
3406ed24944SIan Rogers need_sep = true;
3416ed24944SIan Rogers }
3426ed24944SIan Rogers if (topic) {
3431284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"Topic\": \"%S\"", need_sep ? ",\n" : "", topic);
3446ed24944SIan Rogers need_sep = true;
3456ed24944SIan Rogers }
3466ed24944SIan Rogers if (event_name) {
3471284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"EventName\": \"%S\"", need_sep ? ",\n" : "",
3481284ded7SIan Rogers event_name);
3496ed24944SIan Rogers need_sep = true;
3506ed24944SIan Rogers }
3516ed24944SIan Rogers if (event_alias && strlen(event_alias)) {
3521284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"EventAlias\": \"%S\"", need_sep ? ",\n" : "",
3531284ded7SIan Rogers event_alias);
3546ed24944SIan Rogers need_sep = true;
3556ed24944SIan Rogers }
3566ed24944SIan Rogers if (scale_unit && strlen(scale_unit)) {
3571284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"ScaleUnit\": \"%S\"", need_sep ? ",\n" : "",
3586ed24944SIan Rogers scale_unit);
3596ed24944SIan Rogers need_sep = true;
3606ed24944SIan Rogers }
3616ed24944SIan Rogers if (event_type_desc) {
3621284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"EventType\": \"%S\"", need_sep ? ",\n" : "",
3636ed24944SIan Rogers event_type_desc);
3646ed24944SIan Rogers need_sep = true;
3656ed24944SIan Rogers }
3666ed24944SIan Rogers if (deprecated) {
3671284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"Deprecated\": \"%S\"", need_sep ? ",\n" : "",
3686ed24944SIan Rogers deprecated ? "1" : "0");
3696ed24944SIan Rogers need_sep = true;
3706ed24944SIan Rogers }
3716ed24944SIan Rogers if (desc) {
3721284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"BriefDescription\": \"%S\"", need_sep ? ",\n" : "",
3731284ded7SIan Rogers desc);
3746ed24944SIan Rogers need_sep = true;
3756ed24944SIan Rogers }
3766ed24944SIan Rogers if (long_desc) {
3771284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"PublicDescription\": \"%S\"", need_sep ? ",\n" : "",
3786ed24944SIan Rogers long_desc);
3796ed24944SIan Rogers need_sep = true;
3806ed24944SIan Rogers }
3816ed24944SIan Rogers if (encoding_desc) {
3821284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"Encoding\": \"%S\"", need_sep ? ",\n" : "",
3831284ded7SIan Rogers encoding_desc);
3846ed24944SIan Rogers need_sep = true;
3856ed24944SIan Rogers }
3866ed24944SIan Rogers printf("%s}", need_sep ? "\n" : "");
3871284ded7SIan Rogers strbuf_release(&buf);
3886ed24944SIan Rogers }
3896ed24944SIan Rogers
json_print_metric(void * ps __maybe_unused,const char * group,const char * name,const char * desc,const char * long_desc,const char * expr,const char * threshold,const char * unit)3906ed24944SIan Rogers static void json_print_metric(void *ps __maybe_unused, const char *group,
3916ed24944SIan Rogers const char *name, const char *desc,
3926ed24944SIan Rogers const char *long_desc, const char *expr,
393c7551a2eSIan Rogers const char *threshold, const char *unit)
3946ed24944SIan Rogers {
3956ed24944SIan Rogers struct json_print_state *print_state = ps;
3966ed24944SIan Rogers bool need_sep = false;
3971284ded7SIan Rogers struct strbuf buf;
3986ed24944SIan Rogers
3991284ded7SIan Rogers strbuf_init(&buf, 0);
4006ed24944SIan Rogers printf("%s{\n", print_state->need_sep ? ",\n" : "");
4016ed24944SIan Rogers print_state->need_sep = true;
4026ed24944SIan Rogers if (group) {
4031284ded7SIan Rogers fix_escape_printf(&buf, "\t\"MetricGroup\": \"%S\"", group);
4046ed24944SIan Rogers need_sep = true;
4056ed24944SIan Rogers }
4066ed24944SIan Rogers if (name) {
4071284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"MetricName\": \"%S\"", need_sep ? ",\n" : "", name);
4086ed24944SIan Rogers need_sep = true;
4096ed24944SIan Rogers }
4106ed24944SIan Rogers if (expr) {
4111284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"MetricExpr\": \"%S\"", need_sep ? ",\n" : "", expr);
4126ed24944SIan Rogers need_sep = true;
4136ed24944SIan Rogers }
414c7551a2eSIan Rogers if (threshold) {
415c7551a2eSIan Rogers fix_escape_printf(&buf, "%s\t\"MetricThreshold\": \"%S\"", need_sep ? ",\n" : "",
416c7551a2eSIan Rogers threshold);
417c7551a2eSIan Rogers need_sep = true;
418c7551a2eSIan Rogers }
4196ed24944SIan Rogers if (unit) {
4201284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"ScaleUnit\": \"%S\"", need_sep ? ",\n" : "", unit);
4216ed24944SIan Rogers need_sep = true;
4226ed24944SIan Rogers }
4236ed24944SIan Rogers if (desc) {
4241284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"BriefDescription\": \"%S\"", need_sep ? ",\n" : "",
4251284ded7SIan Rogers desc);
4266ed24944SIan Rogers need_sep = true;
4276ed24944SIan Rogers }
4286ed24944SIan Rogers if (long_desc) {
4291284ded7SIan Rogers fix_escape_printf(&buf, "%s\t\"PublicDescription\": \"%S\"", need_sep ? ",\n" : "",
4306ed24944SIan Rogers long_desc);
4316ed24944SIan Rogers need_sep = true;
4326ed24944SIan Rogers }
4336ed24944SIan Rogers printf("%s}", need_sep ? "\n" : "");
4341284ded7SIan Rogers strbuf_release(&buf);
4356ed24944SIan Rogers }
4366ed24944SIan Rogers
json_skip_duplicate_pmus(void * ps __maybe_unused)4371f4d4d2cSIan Rogers static bool json_skip_duplicate_pmus(void *ps __maybe_unused)
4381f4d4d2cSIan Rogers {
4391f4d4d2cSIan Rogers return false;
4401f4d4d2cSIan Rogers }
4411f4d4d2cSIan Rogers
default_skip_duplicate_pmus(void * ps)442cd4e1efbSIan Rogers static bool default_skip_duplicate_pmus(void *ps)
443cd4e1efbSIan Rogers {
444cd4e1efbSIan Rogers struct print_state *print_state = ps;
445cd4e1efbSIan Rogers
446cd4e1efbSIan Rogers return !print_state->long_desc;
447cd4e1efbSIan Rogers }
448cd4e1efbSIan Rogers
cmd_list(int argc,const char ** argv)449b0ad8ea6SArnaldo Carvalho de Melo int cmd_list(int argc, const char **argv)
45086470930SIngo Molnar {
4510e0ae874SJin Yao int i, ret = 0;
4526ed24944SIan Rogers struct print_state default_ps = {};
4536ed24944SIan Rogers struct print_state json_ps = {};
4546ed24944SIan Rogers void *ps = &default_ps;
455e5c6109fSIan Rogers struct print_callbacks print_cb = {
456e5c6109fSIan Rogers .print_start = default_print_start,
457e5c6109fSIan Rogers .print_end = default_print_end,
458e5c6109fSIan Rogers .print_event = default_print_event,
459e5c6109fSIan Rogers .print_metric = default_print_metric,
460cd4e1efbSIan Rogers .skip_duplicate_pmus = default_skip_duplicate_pmus,
461e5c6109fSIan Rogers };
462003be8c4SIan Rogers const char *cputype = NULL;
463ca0fe624SIan Rogers const char *unit_name = NULL;
4646ed24944SIan Rogers bool json = false;
465b3505208STaesoo Kim struct option list_options[] = {
4666ed24944SIan Rogers OPT_BOOLEAN(0, "raw-dump", &default_ps.name_only, "Dump raw events"),
4676ed24944SIan Rogers OPT_BOOLEAN('j', "json", &json, "JSON encode events and metrics"),
4686ed24944SIan Rogers OPT_BOOLEAN('d', "desc", &default_ps.desc,
4691c5f01feSAndi Kleen "Print extra event descriptions. --no-desc to not print."),
4706ed24944SIan Rogers OPT_BOOLEAN('v', "long-desc", &default_ps.long_desc,
471c8d6828aSSukadev Bhattiprolu "Print longer event descriptions."),
4726ed24944SIan Rogers OPT_BOOLEAN(0, "details", &default_ps.detailed,
473bf874fcfSAndi Kleen "Print information on the perf event names and expressions used internally by events."),
4746ed24944SIan Rogers OPT_BOOLEAN(0, "deprecated", &default_ps.deprecated,
475a7f6c8c8SJin Yao "Print deprecated events."),
476003be8c4SIan Rogers OPT_STRING(0, "cputype", &cputype, "cpu type",
477003be8c4SIan Rogers "Limit PMU or metric printing to the given PMU (e.g. cpu, core or atom)."),
478ca0fe624SIan Rogers OPT_STRING(0, "unit", &unit_name, "PMU name",
479ca0fe624SIan Rogers "Limit PMU or metric printing to the specified PMU."),
480f2361024SAndi Kleen OPT_INCR(0, "debug", &verbose,
481f2361024SAndi Kleen "Enable debugging output"),
48244d742e0SDavid Ahern OPT_END()
48344d742e0SDavid Ahern };
48444d742e0SDavid Ahern const char * const list_usage[] = {
485cc3d139bSIan Rogers #ifdef HAVE_LIBPFM
486cc3d139bSIan Rogers "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob|pfm]",
487cc3d139bSIan Rogers #else
488a90a1c54SIan Rogers "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]",
489cc3d139bSIan Rogers #endif
49044d742e0SDavid Ahern NULL
49144d742e0SDavid Ahern };
49244d742e0SDavid Ahern
493b3505208STaesoo Kim set_option_flag(list_options, 0, "raw-dump", PARSE_OPT_HIDDEN);
494ca0fe624SIan Rogers /* Hide hybrid flag for the more generic 'unit' flag. */
495ca0fe624SIan Rogers set_option_flag(list_options, 0, "cputype", PARSE_OPT_HIDDEN);
496b3505208STaesoo Kim
49744d742e0SDavid Ahern argc = parse_options(argc, argv, list_options, list_usage,
49844d742e0SDavid Ahern PARSE_OPT_STOP_AT_NON_OPTION);
4998e00ddc9SDavid Ahern
5008f7a0dc5SArnaldo Carvalho de Melo setup_pager();
501668b8788SArnaldo Carvalho de Melo
5026ed24944SIan Rogers if (!default_ps.name_only)
503e5c6109fSIan Rogers setup_pager();
504619a303cSYunlong Song
5056ed24944SIan Rogers if (json) {
5066ed24944SIan Rogers print_cb = (struct print_callbacks){
5076ed24944SIan Rogers .print_start = json_print_start,
5086ed24944SIan Rogers .print_end = json_print_end,
5096ed24944SIan Rogers .print_event = json_print_event,
5106ed24944SIan Rogers .print_metric = json_print_metric,
5111f4d4d2cSIan Rogers .skip_duplicate_pmus = json_skip_duplicate_pmus,
5126ed24944SIan Rogers };
5136ed24944SIan Rogers ps = &json_ps;
5146ed24944SIan Rogers } else {
5156ed24944SIan Rogers default_ps.desc = !default_ps.long_desc;
5166ed24944SIan Rogers default_ps.last_topic = strdup("");
5176ed24944SIan Rogers assert(default_ps.last_topic);
5186ed24944SIan Rogers default_ps.visited_metrics = strlist__new(NULL, NULL);
5196ed24944SIan Rogers assert(default_ps.visited_metrics);
520ca0fe624SIan Rogers if (unit_name)
5216ed24944SIan Rogers default_ps.pmu_glob = strdup(unit_name);
522003be8c4SIan Rogers else if (cputype) {
523003be8c4SIan Rogers const struct perf_pmu *pmu = perf_pmus__pmu_for_pmu_filter(cputype);
524003be8c4SIan Rogers
525003be8c4SIan Rogers if (!pmu) {
526003be8c4SIan Rogers pr_err("ERROR: cputype is not supported!\n");
527003be8c4SIan Rogers ret = -1;
528003be8c4SIan Rogers goto out;
529003be8c4SIan Rogers }
530c091ee90SIan Rogers default_ps.pmu_glob = strdup(pmu->name);
5310e0ae874SJin Yao }
5326ed24944SIan Rogers }
5336ed24944SIan Rogers print_cb.print_start(ps);
534e5c6109fSIan Rogers
53544d742e0SDavid Ahern if (argc == 0) {
5366ed24944SIan Rogers default_ps.metrics = true;
5376ed24944SIan Rogers default_ps.metricgroups = true;
5386ed24944SIan Rogers print_events(&print_cb, ps);
5390e0ae874SJin Yao goto out;
5408e00ddc9SDavid Ahern }
541668b8788SArnaldo Carvalho de Melo
54244d742e0SDavid Ahern for (i = 0; i < argc; ++i) {
543dbc67409SArnaldo Carvalho de Melo char *sep, *s;
544dbc67409SArnaldo Carvalho de Melo
54516114951SYunlong Song if (strcmp(argv[i], "tracepoint") == 0)
5466ed24944SIan Rogers print_tracepoint_events(&print_cb, ps);
547668b8788SArnaldo Carvalho de Melo else if (strcmp(argv[i], "hw") == 0 ||
548668b8788SArnaldo Carvalho de Melo strcmp(argv[i], "hardware") == 0)
5496ed24944SIan Rogers print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE,
550e5c6109fSIan Rogers event_symbols_hw, PERF_COUNT_HW_MAX);
551668b8788SArnaldo Carvalho de Melo else if (strcmp(argv[i], "sw") == 0 ||
5525e0861baSAndi Kleen strcmp(argv[i], "software") == 0) {
5536ed24944SIan Rogers print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE,
554e5c6109fSIan Rogers event_symbols_sw, PERF_COUNT_SW_MAX);
5556ed24944SIan Rogers print_tool_events(&print_cb, ps);
5565e0861baSAndi Kleen } else if (strcmp(argv[i], "cache") == 0 ||
557668b8788SArnaldo Carvalho de Melo strcmp(argv[i], "hwcache") == 0)
5586ed24944SIan Rogers print_hwcache_events(&print_cb, ps);
559dc098b35SAndi Kleen else if (strcmp(argv[i], "pmu") == 0)
5601eaf496eSIan Rogers perf_pmus__print_pmu_events(&print_cb, ps);
56140218daeSMasami Hiramatsu else if (strcmp(argv[i], "sdt") == 0)
5626ed24944SIan Rogers print_sdt_events(&print_cb, ps);
563e5c6109fSIan Rogers else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) {
5646ed24944SIan Rogers default_ps.metricgroups = false;
5656ed24944SIan Rogers default_ps.metrics = true;
5666ed24944SIan Rogers metricgroup__print(&print_cb, ps);
567e5c6109fSIan Rogers } else if (strcmp(argv[i], "metricgroup") == 0 ||
568e5c6109fSIan Rogers strcmp(argv[i], "metricgroups") == 0) {
5696ed24944SIan Rogers default_ps.metricgroups = true;
5706ed24944SIan Rogers default_ps.metrics = false;
5716ed24944SIan Rogers metricgroup__print(&print_cb, ps);
572cc3d139bSIan Rogers }
573cc3d139bSIan Rogers #ifdef HAVE_LIBPFM
574cc3d139bSIan Rogers else if (strcmp(argv[i], "pfm") == 0)
575cc3d139bSIan Rogers print_libpfm_events(&print_cb, ps);
576cc3d139bSIan Rogers #endif
577cc3d139bSIan Rogers else if ((sep = strchr(argv[i], ':')) != NULL) {
5786ed24944SIan Rogers char *old_pmu_glob = default_ps.pmu_glob;
579668b8788SArnaldo Carvalho de Melo
5806ed24944SIan Rogers default_ps.event_glob = strdup(argv[i]);
5816ed24944SIan Rogers if (!default_ps.event_glob) {
5820e0ae874SJin Yao ret = -1;
5830e0ae874SJin Yao goto out;
5840e0ae874SJin Yao }
585668b8788SArnaldo Carvalho de Melo
5866ed24944SIan Rogers print_tracepoint_events(&print_cb, ps);
5876ed24944SIan Rogers print_sdt_events(&print_cb, ps);
5886ed24944SIan Rogers default_ps.metrics = true;
5896ed24944SIan Rogers default_ps.metricgroups = true;
5906ed24944SIan Rogers metricgroup__print(&print_cb, ps);
5916ed24944SIan Rogers zfree(&default_ps.event_glob);
5926ed24944SIan Rogers default_ps.pmu_glob = old_pmu_glob;
593dbc67409SArnaldo Carvalho de Melo } else {
594dbc67409SArnaldo Carvalho de Melo if (asprintf(&s, "*%s*", argv[i]) < 0) {
595dbc67409SArnaldo Carvalho de Melo printf("Critical: Not enough memory! Trying to continue...\n");
596dbc67409SArnaldo Carvalho de Melo continue;
597dbc67409SArnaldo Carvalho de Melo }
5986ed24944SIan Rogers default_ps.event_glob = s;
5996ed24944SIan Rogers print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE,
600e5c6109fSIan Rogers event_symbols_hw, PERF_COUNT_HW_MAX);
6016ed24944SIan Rogers print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE,
602e5c6109fSIan Rogers event_symbols_sw, PERF_COUNT_SW_MAX);
6036ed24944SIan Rogers print_tool_events(&print_cb, ps);
6046ed24944SIan Rogers print_hwcache_events(&print_cb, ps);
6051eaf496eSIan Rogers perf_pmus__print_pmu_events(&print_cb, ps);
6066ed24944SIan Rogers print_tracepoint_events(&print_cb, ps);
6076ed24944SIan Rogers print_sdt_events(&print_cb, ps);
6086ed24944SIan Rogers default_ps.metrics = true;
6096ed24944SIan Rogers default_ps.metricgroups = true;
6106ed24944SIan Rogers metricgroup__print(&print_cb, ps);
611dbc67409SArnaldo Carvalho de Melo free(s);
612668b8788SArnaldo Carvalho de Melo }
613668b8788SArnaldo Carvalho de Melo }
6140e0ae874SJin Yao
6150e0ae874SJin Yao out:
6166ed24944SIan Rogers print_cb.print_end(ps);
6176ed24944SIan Rogers free(default_ps.pmu_glob);
6186ed24944SIan Rogers free(default_ps.last_topic);
6196ed24944SIan Rogers free(default_ps.last_metricgroups);
6206ed24944SIan Rogers strlist__delete(default_ps.visited_metrics);
6210e0ae874SJin Yao return ret;
62286470930SIngo Molnar }
623