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