diff options
Diffstat (limited to 'tools/perf/builtin-list.c')
| -rw-r--r-- | tools/perf/builtin-list.c | 243 |
1 files changed, 162 insertions, 81 deletions
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 5cab31231551..5cbca0bacd35 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -19,6 +19,7 @@ #include "util/string2.h" #include "util/strlist.h" #include "util/strbuf.h" +#include "util/tool_pmu.h" #include <subcmd/pager.h> #include <subcmd/parse-options.h> #include <linux/zalloc.h> @@ -57,6 +58,8 @@ struct print_state { bool metrics; /** @metricgroups: Controls printing of metric and metric groups. */ bool metricgroups; + /** @exclude_abi: Exclude PMUs with types less than PERF_TYPE_MAX except PERF_TYPE_RAW. */ + bool exclude_abi; /** @last_topic: The last printed event topic. */ char *last_topic; /** @last_metricgroups: The last printed metric group. */ @@ -112,7 +115,8 @@ static void wordwrap(FILE *fp, const char *s, int start, int max, int corr) } } -static void default_print_event(void *ps, const char *pmu_name, const char *topic, +static void 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, @@ -126,7 +130,10 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi if (deprecated && !print_state->deprecated) return; - if (print_state->pmu_glob && pmu_name && !strglobmatch(pmu_name, print_state->pmu_glob)) + if (print_state->pmu_glob && (!pmu_name || !strglobmatch(pmu_name, print_state->pmu_glob))) + return; + + if (print_state->exclude_abi && pmu_type < PERF_TYPE_MAX && pmu_type != PERF_TYPE_RAW) return; if (print_state->event_glob && @@ -162,14 +169,17 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi } else fputc('\n', fp); - if (desc && print_state->desc) { + if (long_desc && print_state->long_desc) + desc = long_desc; + + if (desc && (print_state->desc || print_state->long_desc)) { char *desc_with_unit = NULL; int desc_len = -1; if (pmu_name && strcmp(pmu_name, "default_core")) { desc_len = strlen(desc); desc_len = asprintf(&desc_with_unit, - desc[desc_len - 1] != '.' + desc_len > 0 && desc[desc_len - 1] != '.' ? "%s. Unit: %s" : "%s Unit: %s", desc, pmu_name); } @@ -178,12 +188,6 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi fprintf(fp, "]\n"); free(desc_with_unit); } - long_desc = long_desc ?: desc; - if (long_desc && print_state->long_desc) { - fprintf(fp, "%*s", 8, "["); - wordwrap(fp, long_desc, 8, pager_get_columns(), 0); - fprintf(fp, "]\n"); - } if (print_state->detailed && encoding_desc) { fprintf(fp, "%*s", 8, ""); @@ -199,7 +203,8 @@ static void default_print_metric(void *ps, const char *long_desc, const char *expr, const char *threshold, - const char *unit __maybe_unused) + const char *unit __maybe_unused, + const char *pmu_name __maybe_unused) { struct print_state *print_state = ps; FILE *fp = print_state->fp; @@ -256,15 +261,14 @@ static void default_print_metric(void *ps, } fprintf(fp, " %s\n", name); - if (desc && print_state->desc) { - fprintf(fp, "%*s", 8, "["); - wordwrap(fp, desc, 8, pager_get_columns(), 0); - fprintf(fp, "]\n"); - } if (long_desc && print_state->long_desc) { fprintf(fp, "%*s", 8, "["); wordwrap(fp, long_desc, 8, pager_get_columns(), 0); fprintf(fp, "]\n"); + } else if (desc && print_state->desc) { + fprintf(fp, "%*s", 8, "["); + wordwrap(fp, desc, 8, pager_get_columns(), 0); + fprintf(fp, "]\n"); } if (expr && print_state->detailed) { fprintf(fp, "%*s", 8, "["); @@ -279,8 +283,8 @@ static void default_print_metric(void *ps, } struct json_print_state { - /** @fp: File to write output to. */ - FILE *fp; + /** The shared print_state */ + struct print_state common; /** Should a separator be printed prior to the next item? */ bool need_sep; }; @@ -288,7 +292,7 @@ struct json_print_state { static void json_print_start(void *ps) { struct json_print_state *print_state = ps; - FILE *fp = print_state->fp; + FILE *fp = print_state->common.fp; fprintf(fp, "[\n"); } @@ -296,7 +300,7 @@ static void json_print_start(void *ps) static void json_print_end(void *ps) { struct json_print_state *print_state = ps; - FILE *fp = print_state->fp; + FILE *fp = print_state->common.fp; fprintf(fp, "%s]\n", print_state->need_sep ? "\n" : ""); } @@ -356,7 +360,8 @@ static void fix_escape_fprintf(FILE *fp, struct strbuf *buf, const char *fmt, .. fputs(buf->buf, fp); } -static void json_print_event(void *ps, const char *pmu_name, const char *topic, +static void 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, @@ -365,9 +370,26 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic, { struct json_print_state *print_state = ps; bool need_sep = false; - FILE *fp = print_state->fp; + FILE *fp = print_state->common.fp; struct strbuf buf; + if (deprecated && !print_state->common.deprecated) + return; + + if (print_state->common.pmu_glob && + (!pmu_name || !strglobmatch(pmu_name, print_state->common.pmu_glob))) + return; + + if (print_state->common.exclude_abi && pmu_type < PERF_TYPE_MAX && + pmu_type != PERF_TYPE_RAW) + return; + + if (print_state->common.event_glob && + (!event_name || !strglobmatch(event_name, print_state->common.event_glob)) && + (!event_alias || !strglobmatch(event_alias, print_state->common.event_glob)) && + (!topic || !strglobmatch_nocase(topic, print_state->common.event_glob))) + return; + strbuf_init(&buf, 0); fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : ""); print_state->need_sep = true; @@ -436,13 +458,21 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic, static void 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 *threshold, const char *unit, + const char *pmu_name) { struct json_print_state *print_state = ps; bool need_sep = false; - FILE *fp = print_state->fp; + FILE *fp = print_state->common.fp; struct strbuf buf; + if (print_state->common.event_glob && + (!print_state->common.metrics || !name || + !strglobmatch(name, print_state->common.event_glob)) && + (!print_state->common.metricgroups || !group || + !strglobmatch(group, print_state->common.event_glob))) + return; + strbuf_init(&buf, 0); fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : ""); print_state->need_sep = true; @@ -486,6 +516,12 @@ static void json_print_metric(void *ps __maybe_unused, const char *group, long_desc); need_sep = true; } + if (pmu_name) { + fix_escape_fprintf(fp, &buf, "%s\t\"Unit\": \"%S\"", + need_sep ? ",\n" : "", + pmu_name); + need_sep = true; + } fprintf(fp, "%s}", need_sep ? "\n" : ""); strbuf_release(&buf); } @@ -507,11 +543,14 @@ int cmd_list(int argc, const char **argv) int i, ret = 0; struct print_state default_ps = { .fp = stdout, + .desc = true, }; - struct print_state json_ps = { - .fp = stdout, + struct json_print_state json_ps = { + .common = { + .fp = stdout, + }, }; - void *ps = &default_ps; + struct print_state *ps = &default_ps; struct print_callbacks print_cb = { .print_start = default_print_start, .print_end = default_print_end, @@ -529,7 +568,7 @@ int cmd_list(int argc, const char **argv) OPT_BOOLEAN('d', "desc", &default_ps.desc, "Print extra event descriptions. --no-desc to not print."), OPT_BOOLEAN('v', "long-desc", &default_ps.long_desc, - "Print longer event descriptions."), + "Print longer event descriptions and all similar PMUs with alphanumeric suffixes."), OPT_BOOLEAN(0, "details", &default_ps.detailed, "Print information on the perf event names and expressions used internally by events."), OPT_STRING('o', "output", &output_path, "file", "output file name"), @@ -559,9 +598,11 @@ int cmd_list(int argc, const char **argv) argc = parse_options(argc, argv, list_options, list_usage, PARSE_OPT_STOP_AT_NON_OPTION); + if (json) + ps = &json_ps.common; + if (output_path) { - default_ps.fp = fopen(output_path, "w"); - json_ps.fp = default_ps.fp; + ps->fp = fopen(output_path, "w"); } setup_pager(); @@ -577,15 +618,13 @@ int cmd_list(int argc, const char **argv) .print_metric = json_print_metric, .skip_duplicate_pmus = json_skip_duplicate_pmus, }; - ps = &json_ps; } else { - default_ps.desc = !default_ps.long_desc; - default_ps.last_topic = strdup(""); - assert(default_ps.last_topic); - default_ps.visited_metrics = strlist__new(NULL, NULL); - assert(default_ps.visited_metrics); + ps->last_topic = strdup(""); + assert(ps->last_topic); + ps->visited_metrics = strlist__new(NULL, NULL); + assert(ps->visited_metrics); if (unit_name) - default_ps.pmu_glob = strdup(unit_name); + ps->pmu_glob = strdup(unit_name); else if (cputype) { const struct perf_pmu *pmu = perf_pmus__pmu_for_pmu_filter(cputype); @@ -594,14 +633,16 @@ int cmd_list(int argc, const char **argv) ret = -1; goto out; } - default_ps.pmu_glob = strdup(pmu->name); + ps->pmu_glob = strdup(pmu->name); } } print_cb.print_start(ps); if (argc == 0) { - default_ps.metrics = true; - default_ps.metricgroups = true; + if (!unit_name) { + ps->metrics = true; + ps->metricgroups = true; + } print_events(&print_cb, ps); goto out; } @@ -609,32 +650,70 @@ int cmd_list(int argc, const char **argv) for (i = 0; i < argc; ++i) { char *sep, *s; - if (strcmp(argv[i], "tracepoint") == 0) - print_tracepoint_events(&print_cb, ps); - else if (strcmp(argv[i], "hw") == 0 || - strcmp(argv[i], "hardware") == 0) - print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE, - event_symbols_hw, PERF_COUNT_HW_MAX); - else if (strcmp(argv[i], "sw") == 0 || + if (strcmp(argv[i], "tracepoint") == 0) { + char *old_pmu_glob = default_ps.pmu_glob; + + default_ps.pmu_glob = strdup("tracepoint"); + if (!default_ps.pmu_glob) { + ret = -1; + goto out; + } + perf_pmus__print_pmu_events(&print_cb, ps); + zfree(&default_ps.pmu_glob); + default_ps.pmu_glob = old_pmu_glob; + } else if (strcmp(argv[i], "hw") == 0 || + strcmp(argv[i], "hardware") == 0) { + char *old_event_glob = ps->event_glob; + + ps->event_glob = strdup("legacy hardware"); + if (!ps->event_glob) { + ret = -1; + goto out; + } + perf_pmus__print_pmu_events(&print_cb, ps); + zfree(&ps->event_glob); + ps->event_glob = old_event_glob; + } else if (strcmp(argv[i], "sw") == 0 || strcmp(argv[i], "software") == 0) { - print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, - event_symbols_sw, PERF_COUNT_SW_MAX); - print_tool_events(&print_cb, ps); + char *old_pmu_glob = ps->pmu_glob; + static const char * const sw_globs[] = { "software", "tool" }; + + for (size_t j = 0; j < ARRAY_SIZE(sw_globs); j++) { + ps->pmu_glob = strdup(sw_globs[j]); + if (!ps->pmu_glob) { + ret = -1; + goto out; + } + perf_pmus__print_pmu_events(&print_cb, ps); + zfree(&ps->pmu_glob); + } + ps->pmu_glob = old_pmu_glob; } else if (strcmp(argv[i], "cache") == 0 || - strcmp(argv[i], "hwcache") == 0) - print_hwcache_events(&print_cb, ps); - else if (strcmp(argv[i], "pmu") == 0) + strcmp(argv[i], "hwcache") == 0) { + char *old_event_glob = ps->event_glob; + + ps->event_glob = strdup("legacy cache"); + if (!ps->event_glob) { + ret = -1; + goto out; + } perf_pmus__print_pmu_events(&print_cb, ps); - else if (strcmp(argv[i], "sdt") == 0) + zfree(&ps->event_glob); + ps->event_glob = old_event_glob; + } else if (strcmp(argv[i], "pmu") == 0) { + ps->exclude_abi = true; + perf_pmus__print_pmu_events(&print_cb, ps); + ps->exclude_abi = false; + } else if (strcmp(argv[i], "sdt") == 0) print_sdt_events(&print_cb, ps); else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) { - default_ps.metricgroups = false; - default_ps.metrics = true; + ps->metricgroups = false; + ps->metrics = true; metricgroup__print(&print_cb, ps); } else if (strcmp(argv[i], "metricgroup") == 0 || strcmp(argv[i], "metricgroups") == 0) { - default_ps.metricgroups = true; - default_ps.metrics = false; + ps->metricgroups = true; + ps->metrics = false; metricgroup__print(&print_cb, ps); } #ifdef HAVE_LIBPFM @@ -642,38 +721,40 @@ int cmd_list(int argc, const char **argv) print_libpfm_events(&print_cb, ps); #endif else if ((sep = strchr(argv[i], ':')) != NULL) { - char *old_pmu_glob = default_ps.pmu_glob; + char *old_pmu_glob = ps->pmu_glob; + char *old_event_glob = ps->event_glob; - default_ps.event_glob = strdup(argv[i]); - if (!default_ps.event_glob) { + ps->event_glob = strdup(argv[i]); + if (!ps->event_glob) { ret = -1; goto out; } - print_tracepoint_events(&print_cb, ps); + ps->pmu_glob = strdup("tracepoint"); + if (!ps->pmu_glob) { + zfree(&ps->event_glob); + ret = -1; + goto out; + } + perf_pmus__print_pmu_events(&print_cb, ps); + zfree(&ps->pmu_glob); + ps->pmu_glob = old_pmu_glob; print_sdt_events(&print_cb, ps); - default_ps.metrics = true; - default_ps.metricgroups = true; + ps->metrics = true; + ps->metricgroups = true; metricgroup__print(&print_cb, ps); - zfree(&default_ps.event_glob); - default_ps.pmu_glob = old_pmu_glob; + zfree(&ps->event_glob); + ps->event_glob = old_event_glob; } else { if (asprintf(&s, "*%s*", argv[i]) < 0) { printf("Critical: Not enough memory! Trying to continue...\n"); continue; } - default_ps.event_glob = s; - print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE, - event_symbols_hw, PERF_COUNT_HW_MAX); - print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, - event_symbols_sw, PERF_COUNT_SW_MAX); - print_tool_events(&print_cb, ps); - print_hwcache_events(&print_cb, ps); + ps->event_glob = s; perf_pmus__print_pmu_events(&print_cb, ps); - print_tracepoint_events(&print_cb, ps); print_sdt_events(&print_cb, ps); - default_ps.metrics = true; - default_ps.metricgroups = true; + ps->metrics = true; + ps->metricgroups = true; metricgroup__print(&print_cb, ps); free(s); } @@ -681,12 +762,12 @@ int cmd_list(int argc, const char **argv) out: print_cb.print_end(ps); - free(default_ps.pmu_glob); - free(default_ps.last_topic); - free(default_ps.last_metricgroups); - strlist__delete(default_ps.visited_metrics); + free(ps->pmu_glob); + free(ps->last_topic); + free(ps->last_metricgroups); + strlist__delete(ps->visited_metrics); if (output_path) - fclose(default_ps.fp); + fclose(ps->fp); return ret; } |
