]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf x86/topdown: Complete topdown slots/metrics events check
authorDapeng Mi <dapeng1.mi@linux.intel.com>
Fri, 13 Sep 2024 08:47:07 +0000 (08:47 +0000)
committerNamhyung Kim <namhyung@kernel.org>
Mon, 30 Sep 2024 22:23:43 +0000 (15:23 -0700)
It's not complete to check whether an event is a topdown slots or
topdown metrics event by only comparing the event name since user
may assign the event by RAW format, e.g.

perf stat -e '{instructions,cpu/r400/,cpu/r8300/}' sleep 1

 Performance counter stats for 'sleep 1':

     <not counted>      instructions
     <not counted>      cpu/r400/
   <not supported>      cpu/r8300/

       1.002917796 seconds time elapsed

       0.002955000 seconds user
       0.000000000 seconds sys

The RAW format slots and topdown-be-bound events are not recognized and
not regroup the events, and eventually cause error.

Thus add two helpers arch_is_topdown_slots()/arch_is_topdown_metrics()
to detect whether an event is topdown slots/metrics event by comparing
the event config directly, and use these two helpers to replace the
original event name comparisons.

Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Yongwei Ma <yongwei.ma@intel.com>
Link: https://lore.kernel.org/r/20240913084712.13861-2-dapeng1.mi@linux.intel.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/arch/x86/util/evlist.c
tools/perf/arch/x86/util/evsel.c
tools/perf/arch/x86/util/topdown.c
tools/perf/arch/x86/util/topdown.h

index 3a4bf13b175931e27d31fc2a676521f7a75767ac..044bc59482c88364aa449e0283ce8fbce433b969 100644 (file)
@@ -10,14 +10,14 @@ int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs)
        if (topdown_sys_has_perf_metrics() &&
            (arch_evsel__must_be_in_group(lhs) || arch_evsel__must_be_in_group(rhs))) {
                /* Ensure the topdown slots comes first. */
-               if (strcasestr(lhs->name, "slots") && !strcasestr(lhs->name, "uops_retired.slots"))
+               if (arch_is_topdown_slots(lhs))
                        return -1;
-               if (strcasestr(rhs->name, "slots") && !strcasestr(rhs->name, "uops_retired.slots"))
+               if (arch_is_topdown_slots(rhs))
                        return 1;
                /* Followed by topdown events. */
-               if (strcasestr(lhs->name, "topdown") && !strcasestr(rhs->name, "topdown"))
+               if (arch_is_topdown_metrics(lhs) && !arch_is_topdown_metrics(rhs))
                        return -1;
-               if (!strcasestr(lhs->name, "topdown") && strcasestr(rhs->name, "topdown"))
+               if (!arch_is_topdown_metrics(lhs) && arch_is_topdown_metrics(rhs))
                        return 1;
        }
 
index cf7c116eeb8e41241be519464f6cfd50c3aec654..3dd29ba2c23b06b70c7fe96c701965b65b24a78c 100644 (file)
@@ -6,6 +6,7 @@
 #include "util/pmu.h"
 #include "util/pmus.h"
 #include "linux/string.h"
+#include "topdown.h"
 #include "evsel.h"
 #include "util/debug.h"
 #include "env.h"
@@ -65,7 +66,7 @@ bool arch_evsel__must_be_in_group(const struct evsel *evsel)
            strcasestr(evsel->name, "uops_retired.slots"))
                return false;
 
-       return strcasestr(evsel->name, "topdown") || strcasestr(evsel->name, "slots");
+       return arch_is_topdown_metrics(evsel) || arch_is_topdown_slots(evsel);
 }
 
 int arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size)
index 3f9a267d4501b669140792aa45e4e9b0f6cb464b..49f25d67ed77698a3f87af6b973bf9963538bc06 100644 (file)
@@ -32,6 +32,52 @@ bool topdown_sys_has_perf_metrics(void)
 }
 
 #define TOPDOWN_SLOTS          0x0400
+bool arch_is_topdown_slots(const struct evsel *evsel)
+{
+       if (evsel->core.attr.config == TOPDOWN_SLOTS)
+               return true;
+
+       return false;
+}
+
+static int compare_topdown_event(void *vstate, struct pmu_event_info *info)
+{
+       int *config = vstate;
+       int event = 0;
+       int umask = 0;
+       char *str;
+
+       if (!strcasestr(info->name, "topdown"))
+               return 0;
+
+       str = strcasestr(info->str, "event=");
+       if (str)
+               sscanf(str, "event=%x", &event);
+
+       str = strcasestr(info->str, "umask=");
+       if (str)
+               sscanf(str, "umask=%x", &umask);
+
+       if (event == 0 && *config == (event | umask << 8))
+               return 1;
+
+       return 0;
+}
+
+bool arch_is_topdown_metrics(const struct evsel *evsel)
+{
+       struct perf_pmu *pmu = evsel__find_pmu(evsel);
+       int config = evsel->core.attr.config;
+
+       if (!pmu || !pmu->is_core)
+               return false;
+
+       if (perf_pmu__for_each_event(pmu, false, &config,
+                                    compare_topdown_event))
+               return true;
+
+       return false;
+}
 
 /*
  * Check whether a topdown group supports sample-read.
@@ -44,7 +90,7 @@ bool arch_topdown_sample_read(struct evsel *leader)
        if (!evsel__sys_has_perf_metrics(leader))
                return false;
 
-       if (leader->core.attr.config == TOPDOWN_SLOTS)
+       if (arch_is_topdown_slots(leader))
                return true;
 
        return false;
index 46bf9273e572fa5d8f41becabc3ffe834e9a8a7e..1bae9b1822d71b8d6c69aa3fe81aab3444238c97 100644 (file)
@@ -3,5 +3,7 @@
 #define _TOPDOWN_H 1
 
 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);
 
 #endif