xref: /linux/tools/perf/builtin-list.c (revision f4f346c3465949ebba80c6cc52cd8d2eeaa545fd)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * builtin-list.c
4  *
5  * Builtin list command: list all event types
6  *
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>
10  */
11 #include "builtin.h"
12 
13 #include "util/print-events.h"
14 #include "util/pmus.h"
15 #include "util/pmu.h"
16 #include "util/debug.h"
17 #include "util/metricgroup.h"
18 #include "util/pfm.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>
26 #include <ctype.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 
30 /**
31  * struct print_state - State and configuration passed to the default_print
32  * functions.
33  */
34 struct print_state {
35 	/** @fp: File to write output to. */
36 	FILE *fp;
37 	/**
38 	 * @pmu_glob: Optionally restrict PMU and metric matching to PMU or
39 	 * debugfs subsystem name.
40 	 */
41 	char *pmu_glob;
42 	/** @event_glob: Optional pattern matching glob. */
43 	char *event_glob;
44 	/** @name_only: Print event or metric names only. */
45 	bool name_only;
46 	/** @desc: Print the event or metric description. */
47 	bool desc;
48 	/** @long_desc: Print longer event or metric description. */
49 	bool long_desc;
50 	/** @deprecated: Print deprecated events or metrics. */
51 	bool deprecated;
52 	/**
53 	 * @detailed: Print extra information on the perf event such as names
54 	 * and expressions used internally by events.
55 	 */
56 	bool detailed;
57 	/** @metrics: Controls printing of metric and metric groups. */
58 	bool metrics;
59 	/** @metricgroups: Controls printing of metric and metric groups. */
60 	bool metricgroups;
61 	/** @exclude_abi: Exclude PMUs with types less than PERF_TYPE_MAX except PERF_TYPE_RAW. */
62 	bool exclude_abi;
63 	/** @last_topic: The last printed event topic. */
64 	char *last_topic;
65 	/** @last_metricgroups: The last printed metric group. */
66 	char *last_metricgroups;
67 	/** @visited_metrics: Metrics that are printed to avoid duplicates. */
68 	struct strlist *visited_metrics;
69 };
70 
default_print_start(void * ps)71 static void default_print_start(void *ps)
72 {
73 	struct print_state *print_state = ps;
74 
75 	if (!print_state->name_only && pager_in_use()) {
76 		fprintf(print_state->fp,
77 			"\nList of pre-defined events (to be used in -e or -M):\n\n");
78 	}
79 }
80 
default_print_end(void * print_state __maybe_unused)81 static void default_print_end(void *print_state __maybe_unused) {}
82 
skip_spaces_or_commas(const char * str)83 static const char *skip_spaces_or_commas(const char *str)
84 {
85 	while (isspace(*str) || *str == ',')
86 		++str;
87 	return str;
88 }
89 
wordwrap(FILE * fp,const char * s,int start,int max,int corr)90 static void wordwrap(FILE *fp, const char *s, int start, int max, int corr)
91 {
92 	int column = start;
93 	int n;
94 	bool saw_newline = false;
95 	bool comma = false;
96 
97 	while (*s) {
98 		int wlen = strcspn(s, " ,\t\n");
99 		const char *sep = comma ? "," : " ";
100 
101 		if ((column + wlen >= max && column > start) || saw_newline) {
102 			fprintf(fp, comma ? ",\n%*s" : "\n%*s", start, "");
103 			column = start + corr;
104 		}
105 		if (column <= start)
106 			sep = "";
107 		n = fprintf(fp, "%s%.*s", sep, wlen, s);
108 		if (n <= 0)
109 			break;
110 		saw_newline = s[wlen] == '\n';
111 		s += wlen;
112 		comma = s[0] == ',';
113 		column += n;
114 		s = skip_spaces_or_commas(s);
115 	}
116 }
117 
default_print_event(void * ps,const char * topic,const char * pmu_name,u32 pmu_type,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)118 static void default_print_event(void *ps, const char *topic,
119 				const char *pmu_name, u32 pmu_type,
120 				const char *event_name, const char *event_alias,
121 				const char *scale_unit __maybe_unused,
122 				bool deprecated, const char *event_type_desc,
123 				const char *desc, const char *long_desc,
124 				const char *encoding_desc)
125 {
126 	struct print_state *print_state = ps;
127 	int pos;
128 	FILE *fp = print_state->fp;
129 
130 	if (deprecated && !print_state->deprecated)
131 		return;
132 
133 	if (print_state->pmu_glob && pmu_name && !strglobmatch(pmu_name, print_state->pmu_glob))
134 		return;
135 
136 	if (print_state->exclude_abi && pmu_type < PERF_TYPE_MAX && pmu_type != PERF_TYPE_RAW)
137 		return;
138 
139 	if (print_state->event_glob &&
140 	    (!event_name || !strglobmatch(event_name, print_state->event_glob)) &&
141 	    (!event_alias || !strglobmatch(event_alias, print_state->event_glob)) &&
142 	    (!topic || !strglobmatch_nocase(topic, print_state->event_glob)))
143 		return;
144 
145 	if (print_state->name_only) {
146 		if (event_alias && strlen(event_alias))
147 			fprintf(fp, "%s ", event_alias);
148 		else
149 			fprintf(fp, "%s ", event_name);
150 		return;
151 	}
152 
153 	if (strcmp(print_state->last_topic, topic ?: "")) {
154 		if (topic)
155 			fprintf(fp, "\n%s:\n", topic);
156 		zfree(&print_state->last_topic);
157 		print_state->last_topic = strdup(topic ?: "");
158 	}
159 
160 	if (event_alias && strlen(event_alias))
161 		pos = fprintf(fp, "  %s OR %s", event_name, event_alias);
162 	else
163 		pos = fprintf(fp, "  %s", event_name);
164 
165 	if (!topic && event_type_desc) {
166 		for (; pos < 53; pos++)
167 			fputc(' ', fp);
168 		fprintf(fp, "[%s]\n", event_type_desc);
169 	} else
170 		fputc('\n', fp);
171 
172 	if (long_desc && print_state->long_desc)
173 		desc = long_desc;
174 
175 	if (desc && (print_state->desc || print_state->long_desc)) {
176 		char *desc_with_unit = NULL;
177 		int desc_len = -1;
178 
179 		if (pmu_name && strcmp(pmu_name, "default_core")) {
180 			desc_len = strlen(desc);
181 			desc_len = asprintf(&desc_with_unit,
182 					    desc_len > 0 && desc[desc_len - 1] != '.'
183 					      ? "%s. Unit: %s" : "%s Unit: %s",
184 					    desc, pmu_name);
185 		}
186 		fprintf(fp, "%*s", 8, "[");
187 		wordwrap(fp, desc_len > 0 ? desc_with_unit : desc, 8, pager_get_columns(), 0);
188 		fprintf(fp, "]\n");
189 		free(desc_with_unit);
190 	}
191 
192 	if (print_state->detailed && encoding_desc) {
193 		fprintf(fp, "%*s", 8, "");
194 		wordwrap(fp, encoding_desc, 8, pager_get_columns(), 0);
195 		fputc('\n', fp);
196 	}
197 }
198 
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,const char * pmu_name __maybe_unused)199 static void default_print_metric(void *ps,
200 				const char *group,
201 				const char *name,
202 				const char *desc,
203 				const char *long_desc,
204 				const char *expr,
205 				const char *threshold,
206 				const char *unit __maybe_unused,
207 				const char *pmu_name __maybe_unused)
208 {
209 	struct print_state *print_state = ps;
210 	FILE *fp = print_state->fp;
211 
212 	if (print_state->event_glob &&
213 	    (!print_state->metrics || !name || !strglobmatch(name, print_state->event_glob)) &&
214 	    (!print_state->metricgroups || !group || !strglobmatch(group, print_state->event_glob)))
215 		return;
216 
217 	if (!print_state->name_only && !print_state->last_metricgroups) {
218 		if (print_state->metricgroups) {
219 			fprintf(fp, "\nMetric Groups:\n");
220 			if (!print_state->metrics)
221 				fputc('\n', fp);
222 		} else {
223 			fprintf(fp, "\nMetrics:\n\n");
224 		}
225 	}
226 	if (!print_state->last_metricgroups ||
227 	    strcmp(print_state->last_metricgroups, group ?: "")) {
228 		if (group && print_state->metricgroups) {
229 			if (print_state->name_only) {
230 				fprintf(fp, "%s ", group);
231 			} else {
232 				const char *gdesc = print_state->desc
233 					? describe_metricgroup(group)
234 					: NULL;
235 				const char *print_colon = "";
236 
237 				if (print_state->metrics) {
238 					print_colon = ":";
239 					fputc('\n', fp);
240 				}
241 
242 				if (gdesc)
243 					fprintf(fp, "%s%s [%s]\n", group, print_colon, gdesc);
244 				else
245 					fprintf(fp, "%s%s\n", group, print_colon);
246 			}
247 		}
248 		zfree(&print_state->last_metricgroups);
249 		print_state->last_metricgroups = strdup(group ?: "");
250 	}
251 	if (!print_state->metrics)
252 		return;
253 
254 	if (print_state->name_only) {
255 		if (print_state->metrics &&
256 		    !strlist__has_entry(print_state->visited_metrics, name)) {
257 			fprintf(fp, "%s ", name);
258 			strlist__add(print_state->visited_metrics, name);
259 		}
260 		return;
261 	}
262 	fprintf(fp, "  %s\n", name);
263 
264 	if (long_desc && print_state->long_desc) {
265 		fprintf(fp, "%*s", 8, "[");
266 		wordwrap(fp, long_desc, 8, pager_get_columns(), 0);
267 		fprintf(fp, "]\n");
268 	} else if (desc && print_state->desc) {
269 		fprintf(fp, "%*s", 8, "[");
270 		wordwrap(fp, desc, 8, pager_get_columns(), 0);
271 		fprintf(fp, "]\n");
272 	}
273 	if (expr && print_state->detailed) {
274 		fprintf(fp, "%*s", 8, "[");
275 		wordwrap(fp, expr, 8, pager_get_columns(), 0);
276 		fprintf(fp, "]\n");
277 	}
278 	if (threshold && print_state->detailed) {
279 		fprintf(fp, "%*s", 8, "[");
280 		wordwrap(fp, threshold, 8, pager_get_columns(), 0);
281 		fprintf(fp, "]\n");
282 	}
283 }
284 
285 struct json_print_state {
286 	/** @fp: File to write output to. */
287 	FILE *fp;
288 	/** Should a separator be printed prior to the next item? */
289 	bool need_sep;
290 };
291 
json_print_start(void * ps)292 static void json_print_start(void *ps)
293 {
294 	struct json_print_state *print_state = ps;
295 	FILE *fp = print_state->fp;
296 
297 	fprintf(fp, "[\n");
298 }
299 
json_print_end(void * ps)300 static void json_print_end(void *ps)
301 {
302 	struct json_print_state *print_state = ps;
303 	FILE *fp = print_state->fp;
304 
305 	fprintf(fp, "%s]\n", print_state->need_sep ? "\n" : "");
306 }
307 
fix_escape_fprintf(FILE * fp,struct strbuf * buf,const char * fmt,...)308 static void fix_escape_fprintf(FILE *fp, struct strbuf *buf, const char *fmt, ...)
309 {
310 	va_list args;
311 
312 	va_start(args, fmt);
313 	strbuf_setlen(buf, 0);
314 	for (size_t fmt_pos = 0; fmt_pos < strlen(fmt); fmt_pos++) {
315 		switch (fmt[fmt_pos]) {
316 		case '%':
317 			fmt_pos++;
318 			switch (fmt[fmt_pos]) {
319 			case 's': {
320 				const char *s = va_arg(args, const char*);
321 
322 				strbuf_addstr(buf, s);
323 				break;
324 			}
325 			case 'S': {
326 				const char *s = va_arg(args, const char*);
327 
328 				for (size_t s_pos = 0; s_pos < strlen(s); s_pos++) {
329 					switch (s[s_pos]) {
330 					case '\n':
331 						strbuf_addstr(buf, "\\n");
332 						break;
333 					case '\r':
334 						strbuf_addstr(buf, "\\r");
335 						break;
336 					case '\\':
337 						fallthrough;
338 					case '\"':
339 						strbuf_addch(buf, '\\');
340 						fallthrough;
341 					default:
342 						strbuf_addch(buf, s[s_pos]);
343 						break;
344 					}
345 				}
346 				break;
347 			}
348 			default:
349 				pr_err("Unexpected format character '%c'\n", fmt[fmt_pos]);
350 				strbuf_addch(buf, '%');
351 				strbuf_addch(buf, fmt[fmt_pos]);
352 			}
353 			break;
354 		default:
355 			strbuf_addch(buf, fmt[fmt_pos]);
356 			break;
357 		}
358 	}
359 	va_end(args);
360 	fputs(buf->buf, fp);
361 }
362 
json_print_event(void * ps,const char * topic,const char * pmu_name,u32 pmu_type __maybe_unused,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)363 static void json_print_event(void *ps, const char *topic,
364 			     const char *pmu_name, u32 pmu_type __maybe_unused,
365 			     const char *event_name, const char *event_alias,
366 			     const char *scale_unit,
367 			     bool deprecated, const char *event_type_desc,
368 			     const char *desc, const char *long_desc,
369 			     const char *encoding_desc)
370 {
371 	struct json_print_state *print_state = ps;
372 	bool need_sep = false;
373 	FILE *fp = print_state->fp;
374 	struct strbuf buf;
375 
376 	strbuf_init(&buf, 0);
377 	fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : "");
378 	print_state->need_sep = true;
379 	if (pmu_name) {
380 		fix_escape_fprintf(fp, &buf, "\t\"Unit\": \"%S\"", pmu_name);
381 		need_sep = true;
382 	}
383 	if (topic) {
384 		fix_escape_fprintf(fp, &buf, "%s\t\"Topic\": \"%S\"",
385 				   need_sep ? ",\n" : "",
386 				   topic);
387 		need_sep = true;
388 	}
389 	if (event_name) {
390 		fix_escape_fprintf(fp, &buf, "%s\t\"EventName\": \"%S\"",
391 				   need_sep ? ",\n" : "",
392 				   event_name);
393 		need_sep = true;
394 	}
395 	if (event_alias && strlen(event_alias)) {
396 		fix_escape_fprintf(fp, &buf, "%s\t\"EventAlias\": \"%S\"",
397 				   need_sep ? ",\n" : "",
398 				   event_alias);
399 		need_sep = true;
400 	}
401 	if (scale_unit && strlen(scale_unit)) {
402 		fix_escape_fprintf(fp, &buf, "%s\t\"ScaleUnit\": \"%S\"",
403 				   need_sep ? ",\n" : "",
404 				   scale_unit);
405 		need_sep = true;
406 	}
407 	if (event_type_desc) {
408 		fix_escape_fprintf(fp, &buf, "%s\t\"EventType\": \"%S\"",
409 				   need_sep ? ",\n" : "",
410 				   event_type_desc);
411 		need_sep = true;
412 	}
413 	if (deprecated) {
414 		fix_escape_fprintf(fp, &buf, "%s\t\"Deprecated\": \"%S\"",
415 				   need_sep ? ",\n" : "",
416 				   deprecated ? "1" : "0");
417 		need_sep = true;
418 	}
419 	if (desc) {
420 		fix_escape_fprintf(fp, &buf, "%s\t\"BriefDescription\": \"%S\"",
421 				   need_sep ? ",\n" : "",
422 				   desc);
423 		need_sep = true;
424 	}
425 	if (long_desc) {
426 		fix_escape_fprintf(fp, &buf, "%s\t\"PublicDescription\": \"%S\"",
427 				   need_sep ? ",\n" : "",
428 				   long_desc);
429 		need_sep = true;
430 	}
431 	if (encoding_desc) {
432 		fix_escape_fprintf(fp, &buf, "%s\t\"Encoding\": \"%S\"",
433 				   need_sep ? ",\n" : "",
434 				   encoding_desc);
435 		need_sep = true;
436 	}
437 	fprintf(fp, "%s}", need_sep ? "\n" : "");
438 	strbuf_release(&buf);
439 }
440 
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,const char * pmu_name)441 static void json_print_metric(void *ps __maybe_unused, const char *group,
442 			      const char *name, const char *desc,
443 			      const char *long_desc, const char *expr,
444 			      const char *threshold, const char *unit,
445 			      const char *pmu_name)
446 {
447 	struct json_print_state *print_state = ps;
448 	bool need_sep = false;
449 	FILE *fp = print_state->fp;
450 	struct strbuf buf;
451 
452 	strbuf_init(&buf, 0);
453 	fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : "");
454 	print_state->need_sep = true;
455 	if (group) {
456 		fix_escape_fprintf(fp, &buf, "\t\"MetricGroup\": \"%S\"", group);
457 		need_sep = true;
458 	}
459 	if (name) {
460 		fix_escape_fprintf(fp, &buf, "%s\t\"MetricName\": \"%S\"",
461 				   need_sep ? ",\n" : "",
462 				   name);
463 		need_sep = true;
464 	}
465 	if (expr) {
466 		fix_escape_fprintf(fp, &buf, "%s\t\"MetricExpr\": \"%S\"",
467 				   need_sep ? ",\n" : "",
468 				   expr);
469 		need_sep = true;
470 	}
471 	if (threshold) {
472 		fix_escape_fprintf(fp, &buf, "%s\t\"MetricThreshold\": \"%S\"",
473 				   need_sep ? ",\n" : "",
474 				   threshold);
475 		need_sep = true;
476 	}
477 	if (unit) {
478 		fix_escape_fprintf(fp, &buf, "%s\t\"ScaleUnit\": \"%S\"",
479 				   need_sep ? ",\n" : "",
480 				   unit);
481 		need_sep = true;
482 	}
483 	if (desc) {
484 		fix_escape_fprintf(fp, &buf, "%s\t\"BriefDescription\": \"%S\"",
485 				   need_sep ? ",\n" : "",
486 				   desc);
487 		need_sep = true;
488 	}
489 	if (long_desc) {
490 		fix_escape_fprintf(fp, &buf, "%s\t\"PublicDescription\": \"%S\"",
491 				   need_sep ? ",\n" : "",
492 				   long_desc);
493 		need_sep = true;
494 	}
495 	if (pmu_name) {
496 		fix_escape_fprintf(fp, &buf, "%s\t\"Unit\": \"%S\"",
497 				   need_sep ? ",\n" : "",
498 				   pmu_name);
499 		need_sep = true;
500 	}
501 	fprintf(fp, "%s}", need_sep ? "\n" : "");
502 	strbuf_release(&buf);
503 }
504 
json_skip_duplicate_pmus(void * ps __maybe_unused)505 static bool json_skip_duplicate_pmus(void *ps __maybe_unused)
506 {
507 	return false;
508 }
509 
default_skip_duplicate_pmus(void * ps)510 static bool default_skip_duplicate_pmus(void *ps)
511 {
512 	struct print_state *print_state = ps;
513 
514 	return !print_state->long_desc;
515 }
516 
cmd_list(int argc,const char ** argv)517 int cmd_list(int argc, const char **argv)
518 {
519 	int i, ret = 0;
520 	struct print_state default_ps = {
521 		.fp = stdout,
522 		.desc = true,
523 	};
524 	struct print_state json_ps = {
525 		.fp = stdout,
526 	};
527 	void *ps = &default_ps;
528 	struct print_callbacks print_cb = {
529 		.print_start = default_print_start,
530 		.print_end = default_print_end,
531 		.print_event = default_print_event,
532 		.print_metric = default_print_metric,
533 		.skip_duplicate_pmus = default_skip_duplicate_pmus,
534 	};
535 	const char *cputype = NULL;
536 	const char *unit_name = NULL;
537 	const char *output_path = NULL;
538 	bool json = false;
539 	struct option list_options[] = {
540 		OPT_BOOLEAN(0, "raw-dump", &default_ps.name_only, "Dump raw events"),
541 		OPT_BOOLEAN('j', "json", &json, "JSON encode events and metrics"),
542 		OPT_BOOLEAN('d', "desc", &default_ps.desc,
543 			    "Print extra event descriptions. --no-desc to not print."),
544 		OPT_BOOLEAN('v', "long-desc", &default_ps.long_desc,
545 			    "Print longer event descriptions and all similar PMUs with alphanumeric suffixes."),
546 		OPT_BOOLEAN(0, "details", &default_ps.detailed,
547 			    "Print information on the perf event names and expressions used internally by events."),
548 		OPT_STRING('o', "output", &output_path, "file", "output file name"),
549 		OPT_BOOLEAN(0, "deprecated", &default_ps.deprecated,
550 			    "Print deprecated events."),
551 		OPT_STRING(0, "cputype", &cputype, "cpu type",
552 			   "Limit PMU or metric printing to the given PMU (e.g. cpu, core or atom)."),
553 		OPT_STRING(0, "unit", &unit_name, "PMU name",
554 			   "Limit PMU or metric printing to the specified PMU."),
555 		OPT_INCR(0, "debug", &verbose,
556 			     "Enable debugging output"),
557 		OPT_END()
558 	};
559 	const char * const list_usage[] = {
560 #ifdef HAVE_LIBPFM
561 		"perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob|pfm]",
562 #else
563 		"perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]",
564 #endif
565 		NULL
566 	};
567 
568 	set_option_flag(list_options, 0, "raw-dump", PARSE_OPT_HIDDEN);
569 	/* Hide hybrid flag for the more generic 'unit' flag. */
570 	set_option_flag(list_options, 0, "cputype", PARSE_OPT_HIDDEN);
571 
572 	argc = parse_options(argc, argv, list_options, list_usage,
573 			     PARSE_OPT_STOP_AT_NON_OPTION);
574 
575 	if (output_path) {
576 		default_ps.fp = fopen(output_path, "w");
577 		json_ps.fp = default_ps.fp;
578 	}
579 
580 	setup_pager();
581 
582 	if (!default_ps.name_only)
583 		setup_pager();
584 
585 	if (json) {
586 		print_cb = (struct print_callbacks){
587 			.print_start = json_print_start,
588 			.print_end = json_print_end,
589 			.print_event = json_print_event,
590 			.print_metric = json_print_metric,
591 			.skip_duplicate_pmus = json_skip_duplicate_pmus,
592 		};
593 		ps = &json_ps;
594 	} else {
595 		default_ps.last_topic = strdup("");
596 		assert(default_ps.last_topic);
597 		default_ps.visited_metrics = strlist__new(NULL, NULL);
598 		assert(default_ps.visited_metrics);
599 		if (unit_name)
600 			default_ps.pmu_glob = strdup(unit_name);
601 		else if (cputype) {
602 			const struct perf_pmu *pmu = perf_pmus__pmu_for_pmu_filter(cputype);
603 
604 			if (!pmu) {
605 				pr_err("ERROR: cputype is not supported!\n");
606 				ret = -1;
607 				goto out;
608 			}
609 			default_ps.pmu_glob = strdup(pmu->name);
610 		}
611 	}
612 	print_cb.print_start(ps);
613 
614 	if (argc == 0) {
615 		default_ps.metrics = true;
616 		default_ps.metricgroups = true;
617 		print_events(&print_cb, ps);
618 		goto out;
619 	}
620 
621 	for (i = 0; i < argc; ++i) {
622 		char *sep, *s;
623 
624 		if (strcmp(argv[i], "tracepoint") == 0) {
625 			char *old_pmu_glob = default_ps.pmu_glob;
626 
627 			default_ps.pmu_glob = strdup("tracepoint");
628 			if (!default_ps.pmu_glob) {
629 				ret = -1;
630 				goto out;
631 			}
632 			perf_pmus__print_pmu_events(&print_cb, ps);
633 			zfree(&default_ps.pmu_glob);
634 			default_ps.pmu_glob = old_pmu_glob;
635 		} else if (strcmp(argv[i], "hw") == 0 ||
636 			 strcmp(argv[i], "hardware") == 0)
637 			print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE,
638 					event_symbols_hw, PERF_COUNT_HW_MAX);
639 		else if (strcmp(argv[i], "sw") == 0 ||
640 			 strcmp(argv[i], "software") == 0) {
641 			char *old_pmu_glob = default_ps.pmu_glob;
642 			static const char * const sw_globs[] = { "software", "tool" };
643 
644 			for (size_t j = 0; j < ARRAY_SIZE(sw_globs); j++) {
645 				default_ps.pmu_glob = strdup(sw_globs[j]);
646 				if (!default_ps.pmu_glob) {
647 					ret = -1;
648 					goto out;
649 				}
650 				perf_pmus__print_pmu_events(&print_cb, ps);
651 				zfree(&default_ps.pmu_glob);
652 			}
653 			default_ps.pmu_glob = old_pmu_glob;
654 		} else if (strcmp(argv[i], "cache") == 0 ||
655 			 strcmp(argv[i], "hwcache") == 0)
656 			print_hwcache_events(&print_cb, ps);
657 		else if (strcmp(argv[i], "pmu") == 0) {
658 			default_ps.exclude_abi = true;
659 			perf_pmus__print_pmu_events(&print_cb, ps);
660 			default_ps.exclude_abi = false;
661 		} else if (strcmp(argv[i], "sdt") == 0)
662 			print_sdt_events(&print_cb, ps);
663 		else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) {
664 			default_ps.metricgroups = false;
665 			default_ps.metrics = true;
666 			metricgroup__print(&print_cb, ps);
667 		} else if (strcmp(argv[i], "metricgroup") == 0 ||
668 			   strcmp(argv[i], "metricgroups") == 0) {
669 			default_ps.metricgroups = true;
670 			default_ps.metrics = false;
671 			metricgroup__print(&print_cb, ps);
672 		}
673 #ifdef HAVE_LIBPFM
674 		else if (strcmp(argv[i], "pfm") == 0)
675 			print_libpfm_events(&print_cb, ps);
676 #endif
677 		else if ((sep = strchr(argv[i], ':')) != NULL) {
678 			char *old_pmu_glob = default_ps.pmu_glob;
679 			char *old_event_glob = default_ps.event_glob;
680 
681 			default_ps.event_glob = strdup(argv[i]);
682 			if (!default_ps.event_glob) {
683 				ret = -1;
684 				goto out;
685 			}
686 
687 			default_ps.pmu_glob = strdup("tracepoint");
688 			if (!default_ps.pmu_glob) {
689 				zfree(&default_ps.event_glob);
690 				ret = -1;
691 				goto out;
692 			}
693 			perf_pmus__print_pmu_events(&print_cb, ps);
694 			zfree(&default_ps.pmu_glob);
695 			default_ps.pmu_glob = old_pmu_glob;
696 			print_sdt_events(&print_cb, ps);
697 			default_ps.metrics = true;
698 			default_ps.metricgroups = true;
699 			metricgroup__print(&print_cb, ps);
700 			zfree(&default_ps.event_glob);
701 			default_ps.event_glob = old_event_glob;
702 		} else {
703 			if (asprintf(&s, "*%s*", argv[i]) < 0) {
704 				printf("Critical: Not enough memory! Trying to continue...\n");
705 				continue;
706 			}
707 			default_ps.event_glob = s;
708 			print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE,
709 					event_symbols_hw, PERF_COUNT_HW_MAX);
710 			print_hwcache_events(&print_cb, ps);
711 			perf_pmus__print_pmu_events(&print_cb, ps);
712 			print_sdt_events(&print_cb, ps);
713 			default_ps.metrics = true;
714 			default_ps.metricgroups = true;
715 			metricgroup__print(&print_cb, ps);
716 			free(s);
717 		}
718 	}
719 
720 out:
721 	print_cb.print_end(ps);
722 	free(default_ps.pmu_glob);
723 	free(default_ps.last_topic);
724 	free(default_ps.last_metricgroups);
725 	strlist__delete(default_ps.visited_metrics);
726 	if (output_path)
727 		fclose(default_ps.fp);
728 
729 	return ret;
730 }
731