perf stat: Fix find_stat for mixed legacy/non-legacy events

Legacy events typically don't have a PMU when added leading to
mismatched legacy/non-legacy cases in find_stat. Use evsel__find_pmu
to make sure the evsel PMU is looked up. Update the evsel__find_pmu
code to look for the PMU using the extended config type or, for legacy
hardware/hw_cache events on non-hybrid systems, just use the core PMU.

Before:
```
$ perf stat -e cycles,cpu/instructions/ -a sleep 1
 Performance counter stats for 'system wide':

       215,309,764      cycles
        44,326,491      cpu/instructions/

       1.002555314 seconds time elapsed
```
After:
```
$ perf stat -e cycles,cpu/instructions/ -a sleep 1

 Performance counter stats for 'system wide':

       990,676,332      cycles
     1,235,762,487      cpu/instructions/                #    1.25  insn per cycle

       1.002667198 seconds time elapsed
```

Fixes: 3612ca8e29 ("perf stat: Fix the hard-coded metrics calculation on the hybrid")
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: James Clark <james.clark@linaro.org>
Tested-by: Leo Yan <leo.yan@arm.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
Link: https://lore.kernel.org/r/20250109222109.567031-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Ian Rogers
2025-01-09 14:21:07 -08:00
committed by Namhyung Kim
parent 6ab89b7fc2
commit 8ce0d2da14
2 changed files with 19 additions and 4 deletions

View File

@@ -710,11 +710,25 @@ char *perf_pmus__default_pmu_name(void)
struct perf_pmu *evsel__find_pmu(const struct evsel *evsel)
{
struct perf_pmu *pmu = evsel->pmu;
bool legacy_core_type;
if (!pmu) {
pmu = perf_pmus__find_by_type(evsel->core.attr.type);
((struct evsel *)evsel)->pmu = pmu;
if (pmu)
return pmu;
pmu = perf_pmus__find_by_type(evsel->core.attr.type);
legacy_core_type =
evsel->core.attr.type == PERF_TYPE_HARDWARE ||
evsel->core.attr.type == PERF_TYPE_HW_CACHE;
if (!pmu && legacy_core_type) {
if (perf_pmus__supports_extended_type()) {
u32 type = evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT;
pmu = perf_pmus__find_by_type(type);
} else {
pmu = perf_pmus__find_core_pmu();
}
}
((struct evsel *)evsel)->pmu = pmu;
return pmu;
}

View File

@@ -151,6 +151,7 @@ static double find_stat(const struct evsel *evsel, int aggr_idx, enum stat_type
{
struct evsel *cur;
int evsel_ctx = evsel_context(evsel);
struct perf_pmu *evsel_pmu = evsel__find_pmu(evsel);
evlist__for_each_entry(evsel->evlist, cur) {
struct perf_stat_aggr *aggr;
@@ -177,7 +178,7 @@ static double find_stat(const struct evsel *evsel, int aggr_idx, enum stat_type
* Except the SW CLOCK events,
* ignore if not the PMU we're looking for.
*/
if ((type != STAT_NSECS) && (evsel->pmu != cur->pmu))
if ((type != STAT_NSECS) && (evsel_pmu != evsel__find_pmu(cur)))
continue;
aggr = &cur->stats->aggr[aggr_idx];