#ifndef ARCH_TESTS_H
 #define ARCH_TESTS_H
 
+#include "tests/tests.h"
+
 struct test_suite;
 
 /* Tests */
 int test__amd_ibs_period(struct test_suite *test, int subtest);
 int test__hybrid(struct test_suite *test, int subtest);
 
+DECLARE_SUITE(x86_topdown);
+
 extern struct test_suite *arch_tests[];
 
 #endif
 
 perf-test-$(CONFIG_X86_64) += bp-modify.o
 perf-test-y += amd-ibs-via-core-pmu.o
 perf-test-y += amd-ibs-period.o
+perf-test-y += topdown.o
 
 ifdef SHELLCHECK
   SHELL_TESTS := gen-insn-x86-dat.sh
 
        &suite__amd_ibs_via_core_pmu,
        &suite__amd_ibs_period,
        &suite__hybrid,
+       &suite__x86_topdown,
        NULL,
 };
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+#include "arch-tests.h"
+#include "../util/topdown.h"
+#include "evlist.h"
+#include "parse-events.h"
+#include "pmu.h"
+#include "pmus.h"
+
+static int event_cb(void *state, struct pmu_event_info *info)
+{
+       char buf[256];
+       struct parse_events_error parse_err;
+       int *ret = state, err;
+       struct evlist *evlist = evlist__new();
+       struct evsel *evsel;
+
+       if (!evlist)
+               return -ENOMEM;
+
+       parse_events_error__init(&parse_err);
+       snprintf(buf, sizeof(buf), "%s/%s/", info->pmu->name, info->name);
+       err = parse_events(evlist, buf, &parse_err);
+       if (err) {
+               parse_events_error__print(&parse_err, buf);
+               *ret = TEST_FAIL;
+       }
+       parse_events_error__exit(&parse_err);
+       evlist__for_each_entry(evlist, evsel) {
+               bool fail = false;
+               bool p_core_pmu = evsel->pmu->type == PERF_TYPE_RAW;
+               const char *name = evsel__name(evsel);
+
+               if (strcasestr(name, "uops_retired.slots") ||
+                   strcasestr(name, "topdown.backend_bound_slots") ||
+                   strcasestr(name, "topdown.br_mispredict_slots") ||
+                   strcasestr(name, "topdown.memory_bound_slots") ||
+                   strcasestr(name, "topdown.bad_spec_slots") ||
+                   strcasestr(name, "topdown.slots_p")) {
+                       if (arch_is_topdown_slots(evsel) || arch_is_topdown_metrics(evsel))
+                               fail = true;
+               } else if (strcasestr(name, "slots")) {
+                       if (arch_is_topdown_slots(evsel) != p_core_pmu ||
+                           arch_is_topdown_metrics(evsel))
+                               fail = true;
+               } else if (strcasestr(name, "topdown")) {
+                       if (arch_is_topdown_slots(evsel) ||
+                           arch_is_topdown_metrics(evsel) != p_core_pmu)
+                               fail = true;
+               } else if (arch_is_topdown_slots(evsel) || arch_is_topdown_metrics(evsel)) {
+                       fail = true;
+               }
+               if (fail) {
+                       pr_debug("Broken topdown information for '%s'\n", evsel__name(evsel));
+                       *ret = TEST_FAIL;
+               }
+       }
+       evlist__delete(evlist);
+       return 0;
+}
+
+static int test__x86_topdown(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
+{
+       int ret = TEST_OK;
+       struct perf_pmu *pmu = NULL;
+
+       if (!topdown_sys_has_perf_metrics())
+               return TEST_OK;
+
+       while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+               if (perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/false, &ret, event_cb))
+                       break;
+       }
+       return ret;
+}
+
+DEFINE_SUITE("x86 topdown", x86_topdown);
 
 bool evsel__sys_has_perf_metrics(const struct evsel *evsel)
 {
        struct perf_pmu *pmu;
-       u32 type = evsel->core.attr.type;
 
-       /*
-        * The PERF_TYPE_RAW type is the core PMU type, e.g., "cpu" PMU
-        * on a non-hybrid machine, "cpu_core" PMU on a hybrid machine.
-        * The slots event is only available for the core PMU, which
-        * supports the perf metrics feature.
-        * Checking both the PERF_TYPE_RAW type and the slots event
-        * should be good enough to detect the perf metrics feature.
-        */
-again:
-       switch (type) {
-       case PERF_TYPE_HARDWARE:
-       case PERF_TYPE_HW_CACHE:
-               type = evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT;
-               if (type)
-                       goto again;
-               break;
-       case PERF_TYPE_RAW:
-               break;
-       default:
+       if (!topdown_sys_has_perf_metrics())
                return false;
-       }
-
-       pmu = evsel->pmu;
-       if (pmu && perf_pmu__is_fake(pmu))
-               pmu = NULL;
 
-       if (!pmu) {
-               while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
-                       if (pmu->type == PERF_TYPE_RAW)
-                               break;
-               }
-       }
-       return pmu && perf_pmu__have_event(pmu, "slots");
+       /*
+        * The PERF_TYPE_RAW type is the core PMU type, e.g., "cpu" PMU on a
+        * non-hybrid machine, "cpu_core" PMU on a hybrid machine.  The
+        * topdown_sys_has_perf_metrics checks the slots event is only available
+        * for the core PMU, which supports the perf metrics feature. Checking
+        * both the PERF_TYPE_RAW type and the slots event should be good enough
+        * to detect the perf metrics feature.
+        */
+       pmu = evsel__find_pmu(evsel);
+       return pmu && pmu->type == PERF_TYPE_RAW;
 }
 
 bool arch_evsel__must_be_in_group(const struct evsel *evsel)
 {
-       if (!evsel__sys_has_perf_metrics(evsel) || !evsel->name ||
-           strcasestr(evsel->name, "uops_retired.slots"))
+       if (!evsel__sys_has_perf_metrics(evsel))
                return false;
 
        return arch_is_topdown_metrics(evsel) || arch_is_topdown_slots(evsel);
 
 // SPDX-License-Identifier: GPL-2.0
-#include "api/fs/fs.h"
-#include "util/evsel.h"
 #include "util/evlist.h"
 #include "util/pmu.h"
 #include "util/pmus.h"
 #include "topdown.h"
 #include "evsel.h"
 
+// cmask=0, inv=0, pc=0, edge=0, umask=4, event=0
+#define TOPDOWN_SLOTS          0x0400
+
 /* Check whether there is a PMU which supports the perf metrics. */
 bool topdown_sys_has_perf_metrics(void)
 {
        return has_perf_metrics;
 }
 
-#define TOPDOWN_SLOTS          0x0400
 bool arch_is_topdown_slots(const struct evsel *evsel)
 {
-       if (evsel->core.attr.config == TOPDOWN_SLOTS)
-               return true;
-
-       return false;
+       return evsel->core.attr.type == PERF_TYPE_RAW &&
+              evsel->core.attr.config == TOPDOWN_SLOTS &&
+              evsel->core.attr.config1 == 0;
 }
 
 bool arch_is_topdown_metrics(const struct evsel *evsel)
 {
-       int config = evsel->core.attr.config;
-       const char *name_from_config;
-       struct perf_pmu *pmu;
-
-       /* All topdown events have an event code of 0. */
-       if ((config & 0xFF) != 0)
-               return false;
-
-       pmu = evsel__find_pmu(evsel);
-       if (!pmu || !pmu->is_core)
-               return false;
-
-       name_from_config = perf_pmu__name_from_config(pmu, config);
-       return name_from_config && strcasestr(name_from_config, "topdown");
+       // cmask=0, inv=0, pc=0, edge=0, umask=0x80-0x87, event=0
+       return evsel->core.attr.type == PERF_TYPE_RAW &&
+               (evsel->core.attr.config & 0xFFFFF8FF) == 0x8000 &&
+               evsel->core.attr.config1 == 0;
 }
 
 /*
 
 #ifndef _TOPDOWN_H
 #define _TOPDOWN_H 1
 
+#include <stdbool.h>
+
+struct evsel;
+
 bool topdown_sys_has_perf_metrics(void);
 bool arch_is_topdown_slots(const struct evsel *evsel);
 bool arch_is_topdown_metrics(const struct evsel *evsel);