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 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 81 static void default_print_end(void *print_state __maybe_unused) {} 82 83 static const char *skip_spaces_or_commas(const char *str) 84 { 85 while (isspace(*str) || *str == ',') 86 ++str; 87 return str; 88 } 89 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 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 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 /** The shared print_state */ 287 struct print_state common; 288 /** Should a separator be printed prior to the next item? */ 289 bool need_sep; 290 }; 291 292 static void json_print_start(void *ps) 293 { 294 struct json_print_state *print_state = ps; 295 FILE *fp = print_state->common.fp; 296 297 fprintf(fp, "[\n"); 298 } 299 300 static void json_print_end(void *ps) 301 { 302 struct json_print_state *print_state = ps; 303 FILE *fp = print_state->common.fp; 304 305 fprintf(fp, "%s]\n", print_state->need_sep ? "\n" : ""); 306 } 307 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 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->common.fp; 374 struct strbuf buf; 375 376 if (deprecated && !print_state->common.deprecated) 377 return; 378 379 if (print_state->common.pmu_glob && 380 (!pmu_name || !strglobmatch(pmu_name, print_state->common.pmu_glob))) 381 return; 382 383 if (print_state->common.exclude_abi && pmu_type < PERF_TYPE_MAX && 384 pmu_type != PERF_TYPE_RAW) 385 return; 386 387 if (print_state->common.event_glob && 388 (!event_name || !strglobmatch(event_name, print_state->common.event_glob)) && 389 (!event_alias || !strglobmatch(event_alias, print_state->common.event_glob)) && 390 (!topic || !strglobmatch_nocase(topic, print_state->common.event_glob))) 391 return; 392 393 strbuf_init(&buf, 0); 394 fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : ""); 395 print_state->need_sep = true; 396 if (pmu_name) { 397 fix_escape_fprintf(fp, &buf, "\t\"Unit\": \"%S\"", pmu_name); 398 need_sep = true; 399 } 400 if (topic) { 401 fix_escape_fprintf(fp, &buf, "%s\t\"Topic\": \"%S\"", 402 need_sep ? ",\n" : "", 403 topic); 404 need_sep = true; 405 } 406 if (event_name) { 407 fix_escape_fprintf(fp, &buf, "%s\t\"EventName\": \"%S\"", 408 need_sep ? ",\n" : "", 409 event_name); 410 need_sep = true; 411 } 412 if (event_alias && strlen(event_alias)) { 413 fix_escape_fprintf(fp, &buf, "%s\t\"EventAlias\": \"%S\"", 414 need_sep ? ",\n" : "", 415 event_alias); 416 need_sep = true; 417 } 418 if (scale_unit && strlen(scale_unit)) { 419 fix_escape_fprintf(fp, &buf, "%s\t\"ScaleUnit\": \"%S\"", 420 need_sep ? ",\n" : "", 421 scale_unit); 422 need_sep = true; 423 } 424 if (event_type_desc) { 425 fix_escape_fprintf(fp, &buf, "%s\t\"EventType\": \"%S\"", 426 need_sep ? ",\n" : "", 427 event_type_desc); 428 need_sep = true; 429 } 430 if (deprecated) { 431 fix_escape_fprintf(fp, &buf, "%s\t\"Deprecated\": \"%S\"", 432 need_sep ? ",\n" : "", 433 deprecated ? "1" : "0"); 434 need_sep = true; 435 } 436 if (desc) { 437 fix_escape_fprintf(fp, &buf, "%s\t\"BriefDescription\": \"%S\"", 438 need_sep ? ",\n" : "", 439 desc); 440 need_sep = true; 441 } 442 if (long_desc) { 443 fix_escape_fprintf(fp, &buf, "%s\t\"PublicDescription\": \"%S\"", 444 need_sep ? ",\n" : "", 445 long_desc); 446 need_sep = true; 447 } 448 if (encoding_desc) { 449 fix_escape_fprintf(fp, &buf, "%s\t\"Encoding\": \"%S\"", 450 need_sep ? ",\n" : "", 451 encoding_desc); 452 need_sep = true; 453 } 454 fprintf(fp, "%s}", need_sep ? "\n" : ""); 455 strbuf_release(&buf); 456 } 457 458 static void json_print_metric(void *ps __maybe_unused, const char *group, 459 const char *name, const char *desc, 460 const char *long_desc, const char *expr, 461 const char *threshold, const char *unit, 462 const char *pmu_name) 463 { 464 struct json_print_state *print_state = ps; 465 bool need_sep = false; 466 FILE *fp = print_state->common.fp; 467 struct strbuf buf; 468 469 if (print_state->common.event_glob && 470 (!print_state->common.metrics || !name || 471 !strglobmatch(name, print_state->common.event_glob)) && 472 (!print_state->common.metricgroups || !group || 473 !strglobmatch(group, print_state->common.event_glob))) 474 return; 475 476 strbuf_init(&buf, 0); 477 fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : ""); 478 print_state->need_sep = true; 479 if (group) { 480 fix_escape_fprintf(fp, &buf, "\t\"MetricGroup\": \"%S\"", group); 481 need_sep = true; 482 } 483 if (name) { 484 fix_escape_fprintf(fp, &buf, "%s\t\"MetricName\": \"%S\"", 485 need_sep ? ",\n" : "", 486 name); 487 need_sep = true; 488 } 489 if (expr) { 490 fix_escape_fprintf(fp, &buf, "%s\t\"MetricExpr\": \"%S\"", 491 need_sep ? ",\n" : "", 492 expr); 493 need_sep = true; 494 } 495 if (threshold) { 496 fix_escape_fprintf(fp, &buf, "%s\t\"MetricThreshold\": \"%S\"", 497 need_sep ? ",\n" : "", 498 threshold); 499 need_sep = true; 500 } 501 if (unit) { 502 fix_escape_fprintf(fp, &buf, "%s\t\"ScaleUnit\": \"%S\"", 503 need_sep ? ",\n" : "", 504 unit); 505 need_sep = true; 506 } 507 if (desc) { 508 fix_escape_fprintf(fp, &buf, "%s\t\"BriefDescription\": \"%S\"", 509 need_sep ? ",\n" : "", 510 desc); 511 need_sep = true; 512 } 513 if (long_desc) { 514 fix_escape_fprintf(fp, &buf, "%s\t\"PublicDescription\": \"%S\"", 515 need_sep ? ",\n" : "", 516 long_desc); 517 need_sep = true; 518 } 519 if (pmu_name) { 520 fix_escape_fprintf(fp, &buf, "%s\t\"Unit\": \"%S\"", 521 need_sep ? ",\n" : "", 522 pmu_name); 523 need_sep = true; 524 } 525 fprintf(fp, "%s}", need_sep ? "\n" : ""); 526 strbuf_release(&buf); 527 } 528 529 static bool json_skip_duplicate_pmus(void *ps __maybe_unused) 530 { 531 return false; 532 } 533 534 static bool default_skip_duplicate_pmus(void *ps) 535 { 536 struct print_state *print_state = ps; 537 538 return !print_state->long_desc; 539 } 540 541 int cmd_list(int argc, const char **argv) 542 { 543 int i, ret = 0; 544 struct print_state default_ps = { 545 .fp = stdout, 546 .desc = true, 547 }; 548 struct json_print_state json_ps = { 549 .common = { 550 .fp = stdout, 551 }, 552 }; 553 struct print_state *ps = &default_ps; 554 struct print_callbacks print_cb = { 555 .print_start = default_print_start, 556 .print_end = default_print_end, 557 .print_event = default_print_event, 558 .print_metric = default_print_metric, 559 .skip_duplicate_pmus = default_skip_duplicate_pmus, 560 }; 561 const char *cputype = NULL; 562 const char *unit_name = NULL; 563 const char *output_path = NULL; 564 bool json = false; 565 struct option list_options[] = { 566 OPT_BOOLEAN(0, "raw-dump", &default_ps.name_only, "Dump raw events"), 567 OPT_BOOLEAN('j', "json", &json, "JSON encode events and metrics"), 568 OPT_BOOLEAN('d', "desc", &default_ps.desc, 569 "Print extra event descriptions. --no-desc to not print."), 570 OPT_BOOLEAN('v', "long-desc", &default_ps.long_desc, 571 "Print longer event descriptions and all similar PMUs with alphanumeric suffixes."), 572 OPT_BOOLEAN(0, "details", &default_ps.detailed, 573 "Print information on the perf event names and expressions used internally by events."), 574 OPT_STRING('o', "output", &output_path, "file", "output file name"), 575 OPT_BOOLEAN(0, "deprecated", &default_ps.deprecated, 576 "Print deprecated events."), 577 OPT_STRING(0, "cputype", &cputype, "cpu type", 578 "Limit PMU or metric printing to the given PMU (e.g. cpu, core or atom)."), 579 OPT_STRING(0, "unit", &unit_name, "PMU name", 580 "Limit PMU or metric printing to the specified PMU."), 581 OPT_INCR(0, "debug", &verbose, 582 "Enable debugging output"), 583 OPT_END() 584 }; 585 const char * const list_usage[] = { 586 #ifdef HAVE_LIBPFM 587 "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob|pfm]", 588 #else 589 "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]", 590 #endif 591 NULL 592 }; 593 594 set_option_flag(list_options, 0, "raw-dump", PARSE_OPT_HIDDEN); 595 /* Hide hybrid flag for the more generic 'unit' flag. */ 596 set_option_flag(list_options, 0, "cputype", PARSE_OPT_HIDDEN); 597 598 argc = parse_options(argc, argv, list_options, list_usage, 599 PARSE_OPT_STOP_AT_NON_OPTION); 600 601 if (json) 602 ps = &json_ps.common; 603 604 if (output_path) { 605 ps->fp = fopen(output_path, "w"); 606 } 607 608 setup_pager(); 609 610 if (!default_ps.name_only) 611 setup_pager(); 612 613 if (json) { 614 print_cb = (struct print_callbacks){ 615 .print_start = json_print_start, 616 .print_end = json_print_end, 617 .print_event = json_print_event, 618 .print_metric = json_print_metric, 619 .skip_duplicate_pmus = json_skip_duplicate_pmus, 620 }; 621 } else { 622 ps->last_topic = strdup(""); 623 assert(ps->last_topic); 624 ps->visited_metrics = strlist__new(NULL, NULL); 625 assert(ps->visited_metrics); 626 if (unit_name) 627 ps->pmu_glob = strdup(unit_name); 628 else if (cputype) { 629 const struct perf_pmu *pmu = perf_pmus__pmu_for_pmu_filter(cputype); 630 631 if (!pmu) { 632 pr_err("ERROR: cputype is not supported!\n"); 633 ret = -1; 634 goto out; 635 } 636 ps->pmu_glob = strdup(pmu->name); 637 } 638 } 639 print_cb.print_start(ps); 640 641 if (argc == 0) { 642 if (!unit_name) { 643 ps->metrics = true; 644 ps->metricgroups = true; 645 } 646 print_events(&print_cb, ps); 647 goto out; 648 } 649 650 for (i = 0; i < argc; ++i) { 651 char *sep, *s; 652 653 if (strcmp(argv[i], "tracepoint") == 0) { 654 char *old_pmu_glob = default_ps.pmu_glob; 655 656 default_ps.pmu_glob = strdup("tracepoint"); 657 if (!default_ps.pmu_glob) { 658 ret = -1; 659 goto out; 660 } 661 perf_pmus__print_pmu_events(&print_cb, ps); 662 zfree(&default_ps.pmu_glob); 663 default_ps.pmu_glob = old_pmu_glob; 664 } else if (strcmp(argv[i], "hw") == 0 || 665 strcmp(argv[i], "hardware") == 0) { 666 char *old_event_glob = ps->event_glob; 667 668 ps->event_glob = strdup("legacy hardware"); 669 if (!ps->event_glob) { 670 ret = -1; 671 goto out; 672 } 673 perf_pmus__print_pmu_events(&print_cb, ps); 674 zfree(&ps->event_glob); 675 ps->event_glob = old_event_glob; 676 } else if (strcmp(argv[i], "sw") == 0 || 677 strcmp(argv[i], "software") == 0) { 678 char *old_pmu_glob = ps->pmu_glob; 679 static const char * const sw_globs[] = { "software", "tool" }; 680 681 for (size_t j = 0; j < ARRAY_SIZE(sw_globs); j++) { 682 ps->pmu_glob = strdup(sw_globs[j]); 683 if (!ps->pmu_glob) { 684 ret = -1; 685 goto out; 686 } 687 perf_pmus__print_pmu_events(&print_cb, ps); 688 zfree(&ps->pmu_glob); 689 } 690 ps->pmu_glob = old_pmu_glob; 691 } else if (strcmp(argv[i], "cache") == 0 || 692 strcmp(argv[i], "hwcache") == 0) { 693 char *old_event_glob = ps->event_glob; 694 695 ps->event_glob = strdup("legacy cache"); 696 if (!ps->event_glob) { 697 ret = -1; 698 goto out; 699 } 700 perf_pmus__print_pmu_events(&print_cb, ps); 701 zfree(&ps->event_glob); 702 ps->event_glob = old_event_glob; 703 } else if (strcmp(argv[i], "pmu") == 0) { 704 ps->exclude_abi = true; 705 perf_pmus__print_pmu_events(&print_cb, ps); 706 ps->exclude_abi = false; 707 } else if (strcmp(argv[i], "sdt") == 0) 708 print_sdt_events(&print_cb, ps); 709 else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) { 710 ps->metricgroups = false; 711 ps->metrics = true; 712 metricgroup__print(&print_cb, ps); 713 } else if (strcmp(argv[i], "metricgroup") == 0 || 714 strcmp(argv[i], "metricgroups") == 0) { 715 ps->metricgroups = true; 716 ps->metrics = false; 717 metricgroup__print(&print_cb, ps); 718 } 719 #ifdef HAVE_LIBPFM 720 else if (strcmp(argv[i], "pfm") == 0) 721 print_libpfm_events(&print_cb, ps); 722 #endif 723 else if ((sep = strchr(argv[i], ':')) != NULL) { 724 char *old_pmu_glob = ps->pmu_glob; 725 char *old_event_glob = ps->event_glob; 726 727 ps->event_glob = strdup(argv[i]); 728 if (!ps->event_glob) { 729 ret = -1; 730 goto out; 731 } 732 733 ps->pmu_glob = strdup("tracepoint"); 734 if (!ps->pmu_glob) { 735 zfree(&ps->event_glob); 736 ret = -1; 737 goto out; 738 } 739 perf_pmus__print_pmu_events(&print_cb, ps); 740 zfree(&ps->pmu_glob); 741 ps->pmu_glob = old_pmu_glob; 742 print_sdt_events(&print_cb, ps); 743 ps->metrics = true; 744 ps->metricgroups = true; 745 metricgroup__print(&print_cb, ps); 746 zfree(&ps->event_glob); 747 ps->event_glob = old_event_glob; 748 } else { 749 if (asprintf(&s, "*%s*", argv[i]) < 0) { 750 printf("Critical: Not enough memory! Trying to continue...\n"); 751 continue; 752 } 753 ps->event_glob = s; 754 perf_pmus__print_pmu_events(&print_cb, ps); 755 print_sdt_events(&print_cb, ps); 756 ps->metrics = true; 757 ps->metricgroups = true; 758 metricgroup__print(&print_cb, ps); 759 free(s); 760 } 761 } 762 763 out: 764 print_cb.print_end(ps); 765 free(ps->pmu_glob); 766 free(ps->last_topic); 767 free(ps->last_metricgroups); 768 strlist__delete(ps->visited_metrics); 769 if (output_path) 770 fclose(ps->fp); 771 772 return ret; 773 } 774