perf_counter: Detect debugfs location

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>

authored by Jason Baron and committed by Peter Zijlstra 5beeded1 f6bdafef

+102 -17
+76 -1
tools/perf/perf.c
··· 12 #include "util/cache.h" 13 #include "util/quote.h" 14 #include "util/run-command.h" 15 16 const char perf_usage_string[] = 17 "perf [--version] [--help] COMMAND [ARGS]"; ··· 26 const char *cmd; 27 int val; 28 }; 29 30 static int pager_command_config(const char *var, const char *value, void *data) 31 { ··· 58 default: 59 break; 60 } 61 } 62 63 static int handle_options(const char*** argv, int* argc, int* envchanged) ··· 133 (*argc)--; 134 } else if (!prefixcmp(cmd, "--work-tree=")) { 135 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1); 136 if (envchanged) 137 *envchanged = 1; 138 } else { ··· 257 if (use_pager == -1 && p->option & USE_PAGER) 258 use_pager = 1; 259 commit_pager_choice(); 260 261 status = p->fn(argc, argv, prefix); 262 if (status) ··· 376 return done_alias; 377 } 378 379 380 int main(int argc, const char **argv) 381 { ··· 427 cmd = perf_extract_argv0_path(argv[0]); 428 if (!cmd) 429 cmd = "perf-help"; 430 - 431 /* 432 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 433 * ··· 451 argc--; 452 handle_options(&argv, &argc, NULL); 453 commit_pager_choice(); 454 if (argc > 0) { 455 if (!prefixcmp(argv[0], "--")) 456 argv[0] += 2;
··· 12 #include "util/cache.h" 13 #include "util/quote.h" 14 #include "util/run-command.h" 15 + #include "util/parse-events.h" 16 + #include "util/string.h" 17 18 const char perf_usage_string[] = 19 "perf [--version] [--help] COMMAND [ARGS]"; ··· 24 const char *cmd; 25 int val; 26 }; 27 + 28 + static char debugfs_mntpt[MAXPATHLEN]; 29 30 static int pager_command_config(const char *var, const char *value, void *data) 31 { ··· 54 default: 55 break; 56 } 57 + } 58 + 59 + static void set_debugfs_path(void) 60 + { 61 + char *path; 62 + 63 + path = getenv(PERF_DEBUGFS_ENVIRONMENT); 64 + snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt, 65 + "tracing/events"); 66 } 67 68 static int handle_options(const char*** argv, int* argc, int* envchanged) ··· 120 (*argc)--; 121 } else if (!prefixcmp(cmd, "--work-tree=")) { 122 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1); 123 + if (envchanged) 124 + *envchanged = 1; 125 + } else if (!strcmp(cmd, "--debugfs-dir")) { 126 + if (*argc < 2) { 127 + fprintf(stderr, "No directory given for --debugfs-dir.\n"); 128 + usage(perf_usage_string); 129 + } 130 + strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN); 131 + debugfs_mntpt[MAXPATHLEN - 1] = '\0'; 132 + if (envchanged) 133 + *envchanged = 1; 134 + (*argv)++; 135 + (*argc)--; 136 + } else if (!prefixcmp(cmd, "--debugfs-dir=")) { 137 + strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN); 138 + debugfs_mntpt[MAXPATHLEN - 1] = '\0'; 139 if (envchanged) 140 *envchanged = 1; 141 } else { ··· 228 if (use_pager == -1 && p->option & USE_PAGER) 229 use_pager = 1; 230 commit_pager_choice(); 231 + set_debugfs_path(); 232 233 status = p->fn(argc, argv, prefix); 234 if (status) ··· 346 return done_alias; 347 } 348 349 + /* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 350 + static void get_debugfs_mntpt(void) 351 + { 352 + FILE *file; 353 + char fs_type[100]; 354 + char debugfs[MAXPATHLEN]; 355 + 356 + /* 357 + * try the standard location 358 + */ 359 + if (valid_debugfs_mount("/sys/kernel/debug/") == 0) { 360 + strcpy(debugfs_mntpt, "/sys/kernel/debug/"); 361 + return; 362 + } 363 + 364 + /* 365 + * try the sane location 366 + */ 367 + if (valid_debugfs_mount("/debug/") == 0) { 368 + strcpy(debugfs_mntpt, "/debug/"); 369 + return; 370 + } 371 + 372 + /* 373 + * give up and parse /proc/mounts 374 + */ 375 + file = fopen("/proc/mounts", "r"); 376 + if (file == NULL) 377 + return; 378 + 379 + while (fscanf(file, "%*s %" 380 + STR(MAXPATHLEN) 381 + "s %99s %*s %*d %*d\n", 382 + debugfs, fs_type) == 2) { 383 + if (strcmp(fs_type, "debugfs") == 0) 384 + break; 385 + } 386 + fclose(file); 387 + if (strcmp(fs_type, "debugfs") == 0) { 388 + strncpy(debugfs_mntpt, debugfs, MAXPATHLEN); 389 + debugfs_mntpt[MAXPATHLEN - 1] = '\0'; 390 + } 391 + } 392 393 int main(int argc, const char **argv) 394 { ··· 354 cmd = perf_extract_argv0_path(argv[0]); 355 if (!cmd) 356 cmd = "perf-help"; 357 + /* get debugfs mount point from /proc/mounts */ 358 + get_debugfs_mntpt(); 359 /* 360 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 361 * ··· 377 argc--; 378 handle_options(&argv, &argc, NULL); 379 commit_pager_choice(); 380 + set_debugfs_path(); 381 if (argc > 0) { 382 if (!prefixcmp(argv[0], "--")) 383 argv[0] += 2;
+1
tools/perf/util/cache.h
··· 18 #define PERFATTRIBUTES_FILE ".perfattributes" 19 #define INFOATTRIBUTES_FILE "info/attributes" 20 #define ATTRIBUTE_MACRO_PREFIX "[attr]" 21 22 typedef int (*config_fn_t)(const char *, const char *, void *); 23 extern int perf_default_config(const char *, const char *, void *);
··· 18 #define PERFATTRIBUTES_FILE ".perfattributes" 19 #define INFOATTRIBUTES_FILE "info/attributes" 20 #define ATTRIBUTE_MACRO_PREFIX "[attr]" 21 + #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" 22 23 typedef int (*config_fn_t)(const char *, const char *, void *); 24 extern int perf_default_config(const char *, const char *, void *);
+17 -16
tools/perf/util/parse-events.c
··· 5 #include "parse-events.h" 6 #include "exec_cmd.h" 7 #include "string.h" 8 9 extern char *strcasestr(const char *haystack, const char *needle); 10 ··· 13 14 struct perf_counter_attr attrs[MAX_COUNTERS]; 15 16 - static char default_debugfs_path[] = "/sys/kernel/debug/tracing/events"; 17 - 18 struct event_symbol { 19 u8 type; 20 u64 config; 21 char *symbol; 22 char *alias; 23 }; 24 25 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 26 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x ··· 115 116 #define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ 117 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ 118 - if (snprintf(file, MAXPATHLEN, "%s/%s", default_debugfs_path, \ 119 - sys_dirent.d_name) && \ 120 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ 121 (strcmp(sys_dirent.d_name, ".")) && \ 122 (strcmp(sys_dirent.d_name, ".."))) 123 124 #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ 125 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ 126 - if (snprintf(file, MAXPATHLEN, "%s/%s/%s", default_debugfs_path, \ 127 - sys_dirent.d_name, evt_dirent.d_name) && \ 128 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ 129 (strcmp(evt_dirent.d_name, ".")) && \ 130 (strcmp(evt_dirent.d_name, ".."))) 131 132 #define MAX_EVENT_LENGTH 30 133 134 - static int valid_debugfs_mount(void) 135 { 136 struct statfs st_fs; 137 138 - if (statfs(default_debugfs_path, &st_fs) < 0) 139 return -ENOENT; 140 else if (st_fs.f_type != (long) DEBUGFS_MAGIC) 141 return -ENOENT; ··· 153 u64 id; 154 char evt_path[MAXPATHLEN]; 155 156 - if (valid_debugfs_mount()) 157 return "unkown"; 158 159 - sys_dir = opendir(default_debugfs_path); 160 if (!sys_dir) 161 goto cleanup; 162 ··· 167 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, 168 evt_path, st) { 169 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", 170 - default_debugfs_path, sys_dirent.d_name, 171 evt_dirent.d_name); 172 fd = open(evt_path, O_RDONLY); 173 if (fd < 0) ··· 364 u64 id; 365 char evt_path[MAXPATHLEN]; 366 367 - if (valid_debugfs_mount()) 368 return 0; 369 370 evt_name = strchr(*strp, ':'); ··· 382 if (evt_length >= MAX_EVENT_LENGTH) 383 return 0; 384 385 - snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", default_debugfs_path, 386 - sys_name, evt_name); 387 fd = open(evt_path, O_RDONLY); 388 if (fd < 0) 389 return 0; ··· 569 struct stat st; 570 char evt_path[MAXPATHLEN]; 571 572 - if (valid_debugfs_mount()) 573 return; 574 575 - sys_dir = opendir(default_debugfs_path); 576 if (!sys_dir) 577 goto cleanup; 578
··· 5 #include "parse-events.h" 6 #include "exec_cmd.h" 7 #include "string.h" 8 + #include "cache.h" 9 10 extern char *strcasestr(const char *haystack, const char *needle); 11 ··· 12 13 struct perf_counter_attr attrs[MAX_COUNTERS]; 14 15 struct event_symbol { 16 u8 type; 17 u64 config; 18 char *symbol; 19 char *alias; 20 }; 21 + 22 + char debugfs_path[MAXPATHLEN]; 23 24 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 25 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x ··· 114 115 #define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ 116 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ 117 + if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \ 118 + sys_dirent.d_name) && \ 119 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ 120 (strcmp(sys_dirent.d_name, ".")) && \ 121 (strcmp(sys_dirent.d_name, ".."))) 122 123 #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ 124 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ 125 + if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ 126 + sys_dirent.d_name, evt_dirent.d_name) && \ 127 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ 128 (strcmp(evt_dirent.d_name, ".")) && \ 129 (strcmp(evt_dirent.d_name, ".."))) 130 131 #define MAX_EVENT_LENGTH 30 132 133 + int valid_debugfs_mount(const char *debugfs) 134 { 135 struct statfs st_fs; 136 137 + if (statfs(debugfs, &st_fs) < 0) 138 return -ENOENT; 139 else if (st_fs.f_type != (long) DEBUGFS_MAGIC) 140 return -ENOENT; ··· 152 u64 id; 153 char evt_path[MAXPATHLEN]; 154 155 + if (valid_debugfs_mount(debugfs_path)) 156 return "unkown"; 157 158 + sys_dir = opendir(debugfs_path); 159 if (!sys_dir) 160 goto cleanup; 161 ··· 166 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, 167 evt_path, st) { 168 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", 169 + debugfs_path, sys_dirent.d_name, 170 evt_dirent.d_name); 171 fd = open(evt_path, O_RDONLY); 172 if (fd < 0) ··· 363 u64 id; 364 char evt_path[MAXPATHLEN]; 365 366 + if (valid_debugfs_mount(debugfs_path)) 367 return 0; 368 369 evt_name = strchr(*strp, ':'); ··· 381 if (evt_length >= MAX_EVENT_LENGTH) 382 return 0; 383 384 + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, 385 + sys_name, evt_name); 386 fd = open(evt_path, O_RDONLY); 387 if (fd < 0) 388 return 0; ··· 568 struct stat st; 569 char evt_path[MAXPATHLEN]; 570 571 + if (valid_debugfs_mount(debugfs_path)) 572 return; 573 574 + sys_dir = opendir(debugfs_path); 575 if (!sys_dir) 576 goto cleanup; 577
+5
tools/perf/util/parse-events.h
··· 3 * Parse symbolic events/counts passed in as options: 4 */ 5 6 extern int nr_counters; 7 8 extern struct perf_counter_attr attrs[MAX_COUNTERS]; ··· 16 #define EVENTS_HELP_MAX (128*1024) 17 18 extern void print_events(void); 19
··· 3 * Parse symbolic events/counts passed in as options: 4 */ 5 6 + struct option; 7 + 8 extern int nr_counters; 9 10 extern struct perf_counter_attr attrs[MAX_COUNTERS]; ··· 14 #define EVENTS_HELP_MAX (128*1024) 15 16 extern void print_events(void); 17 + 18 + extern char debugfs_path[]; 19 + extern int valid_debugfs_mount(const char *debugfs); 20
+3
tools/perf/util/string.h
··· 5 6 int hex2u64(const char *ptr, u64 *val); 7 8 #endif
··· 5 6 int hex2u64(const char *ptr, u64 *val); 7 8 + #define _STR(x) #x 9 + #define STR(x) _STR(x) 10 + 11 #endif