perf_counter: Detect debugfs location
authorJason Baron <jbaron@redhat.com>
Tue, 21 Jul 2009 18:16:29 +0000 (14:16 -0400)
committerPeter Zijlstra <a.p.zijlstra@chello.nl>
Wed, 22 Jul 2009 16:05:57 +0000 (18:05 +0200)
If "/sys/kernel/debug" is not a debugfs mount point, search for the debugfs
filesystem in /proc/mounts, but also allows the user to specify
'--debugfs-dir=blah' or set the environment variable: 'PERF_DEBUGFS_DIR'

Signed-off-by: Jason Baron <jbaron@redhat.com>
[ also made it probe "/debug" by default ]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20090721181629.GA3094@redhat.com>

tools/perf/perf.c
tools/perf/util/cache.h
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/string.h

index c565678..31982ad 100644 (file)
@@ -12,6 +12,8 @@
 #include "util/cache.h"
 #include "util/quote.h"
 #include "util/run-command.h"
+#include "util/parse-events.h"
+#include "util/string.h"
 
 const char perf_usage_string[] =
        "perf [--version] [--help] COMMAND [ARGS]";
@@ -25,6 +27,8 @@ struct pager_config {
        int val;
 };
 
+static char debugfs_mntpt[MAXPATHLEN];
+
 static int pager_command_config(const char *var, const char *value, void *data)
 {
        struct pager_config *c = data;
@@ -56,6 +60,15 @@ static void commit_pager_choice(void) {
        }
 }
 
+static void set_debugfs_path(void)
+{
+       char *path;
+
+       path = getenv(PERF_DEBUGFS_ENVIRONMENT);
+       snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt,
+                "tracing/events");
+}
+
 static int handle_options(const char*** argv, int* argc, int* envchanged)
 {
        int handled = 0;
@@ -122,6 +135,22 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
                        setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
                        if (envchanged)
                                *envchanged = 1;
+               } else if (!strcmp(cmd, "--debugfs-dir")) {
+                       if (*argc < 2) {
+                               fprintf(stderr, "No directory given for --debugfs-dir.\n");
+                               usage(perf_usage_string);
+                       }
+                       strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN);
+                       debugfs_mntpt[MAXPATHLEN - 1] = '\0';
+                       if (envchanged)
+                               *envchanged = 1;
+                       (*argv)++;
+                       (*argc)--;
+               } else if (!prefixcmp(cmd, "--debugfs-dir=")) {
+                       strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN);
+                       debugfs_mntpt[MAXPATHLEN - 1] = '\0';
+                       if (envchanged)
+                               *envchanged = 1;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(perf_usage_string);
@@ -228,6 +257,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        if (use_pager == -1 && p->option & USE_PAGER)
                use_pager = 1;
        commit_pager_choice();
+       set_debugfs_path();
 
        status = p->fn(argc, argv, prefix);
        if (status)
@@ -346,6 +376,49 @@ static int run_argv(int *argcp, const char ***argv)
        return done_alias;
 }
 
+/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
+static void get_debugfs_mntpt(void)
+{
+       FILE *file;
+       char fs_type[100];
+       char debugfs[MAXPATHLEN];
+
+       /*
+        * try the standard location
+        */
+       if (valid_debugfs_mount("/sys/kernel/debug/") == 0) {
+               strcpy(debugfs_mntpt, "/sys/kernel/debug/");
+               return;
+       }
+
+       /*
+        * try the sane location
+        */
+       if (valid_debugfs_mount("/debug/") == 0) {
+               strcpy(debugfs_mntpt, "/debug/");
+               return;
+       }
+
+       /*
+        * give up and parse /proc/mounts
+        */
+       file = fopen("/proc/mounts", "r");
+       if (file == NULL)
+               return;
+
+       while (fscanf(file, "%*s %"
+                     STR(MAXPATHLEN)
+                     "s %99s %*s %*d %*d\n",
+                     debugfs, fs_type) == 2) {
+               if (strcmp(fs_type, "debugfs") == 0)
+                       break;
+       }
+       fclose(file);
+       if (strcmp(fs_type, "debugfs") == 0) {
+               strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
+               debugfs_mntpt[MAXPATHLEN - 1] = '\0';
+       }
+}
 
 int main(int argc, const char **argv)
 {
@@ -354,7 +427,8 @@ int main(int argc, const char **argv)
        cmd = perf_extract_argv0_path(argv[0]);
        if (!cmd)
                cmd = "perf-help";
-
+       /* get debugfs mount point from /proc/mounts */
+       get_debugfs_mntpt();
        /*
         * "perf-xxxx" is the same as "perf xxxx", but we obviously:
         *
@@ -377,6 +451,7 @@ int main(int argc, const char **argv)
        argc--;
        handle_options(&argv, &argc, NULL);
        commit_pager_choice();
+       set_debugfs_path();
        if (argc > 0) {
                if (!prefixcmp(argv[0], "--"))
                        argv[0] += 2;
index 161d5f4..4b50c41 100644 (file)
@@ -18,6 +18,7 @@
 #define PERFATTRIBUTES_FILE ".perfattributes"
 #define INFOATTRIBUTES_FILE "info/attributes"
 #define ATTRIBUTE_MACRO_PREFIX "[attr]"
+#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
 
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
index 5a3cd3a..7bdad8d 100644 (file)
@@ -5,6 +5,7 @@
 #include "parse-events.h"
 #include "exec_cmd.h"
 #include "string.h"
+#include "cache.h"
 
 extern char *strcasestr(const char *haystack, const char *needle);
 
@@ -12,8 +13,6 @@ int                                   nr_counters;
 
 struct perf_counter_attr               attrs[MAX_COUNTERS];
 
-static char default_debugfs_path[] = "/sys/kernel/debug/tracing/events";
-
 struct event_symbol {
        u8      type;
        u64     config;
@@ -21,6 +20,8 @@ struct event_symbol {
        char    *alias;
 };
 
+char debugfs_path[MAXPATHLEN];
+
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
 
@@ -114,27 +115,27 @@ static unsigned long hw_cache_stat[C(MAX)] = {
 
 #define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st)           \
        while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next)        \
-       if (snprintf(file, MAXPATHLEN, "%s/%s", default_debugfs_path,          \
-                       sys_dirent.d_name) &&                                  \
+       if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path,                  \
+                       sys_dirent.d_name) &&                                  \
           (!stat(file, &st)) && (S_ISDIR(st.st_mode)) &&                      \
           (strcmp(sys_dirent.d_name, ".")) &&                                 \
           (strcmp(sys_dirent.d_name, "..")))
 
 #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st)    \
        while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next)        \
-       if (snprintf(file, MAXPATHLEN, "%s/%s/%s", default_debugfs_path,       \
-                       sys_dirent.d_name, evt_dirent.d_name) &&               \
+       if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path,               \
+                    sys_dirent.d_name, evt_dirent.d_name) &&                  \
           (!stat(file, &st)) && (S_ISDIR(st.st_mode)) &&                      \
           (strcmp(evt_dirent.d_name, ".")) &&                                 \
           (strcmp(evt_dirent.d_name, "..")))
 
 #define MAX_EVENT_LENGTH 30
 
-static int valid_debugfs_mount(void)
+int valid_debugfs_mount(const char *debugfs)
 {
        struct statfs st_fs;
 
-       if (statfs(default_debugfs_path, &st_fs) < 0)
+       if (statfs(debugfs, &st_fs) < 0)
                return -ENOENT;
        else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
                return -ENOENT;
@@ -152,10 +153,10 @@ static char *tracepoint_id_to_name(u64 config)
        u64 id;
        char evt_path[MAXPATHLEN];
 
-       if (valid_debugfs_mount())
+       if (valid_debugfs_mount(debugfs_path))
                return "unkown";
 
-       sys_dir = opendir(default_debugfs_path);
+       sys_dir = opendir(debugfs_path);
        if (!sys_dir)
                goto cleanup;
 
@@ -166,7 +167,7 @@ static char *tracepoint_id_to_name(u64 config)
                for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
                                                                evt_path, st) {
                        snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
-                                default_debugfs_path, sys_dirent.d_name,
+                                debugfs_path, sys_dirent.d_name,
                                 evt_dirent.d_name);
                        fd = open(evt_path, O_RDONLY);
                        if (fd < 0)
@@ -363,7 +364,7 @@ static int parse_tracepoint_event(const char **strp,
        u64 id;
        char evt_path[MAXPATHLEN];
 
-       if (valid_debugfs_mount())
+       if (valid_debugfs_mount(debugfs_path))
                return 0;
 
        evt_name = strchr(*strp, ':');
@@ -381,8 +382,8 @@ static int parse_tracepoint_event(const char **strp,
        if (evt_length >= MAX_EVENT_LENGTH)
                return 0;
 
-       snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", default_debugfs_path,
-                               sys_name, evt_name);
+       snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
+                sys_name, evt_name);
        fd = open(evt_path, O_RDONLY);
        if (fd < 0)
                return 0;
@@ -568,10 +569,10 @@ static void print_tracepoint_events(void)
        struct stat st;
        char evt_path[MAXPATHLEN];
 
-       if (valid_debugfs_mount())
+       if (valid_debugfs_mount(debugfs_path))
                return;
 
-       sys_dir = opendir(default_debugfs_path);
+       sys_dir = opendir(debugfs_path);
        if (!sys_dir)
                goto cleanup;
 
index e3d5529..1ea5d09 100644 (file)
@@ -3,6 +3,8 @@
  * Parse symbolic events/counts passed in as options:
  */
 
+struct option;
+
 extern int                     nr_counters;
 
 extern struct perf_counter_attr attrs[MAX_COUNTERS];
@@ -15,3 +17,6 @@ extern int parse_events(const struct option *opt, const char *str, int unset);
 
 extern void print_events(void);
 
+extern char debugfs_path[];
+extern int valid_debugfs_mount(const char *debugfs);
+
index 3dca2f6..bf39dfa 100644 (file)
@@ -5,4 +5,7 @@
 
 int hex2u64(const char *ptr, u64 *val);
 
+#define _STR(x) #x
+#define STR(x) _STR(x)
+
 #endif