summaryrefslogtreecommitdiff
path: root/tools/perf/util/stat-display.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/stat-display.c')
-rw-r--r--tools/perf/util/stat-display.c230
1 files changed, 38 insertions, 192 deletions
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index e852ac0d9847..729ad5cd52cb 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -798,40 +798,28 @@ static void abs_printout(struct perf_stat_config *config,
print_cgroup(config, os, evsel->cgrp);
}
-static bool is_mixed_hw_group(struct evsel *counter)
-{
- struct evlist *evlist = counter->evlist;
- u32 pmu_type = counter->core.attr.type;
- struct evsel *pos;
-
- if (counter->core.nr_members < 2)
- return false;
-
- evlist__for_each_entry(evlist, pos) {
- /* software events can be part of any hardware group */
- if (pos->core.attr.type == PERF_TYPE_SOFTWARE)
- continue;
- if (pmu_type == PERF_TYPE_SOFTWARE) {
- pmu_type = pos->core.attr.type;
- continue;
- }
- if (pmu_type != pos->core.attr.type)
- return true;
- }
-
- return false;
-}
-
-static bool evlist__has_hybrid(struct evlist *evlist)
+static bool evlist__has_hybrid_pmus(struct evlist *evlist)
{
struct evsel *evsel;
+ struct perf_pmu *last_core_pmu = NULL;
if (perf_pmus__num_core_pmus() == 1)
return false;
evlist__for_each_entry(evlist, evsel) {
- if (evsel->core.is_pmu_core)
+ if (evsel->core.is_pmu_core) {
+ struct perf_pmu *pmu = evsel__find_pmu(evsel);
+
+ if (pmu == last_core_pmu)
+ continue;
+
+ if (last_core_pmu == NULL) {
+ last_core_pmu = pmu;
+ continue;
+ }
+ /* A distinct core PMU. */
return true;
+ }
}
return false;
@@ -872,10 +860,8 @@ static void printout(struct perf_stat_config *config, struct outstate *os,
ok = false;
if (counter->supported) {
- if (!evlist__has_hybrid(counter->evlist)) {
+ if (!evlist__has_hybrid_pmus(counter->evlist)) {
config->print_free_counters_hint = 1;
- if (is_mixed_hw_group(counter))
- config->print_mixed_hw_group_error = 1;
}
}
}
@@ -929,61 +915,6 @@ static void printout(struct perf_stat_config *config, struct outstate *os,
}
}
-static void evsel__uniquify_counter(struct evsel *counter)
-{
- const char *name, *pmu_name;
- char *new_name, *config;
- int ret;
-
- /* No uniquification necessary. */
- if (!counter->needs_uniquify)
- return;
-
- /* The evsel was already uniquified. */
- if (counter->uniquified_name)
- return;
-
- /* Avoid checking to uniquify twice. */
- counter->uniquified_name = true;
-
- name = evsel__name(counter);
- pmu_name = counter->pmu->name;
- /* Already prefixed by the PMU name. */
- if (!strncmp(name, pmu_name, strlen(pmu_name)))
- return;
-
- config = strchr(name, '/');
- if (config) {
- int len = config - name;
-
- if (config[1] == '/') {
- /* case: event// */
- ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 2);
- } else {
- /* case: event/.../ */
- ret = asprintf(&new_name, "%s/%.*s,%s", pmu_name, len, name, config + 1);
- }
- } else {
- config = strchr(name, ':');
- if (config) {
- /* case: event:.. */
- int len = config - name;
-
- ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 1);
- } else {
- /* case: event */
- ret = asprintf(&new_name, "%s/%s/", pmu_name, name);
- }
- }
- if (ret > 0) {
- free(counter->name);
- counter->name = new_name;
- } else {
- /* ENOMEM from asprintf. */
- counter->uniquified_name = false;
- }
-}
-
/**
* should_skip_zero_count() - Check if the event should print 0 values.
* @config: The perf stat configuration (including aggregation mode).
@@ -1022,8 +953,16 @@ static bool should_skip_zero_counter(struct perf_stat_config *config,
return true;
/*
- * Many tool events are only gathered on the first index, skip other
- * zero values.
+ * In per-thread mode the aggr_map and aggr_get_id functions may be
+ * NULL, assume all 0 values should be output in that case.
+ */
+ if (!config->aggr_map || !config->aggr_get_id)
+ return false;
+
+ /*
+ * Tool events may be gathered on all logical CPUs, for example
+ * system_time, but for many the first index is the only one used, for
+ * example num_cores. Don't skip for the first index.
*/
if (evsel__is_tool(counter)) {
struct aggr_cpu_id own_id =
@@ -1031,15 +970,12 @@ static bool should_skip_zero_counter(struct perf_stat_config *config,
return !aggr_cpu_id__equal(id, &own_id);
}
-
/*
- * Skip value 0 when it's an uncore event and the given aggr id
- * does not belong to the PMU cpumask.
+ * Skip value 0 when the counter's cpumask doesn't match the given aggr
+ * id.
*/
- if (!counter->pmu || !counter->pmu->is_uncore)
- return false;
- perf_cpu_map__for_each_cpu(cpu, idx, counter->pmu->cpus) {
+ perf_cpu_map__for_each_cpu(cpu, idx, counter->core.cpus) {
struct aggr_cpu_id own_id = config->aggr_get_id(config, cpu);
if (aggr_cpu_id__equal(id, &own_id))
@@ -1066,10 +1002,15 @@ static void print_counter_aggrdata(struct perf_stat_config *config,
os->evsel = counter;
/* Skip already merged uncore/hybrid events */
- if (counter->merged_stat)
- return;
-
- evsel__uniquify_counter(counter);
+ if (config->aggr_mode != AGGR_NONE) {
+ if (evsel__is_hybrid(counter)) {
+ if (config->hybrid_merge && counter->first_wildcard_match != NULL)
+ return;
+ } else {
+ if (counter->first_wildcard_match != NULL)
+ return;
+ }
+ }
val = aggr->counts.val;
ena = aggr->counts.ena;
@@ -1575,11 +1516,6 @@ static void print_footer(struct perf_stat_config *config)
" echo 0 > /proc/sys/kernel/nmi_watchdog\n"
" perf stat ...\n"
" echo 1 > /proc/sys/kernel/nmi_watchdog\n");
-
- if (config->print_mixed_hw_group_error)
- fprintf(output,
- "The events in group usually have to be from "
- "the same PMU. Try reorganizing the group.\n");
}
static void print_percore(struct perf_stat_config *config,
@@ -1650,96 +1586,6 @@ static void print_cgroup_counter(struct perf_stat_config *config, struct evlist
print_metric_end(config, os);
}
-/* Should uniquify be disabled for the evlist? */
-static bool evlist__disable_uniquify(const struct evlist *evlist)
-{
- struct evsel *counter;
- struct perf_pmu *last_pmu = NULL;
- bool first = true;
-
- evlist__for_each_entry(evlist, counter) {
- /* If PMUs vary then uniquify can be useful. */
- if (!first && counter->pmu != last_pmu)
- return false;
- first = false;
- if (counter->pmu) {
- /* Allow uniquify for uncore PMUs. */
- if (!counter->pmu->is_core)
- return false;
- /* Keep hybrid event names uniquified for clarity. */
- if (perf_pmus__num_core_pmus() > 1)
- return false;
- }
- }
- return true;
-}
-
-static void evsel__set_needs_uniquify(struct evsel *counter, const struct perf_stat_config *config)
-{
- struct evsel *evsel;
-
- if (counter->merged_stat) {
- /* Counter won't be shown. */
- return;
- }
-
- if (counter->use_config_name || counter->is_libpfm_event) {
- /* Original name will be used. */
- return;
- }
-
- if (!config->hybrid_merge && evsel__is_hybrid(counter)) {
- /* Unique hybrid counters necessary. */
- counter->needs_uniquify = true;
- return;
- }
-
- if (counter->core.attr.type < PERF_TYPE_MAX && counter->core.attr.type != PERF_TYPE_RAW) {
- /* Legacy event, don't uniquify. */
- return;
- }
-
- if (counter->pmu && counter->pmu->is_core &&
- counter->alternate_hw_config != PERF_COUNT_HW_MAX) {
- /* A sysfs or json event replacing a legacy event, don't uniquify. */
- return;
- }
-
- if (config->aggr_mode == AGGR_NONE) {
- /* Always unique with no aggregation. */
- counter->needs_uniquify = true;
- return;
- }
-
- /*
- * Do other non-merged events in the evlist have the same name? If so
- * uniquify is necessary.
- */
- evlist__for_each_entry(counter->evlist, evsel) {
- if (evsel == counter || evsel->merged_stat)
- continue;
-
- if (evsel__name_is(counter, evsel__name(evsel))) {
- counter->needs_uniquify = true;
- return;
- }
- }
-}
-
-static void evlist__set_needs_uniquify(struct evlist *evlist, const struct perf_stat_config *config)
-{
- struct evsel *counter;
-
- if (evlist__disable_uniquify(evlist)) {
- evlist__for_each_entry(evlist, counter)
- counter->uniquified_name = true;
- return;
- }
-
- evlist__for_each_entry(evlist, counter)
- evsel__set_needs_uniquify(counter, config);
-}
-
void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config,
struct target *_target, struct timespec *ts,
int argc, const char **argv)
@@ -1751,7 +1597,7 @@ void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *conf
.first = true,
};
- evlist__set_needs_uniquify(evlist, config);
+ evlist__uniquify_evsel_names(evlist, config);
if (config->iostat_run)
evlist->selected = evlist__first(evlist);