Skip to content

Commit 5b546de

Browse files
captain5050namhyung
authored andcommitted
perf topdown: Use attribute to see an event is a topdown metic or slots
The string comparisons were overly broad and could fire for the incorrect PMU and events. Switch to using the config in the attribute then add a perf test to confirm the attribute config values match those of parsed events of that name and don't match others. This exposed matches for slots events that shouldn't have matched as the slots fixed counter event, such as topdown.slots_p. Fixes: fbc7983 ("perf x86/topdown: Refine helper arch_is_topdown_metrics()") Signed-off-by: Ian Rogers <irogers@google.com> Link: https://lore.kernel.org/r/20250719030517.1990983-14-irogers@google.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
1 parent 811082e commit 5b546de

7 files changed

Lines changed: 108 additions & 55 deletions

File tree

tools/perf/arch/x86/include/arch-tests.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#ifndef ARCH_TESTS_H
33
#define ARCH_TESTS_H
44

5+
#include "tests/tests.h"
6+
57
struct test_suite;
68

79
/* Tests */
@@ -17,6 +19,8 @@ int test__amd_ibs_via_core_pmu(struct test_suite *test, int subtest);
1719
int test__amd_ibs_period(struct test_suite *test, int subtest);
1820
int test__hybrid(struct test_suite *test, int subtest);
1921

22+
DECLARE_SUITE(x86_topdown);
23+
2024
extern struct test_suite *arch_tests[];
2125

2226
#endif

tools/perf/arch/x86/tests/Build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ endif
1111
perf-test-$(CONFIG_X86_64) += bp-modify.o
1212
perf-test-y += amd-ibs-via-core-pmu.o
1313
perf-test-y += amd-ibs-period.o
14+
perf-test-y += topdown.o
1415

1516
ifdef SHELLCHECK
1617
SHELL_TESTS := gen-insn-x86-dat.sh

tools/perf/arch/x86/tests/arch-tests.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@ struct test_suite *arch_tests[] = {
5353
&suite__amd_ibs_via_core_pmu,
5454
&suite__amd_ibs_period,
5555
&suite__hybrid,
56+
&suite__x86_topdown,
5657
NULL,
5758
};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include "arch-tests.h"
3+
#include "../util/topdown.h"
4+
#include "evlist.h"
5+
#include "parse-events.h"
6+
#include "pmu.h"
7+
#include "pmus.h"
8+
9+
static int event_cb(void *state, struct pmu_event_info *info)
10+
{
11+
char buf[256];
12+
struct parse_events_error parse_err;
13+
int *ret = state, err;
14+
struct evlist *evlist = evlist__new();
15+
struct evsel *evsel;
16+
17+
if (!evlist)
18+
return -ENOMEM;
19+
20+
parse_events_error__init(&parse_err);
21+
snprintf(buf, sizeof(buf), "%s/%s/", info->pmu->name, info->name);
22+
err = parse_events(evlist, buf, &parse_err);
23+
if (err) {
24+
parse_events_error__print(&parse_err, buf);
25+
*ret = TEST_FAIL;
26+
}
27+
parse_events_error__exit(&parse_err);
28+
evlist__for_each_entry(evlist, evsel) {
29+
bool fail = false;
30+
bool p_core_pmu = evsel->pmu->type == PERF_TYPE_RAW;
31+
const char *name = evsel__name(evsel);
32+
33+
if (strcasestr(name, "uops_retired.slots") ||
34+
strcasestr(name, "topdown.backend_bound_slots") ||
35+
strcasestr(name, "topdown.br_mispredict_slots") ||
36+
strcasestr(name, "topdown.memory_bound_slots") ||
37+
strcasestr(name, "topdown.bad_spec_slots") ||
38+
strcasestr(name, "topdown.slots_p")) {
39+
if (arch_is_topdown_slots(evsel) || arch_is_topdown_metrics(evsel))
40+
fail = true;
41+
} else if (strcasestr(name, "slots")) {
42+
if (arch_is_topdown_slots(evsel) != p_core_pmu ||
43+
arch_is_topdown_metrics(evsel))
44+
fail = true;
45+
} else if (strcasestr(name, "topdown")) {
46+
if (arch_is_topdown_slots(evsel) ||
47+
arch_is_topdown_metrics(evsel) != p_core_pmu)
48+
fail = true;
49+
} else if (arch_is_topdown_slots(evsel) || arch_is_topdown_metrics(evsel)) {
50+
fail = true;
51+
}
52+
if (fail) {
53+
pr_debug("Broken topdown information for '%s'\n", evsel__name(evsel));
54+
*ret = TEST_FAIL;
55+
}
56+
}
57+
evlist__delete(evlist);
58+
return 0;
59+
}
60+
61+
static int test__x86_topdown(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
62+
{
63+
int ret = TEST_OK;
64+
struct perf_pmu *pmu = NULL;
65+
66+
if (!topdown_sys_has_perf_metrics())
67+
return TEST_OK;
68+
69+
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
70+
if (perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/false, &ret, event_cb))
71+
break;
72+
}
73+
return ret;
74+
}
75+
76+
DEFINE_SUITE("x86 topdown", x86_topdown);

tools/perf/arch/x86/util/evsel.c

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,47 +23,25 @@ void arch_evsel__set_sample_weight(struct evsel *evsel)
2323
bool evsel__sys_has_perf_metrics(const struct evsel *evsel)
2424
{
2525
struct perf_pmu *pmu;
26-
u32 type = evsel->core.attr.type;
2726

28-
/*
29-
* The PERF_TYPE_RAW type is the core PMU type, e.g., "cpu" PMU
30-
* on a non-hybrid machine, "cpu_core" PMU on a hybrid machine.
31-
* The slots event is only available for the core PMU, which
32-
* supports the perf metrics feature.
33-
* Checking both the PERF_TYPE_RAW type and the slots event
34-
* should be good enough to detect the perf metrics feature.
35-
*/
36-
again:
37-
switch (type) {
38-
case PERF_TYPE_HARDWARE:
39-
case PERF_TYPE_HW_CACHE:
40-
type = evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT;
41-
if (type)
42-
goto again;
43-
break;
44-
case PERF_TYPE_RAW:
45-
break;
46-
default:
27+
if (!topdown_sys_has_perf_metrics())
4728
return false;
48-
}
49-
50-
pmu = evsel->pmu;
51-
if (pmu && perf_pmu__is_fake(pmu))
52-
pmu = NULL;
5329

54-
if (!pmu) {
55-
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
56-
if (pmu->type == PERF_TYPE_RAW)
57-
break;
58-
}
59-
}
60-
return pmu && perf_pmu__have_event(pmu, "slots");
30+
/*
31+
* The PERF_TYPE_RAW type is the core PMU type, e.g., "cpu" PMU on a
32+
* non-hybrid machine, "cpu_core" PMU on a hybrid machine. The
33+
* topdown_sys_has_perf_metrics checks the slots event is only available
34+
* for the core PMU, which supports the perf metrics feature. Checking
35+
* both the PERF_TYPE_RAW type and the slots event should be good enough
36+
* to detect the perf metrics feature.
37+
*/
38+
pmu = evsel__find_pmu(evsel);
39+
return pmu && pmu->type == PERF_TYPE_RAW;
6140
}
6241

6342
bool arch_evsel__must_be_in_group(const struct evsel *evsel)
6443
{
65-
if (!evsel__sys_has_perf_metrics(evsel) || !evsel->name ||
66-
strcasestr(evsel->name, "uops_retired.slots"))
44+
if (!evsel__sys_has_perf_metrics(evsel))
6745
return false;
6846

6947
return arch_is_topdown_metrics(evsel) || arch_is_topdown_slots(evsel);

tools/perf/arch/x86/util/topdown.c

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// SPDX-License-Identifier: GPL-2.0
2-
#include "api/fs/fs.h"
3-
#include "util/evsel.h"
42
#include "util/evlist.h"
53
#include "util/pmu.h"
64
#include "util/pmus.h"
75
#include "util/topdown.h"
86
#include "topdown.h"
97
#include "evsel.h"
108

9+
// cmask=0, inv=0, pc=0, edge=0, umask=4, event=0
10+
#define TOPDOWN_SLOTS 0x0400
11+
1112
/* Check whether there is a PMU which supports the perf metrics. */
1213
bool topdown_sys_has_perf_metrics(void)
1314
{
@@ -32,31 +33,19 @@ bool topdown_sys_has_perf_metrics(void)
3233
return has_perf_metrics;
3334
}
3435

35-
#define TOPDOWN_SLOTS 0x0400
3636
bool arch_is_topdown_slots(const struct evsel *evsel)
3737
{
38-
if (evsel->core.attr.config == TOPDOWN_SLOTS)
39-
return true;
40-
41-
return false;
38+
return evsel->core.attr.type == PERF_TYPE_RAW &&
39+
evsel->core.attr.config == TOPDOWN_SLOTS &&
40+
evsel->core.attr.config1 == 0;
4241
}
4342

4443
bool arch_is_topdown_metrics(const struct evsel *evsel)
4544
{
46-
int config = evsel->core.attr.config;
47-
const char *name_from_config;
48-
struct perf_pmu *pmu;
49-
50-
/* All topdown events have an event code of 0. */
51-
if ((config & 0xFF) != 0)
52-
return false;
53-
54-
pmu = evsel__find_pmu(evsel);
55-
if (!pmu || !pmu->is_core)
56-
return false;
57-
58-
name_from_config = perf_pmu__name_from_config(pmu, config);
59-
return name_from_config && strcasestr(name_from_config, "topdown");
45+
// cmask=0, inv=0, pc=0, edge=0, umask=0x80-0x87, event=0
46+
return evsel->core.attr.type == PERF_TYPE_RAW &&
47+
(evsel->core.attr.config & 0xFFFFF8FF) == 0x8000 &&
48+
evsel->core.attr.config1 == 0;
6049
}
6150

6251
/*

tools/perf/arch/x86/util/topdown.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
#ifndef _TOPDOWN_H
33
#define _TOPDOWN_H 1
44

5+
#include <stdbool.h>
6+
7+
struct evsel;
8+
59
bool topdown_sys_has_perf_metrics(void);
610
bool arch_is_topdown_slots(const struct evsel *evsel);
711
bool arch_is_topdown_metrics(const struct evsel *evsel);

0 commit comments

Comments
 (0)