From 94b1a603fca78388ef7575411aed4b1fabd843f9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:36 -0800 Subject: perf stat: Add TopdownL1 metric as a default if present When there are no events and on Intel, the topdown events will be added by default if present. To display the metrics associated with these request special handling in stat-shadow.c. To more easily update these metrics use the json metric version via the TopdownL1 group. This makes the handling less platform specific. Modify the metricgroup__has_metric code to also cover metric groups. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-40-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/topdown.c | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'tools/perf/arch/x86/util/topdown.c') diff --git a/tools/perf/arch/x86/util/topdown.c b/tools/perf/arch/x86/util/topdown.c index 54810f9acd6f..eb3a7d9652ab 100644 --- a/tools/perf/arch/x86/util/topdown.c +++ b/tools/perf/arch/x86/util/topdown.c @@ -9,11 +9,6 @@ #include "topdown.h" #include "evsel.h" -#define TOPDOWN_L1_EVENTS "{slots,topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound}" -#define TOPDOWN_L1_EVENTS_CORE "{slots,cpu_core/topdown-retiring/,cpu_core/topdown-bad-spec/,cpu_core/topdown-fe-bound/,cpu_core/topdown-be-bound/}" -#define TOPDOWN_L2_EVENTS "{slots,topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound,topdown-heavy-ops,topdown-br-mispredict,topdown-fetch-lat,topdown-mem-bound}" -#define TOPDOWN_L2_EVENTS_CORE "{slots,cpu_core/topdown-retiring/,cpu_core/topdown-bad-spec/,cpu_core/topdown-fe-bound/,cpu_core/topdown-be-bound/,cpu_core/topdown-heavy-ops/,cpu_core/topdown-br-mispredict/,cpu_core/topdown-fetch-lat/,cpu_core/topdown-mem-bound/}" - /* Check whether there is a PMU which supports the perf metrics. */ bool topdown_sys_has_perf_metrics(void) { @@ -99,28 +94,3 @@ const char *arch_get_topdown_pmu_name(struct evlist *evlist, bool warn) return pmu_name; } - -int topdown_parse_events(struct evlist *evlist) -{ - const char *topdown_events; - const char *pmu_name; - - if (!topdown_sys_has_perf_metrics()) - return 0; - - pmu_name = arch_get_topdown_pmu_name(evlist, false); - - if (pmu_have_event(pmu_name, "topdown-heavy-ops")) { - if (!strcmp(pmu_name, "cpu_core")) - topdown_events = TOPDOWN_L2_EVENTS_CORE; - else - topdown_events = TOPDOWN_L2_EVENTS; - } else { - if (!strcmp(pmu_name, "cpu_core")) - topdown_events = TOPDOWN_L1_EVENTS_CORE; - else - topdown_events = TOPDOWN_L1_EVENTS; - } - - return parse_event(evlist, topdown_events); -} -- cgit v1.2.3 From 1647cd5b8802698fb49ccb851b07b098520b5092 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:37 -0800 Subject: perf stat: Implement --topdown using json metrics Request the topdown metric group of a level with the metrics in the group 'TopdownL' rather than through specific events. As more topdown levels are supported this way, such as 6 on Intel Ice Lake, default to just showing the level 1 metrics. This can be overridden using '--td-level'. Rather than determine the maximum topdown level from sysfs, use the metric group names. Remove some now unused topdown code. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-41-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/topdown.c | 48 +-------------- tools/perf/builtin-stat.c | 118 +++++++------------------------------ tools/perf/util/metricgroup.c | 31 ++++++++++ tools/perf/util/metricgroup.h | 1 + tools/perf/util/topdown.c | 68 +-------------------- tools/perf/util/topdown.h | 11 ++-- 6 files changed, 58 insertions(+), 219 deletions(-) (limited to 'tools/perf/arch/x86/util/topdown.c') diff --git a/tools/perf/arch/x86/util/topdown.c b/tools/perf/arch/x86/util/topdown.c index eb3a7d9652ab..9ad5e5c7bd27 100644 --- a/tools/perf/arch/x86/util/topdown.c +++ b/tools/perf/arch/x86/util/topdown.c @@ -1,11 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include "api/fs/fs.h" +#include "util/evsel.h" #include "util/pmu.h" #include "util/topdown.h" -#include "util/evlist.h" -#include "util/debug.h" -#include "util/pmu-hybrid.h" #include "topdown.h" #include "evsel.h" @@ -33,30 +30,6 @@ bool topdown_sys_has_perf_metrics(void) return has_perf_metrics; } -/* - * Check whether we can use a group for top down. - * Without a group may get bad results due to multiplexing. - */ -bool arch_topdown_check_group(bool *warn) -{ - int n; - - if (sysctl__read_int("kernel/nmi_watchdog", &n) < 0) - return false; - if (n > 0) { - *warn = true; - return false; - } - return true; -} - -void arch_topdown_group_warn(void) -{ - fprintf(stderr, - "nmi_watchdog enabled with topdown. May give wrong results.\n" - "Disable with echo 0 > /proc/sys/kernel/nmi_watchdog\n"); -} - #define TOPDOWN_SLOTS 0x0400 /* @@ -65,7 +38,6 @@ void arch_topdown_group_warn(void) * Only Topdown metric supports sample-read. The slots * event must be the leader of the topdown group. */ - bool arch_topdown_sample_read(struct evsel *leader) { if (!evsel__sys_has_perf_metrics(leader)) @@ -76,21 +48,3 @@ bool arch_topdown_sample_read(struct evsel *leader) return false; } - -const char *arch_get_topdown_pmu_name(struct evlist *evlist, bool warn) -{ - const char *pmu_name; - - if (!perf_pmu__has_hybrid()) - return "cpu"; - - if (!evlist->hybrid_pmu_name) { - if (warn) - pr_warning("WARNING: default to use cpu_core topdown events\n"); - evlist->hybrid_pmu_name = perf_pmu__hybrid_type_to_pmu("core"); - } - - pmu_name = evlist->hybrid_pmu_name; - - return pmu_name; -} diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 796e98e453f6..bdb1ef4fc6ad 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -124,39 +124,6 @@ static const char * transaction_limited_attrs = { "}" }; -static const char * topdown_attrs[] = { - "topdown-total-slots", - "topdown-slots-retired", - "topdown-recovery-bubbles", - "topdown-fetch-bubbles", - "topdown-slots-issued", - NULL, -}; - -static const char *topdown_metric_attrs[] = { - "slots", - "topdown-retiring", - "topdown-bad-spec", - "topdown-fe-bound", - "topdown-be-bound", - NULL, -}; - -static const char *topdown_metric_L2_attrs[] = { - "slots", - "topdown-retiring", - "topdown-bad-spec", - "topdown-fe-bound", - "topdown-be-bound", - "topdown-heavy-ops", - "topdown-br-mispredict", - "topdown-fetch-lat", - "topdown-mem-bound", - NULL, -}; - -#define TOPDOWN_MAX_LEVEL 2 - static const char *smi_cost_attrs = { "{" "msr/aperf/," @@ -1914,86 +1881,41 @@ static int add_default_attributes(void) } if (topdown_run) { - const char **metric_attrs = topdown_metric_attrs; - unsigned int max_level = 1; - char *str = NULL; - bool warn = false; - const char *pmu_name = arch_get_topdown_pmu_name(evsel_list, true); + unsigned int max_level = metricgroups__topdown_max_level(); + char str[] = "TopdownL1"; if (!force_metric_only) stat_config.metric_only = true; - if (pmu_have_event(pmu_name, topdown_metric_L2_attrs[5])) { - metric_attrs = topdown_metric_L2_attrs; - max_level = 2; + if (!max_level) { + pr_err("Topdown requested but the topdown metric groups aren't present.\n" + "(See perf list the metric groups have names like TopdownL1)"); + return -1; } - if (stat_config.topdown_level > max_level) { pr_err("Invalid top-down metrics level. The max level is %u.\n", max_level); return -1; } else if (!stat_config.topdown_level) - stat_config.topdown_level = max_level; + stat_config.topdown_level = 1; - if (topdown_filter_events(metric_attrs, &str, 1, pmu_name) < 0) { - pr_err("Out of memory\n"); - return -1; - } - - if (metric_attrs[0] && str) { - if (!stat_config.interval && !stat_config.metric_only) { - fprintf(stat_config.output, - "Topdown accuracy may decrease when measuring long periods.\n" - "Please print the result regularly, e.g. -I1000\n"); - } - goto setup_metrics; - } - - zfree(&str); - - if (stat_config.aggr_mode != AGGR_GLOBAL && - stat_config.aggr_mode != AGGR_CORE) { - pr_err("top down event configuration requires --per-core mode\n"); - return -1; - } - stat_config.aggr_mode = AGGR_CORE; - if (nr_cgroups || !target__has_cpu(&target)) { - pr_err("top down event configuration requires system-wide mode (-a)\n"); - return -1; - } - - if (topdown_filter_events(topdown_attrs, &str, - arch_topdown_check_group(&warn), - pmu_name) < 0) { - pr_err("Out of memory\n"); - return -1; + if (!stat_config.interval && !stat_config.metric_only) { + fprintf(stat_config.output, + "Topdown accuracy may decrease when measuring long periods.\n" + "Please print the result regularly, e.g. -I1000\n"); } - - if (topdown_attrs[0] && str) { - struct parse_events_error errinfo; - if (warn) - arch_topdown_group_warn(); -setup_metrics: - parse_events_error__init(&errinfo); - err = parse_events(evsel_list, str, &errinfo); - if (err) { - fprintf(stderr, - "Cannot set up top down events %s: %d\n", - str, err); - parse_events_error__print(&errinfo, str); - parse_events_error__exit(&errinfo); - free(str); - return -1; - } - parse_events_error__exit(&errinfo); - } else { - fprintf(stderr, "System does not support topdown\n"); + str[8] = stat_config.topdown_level + '0'; + if (metricgroup__parse_groups(evsel_list, str, + /*metric_no_group=*/false, + /*metric_no_merge=*/false, + /*metric_no_threshold=*/true, + stat_config.user_requested_cpu_list, + stat_config.system_wide, + &stat_config.metric_events) < 0) return -1; - } - free(str); } if (!stat_config.topdown_level) - stat_config.topdown_level = TOPDOWN_MAX_LEVEL; + stat_config.topdown_level = 1; if (!evsel_list->core.nr_entries) { /* No events so add defaults. */ diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 64a35f2787dc..de6dd527a2ba 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -1665,6 +1665,37 @@ bool metricgroup__has_metric(const char *metric) (void *)metric) ? true : false; } +static int metricgroup__topdown_max_level_callback(const struct pmu_metric *pm, + const struct pmu_metrics_table *table __maybe_unused, + void *data) +{ + unsigned int *max_level = data; + unsigned int level; + const char *p = strstr(pm->metric_group, "TopdownL"); + + if (!p || p[8] == '\0') + return 0; + + level = p[8] - '0'; + if (level > *max_level) + *max_level = level; + + return 0; +} + +unsigned int metricgroups__topdown_max_level(void) +{ + unsigned int max_level = 0; + const struct pmu_metrics_table *table = pmu_metrics_table__find(); + + if (!table) + return false; + + pmu_metrics_table_for_each_metric(table, metricgroup__topdown_max_level_callback, + &max_level); + return max_level; +} + int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, struct rblist *new_metric_events, struct rblist *old_metric_events) diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 8d50052c5b4c..77472e35705e 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -81,6 +81,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist, void metricgroup__print(const struct print_callbacks *print_cb, void *print_state); bool metricgroup__has_metric(const char *metric); +unsigned int metricgroups__topdown_max_level(void); int arch_get_runtimeparam(const struct pmu_metric *pm); void metricgroup__rblist_exit(struct rblist *metric_events); diff --git a/tools/perf/util/topdown.c b/tools/perf/util/topdown.c index 1090841550f7..18fd5fed5d1a 100644 --- a/tools/perf/util/topdown.c +++ b/tools/perf/util/topdown.c @@ -1,74 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -#include -#include "pmu.h" -#include "pmu-hybrid.h" #include "topdown.h" - -int topdown_filter_events(const char **attr, char **str, bool use_group, - const char *pmu_name) -{ - int off = 0; - int i; - int len = 0; - char *s; - bool is_hybrid = perf_pmu__is_hybrid(pmu_name); - - for (i = 0; attr[i]; i++) { - if (pmu_have_event(pmu_name, attr[i])) { - if (is_hybrid) - len += strlen(attr[i]) + strlen(pmu_name) + 3; - else - len += strlen(attr[i]) + 1; - attr[i - off] = attr[i]; - } else - off++; - } - attr[i - off] = NULL; - - *str = malloc(len + 1 + 2); - if (!*str) - return -1; - s = *str; - if (i - off == 0) { - *s = 0; - return 0; - } - if (use_group) - *s++ = '{'; - for (i = 0; attr[i]; i++) { - if (!is_hybrid) - strcpy(s, attr[i]); - else - sprintf(s, "%s/%s/", pmu_name, attr[i]); - s += strlen(s); - *s++ = ','; - } - if (use_group) { - s[-1] = '}'; - *s = 0; - } else - s[-1] = 0; - return 0; -} - -__weak bool arch_topdown_check_group(bool *warn) -{ - *warn = false; - return false; -} - -__weak void arch_topdown_group_warn(void) -{ -} +#include __weak bool arch_topdown_sample_read(struct evsel *leader __maybe_unused) { return false; } - -__weak const char *arch_get_topdown_pmu_name(struct evlist *evlist - __maybe_unused, - bool warn __maybe_unused) -{ - return "cpu"; -} diff --git a/tools/perf/util/topdown.h b/tools/perf/util/topdown.h index f9531528c559..1996c5fedcd7 100644 --- a/tools/perf/util/topdown.h +++ b/tools/perf/util/topdown.h @@ -1,14 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef TOPDOWN_H #define TOPDOWN_H 1 -#include "evsel.h" -#include "evlist.h" -bool arch_topdown_check_group(bool *warn); -void arch_topdown_group_warn(void); +#include + +struct evsel; + bool arch_topdown_sample_read(struct evsel *leader); -const char *arch_get_topdown_pmu_name(struct evlist *evlist, bool warn); -int topdown_filter_events(const char **attr, char **str, bool use_group, - const char *pmu_name); #endif -- cgit v1.2.3