Check if current kernel support available memory events
and display the status within -e  list option:

  $ perf mem record -e list
  [ok] ldlat-loads
  [ok] ldlat-stores

Link: http://lkml.kernel.org/n/tip-r8smhxjfe69q67jwt7mzs...@git.kernel.org
Signed-off-by: Jiri Olsa <jo...@kernel.org>
---
 tools/perf/builtin-mem.c     | 14 +++++++++++++-
 tools/perf/util/mem-events.c | 35 ++++++++++++++++++++++++++++++++---
 tools/perf/util/mem-events.h |  3 +++
 3 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index b3f8a89ede40..e64e0aa7ba0e 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -40,7 +40,8 @@ static int parse_record_events(const struct option *opt,
        for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
                struct perf_mem_event *e = &perf_mem_events[j];
 
-               fprintf(stderr, "%-20s%s",
+               fprintf(stderr, "%s%-20s%s",
+                       e->supported ? "[ok] " : "     ",
                        e->tag, verbose ? "" : "\n");
                if (verbose)
                        fprintf(stderr, " [%s]\n", e->name);
@@ -92,6 +93,12 @@ static int __cmd_record(int argc, const char **argv, struct 
perf_mem *mem)
                if (!perf_mem_events[j].record)
                        continue;
 
+               if (!perf_mem_events[j].supported) {
+                       pr_err("failed: event '%s' not supported\n",
+                              perf_mem_events[j].name);
+                       return -1;
+               }
+
                rec_argv[i++] = "-e";
                rec_argv[i++] = perf_mem_events[j].name;
        };
@@ -355,6 +362,11 @@ int cmd_mem(int argc, const char **argv, const char 
*prefix __maybe_unused)
                NULL
        };
 
+       if (perf_mem_events__init()) {
+               pr_err("failed: memory events not supported\n");
+               return -1;
+       }
+
        argc = parse_options_subcommand(argc, argv, mem_options, 
mem_subcommands,
                                        mem_usage, 
PARSE_OPT_STOP_AT_NON_OPTION);
 
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
index b1507c04b257..e21853fe1312 100644
--- a/tools/perf/util/mem-events.c
+++ b/tools/perf/util/mem-events.c
@@ -2,15 +2,20 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <api/fs/fs.h>
 #include "mem-events.h"
 #include "debug.h"
 
-#define E(t, n) { .tag = t, .name = n }
+#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
 
 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
-       E("ldlat-loads",        "cpu/mem-loads,ldlat=30/P"),
-       E("ldlat-stores",       "cpu/mem-stores/P"),
+       E("ldlat-loads",        "cpu/mem-loads,ldlat=30/P",     "mem-loads"),
+       E("ldlat-stores",       "cpu/mem-stores/P",             "mem-stores"),
 };
+#undef E
 
 #undef E
 
@@ -49,3 +54,27 @@ int perf_mem_events__parse(const char *str)
        pr_err("failed: event '%s' not found, use '-e list' to get list of 
available events\n", str);
        return -1;
 }
+
+int perf_mem_events__init(void)
+{
+       const char *mnt = sysfs__mount();
+       bool found = false;
+       int j;
+
+       if (!mnt)
+               return -ENOENT;
+
+       for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
+               char path[PATH_MAX];
+               struct perf_mem_event *e = &perf_mem_events[j];
+               struct stat st;
+
+               scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
+                         mnt, e->sysfs_name);
+
+               if (!stat(path, &st))
+                       e->supported = found = true;
+       }
+
+       return found ? 0 : -ENOENT;
+}
diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h
index 0b5247468462..b9a786346c03 100644
--- a/tools/perf/util/mem-events.h
+++ b/tools/perf/util/mem-events.h
@@ -5,8 +5,10 @@
 
 struct perf_mem_event {
        bool            record;
+       bool            supported;
        const char      *tag;
        const char      *name;
+       const char      *sysfs_name;
 };
 
 enum {
@@ -18,6 +20,7 @@ enum {
 extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];
 
 int perf_mem_events__parse(const char *str);
+int perf_mem_events__init(void);
 
 #endif /* __PERF_MEM_EVENTS_H */
 
-- 
2.4.3

Reply via email to