diff options
| -rw-r--r-- | tools/perf/util/parse-events.c | 175 | ||||
| -rw-r--r-- | tools/perf/util/util.h | 2 |
2 files changed, 176 insertions, 1 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d18c98edd00d..5a3cd3a34af1 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -12,6 +12,8 @@ int nr_counters; | |||
| 12 | 12 | ||
| 13 | struct perf_counter_attr attrs[MAX_COUNTERS]; | 13 | struct perf_counter_attr attrs[MAX_COUNTERS]; |
| 14 | 14 | ||
| 15 | static char default_debugfs_path[] = "/sys/kernel/debug/tracing/events"; | ||
| 16 | |||
| 15 | struct event_symbol { | 17 | struct event_symbol { |
| 16 | u8 type; | 18 | u8 type; |
| 17 | u64 config; | 19 | u64 config; |
| @@ -110,6 +112,88 @@ static unsigned long hw_cache_stat[C(MAX)] = { | |||
| 110 | [C(BPU)] = (CACHE_READ), | 112 | [C(BPU)] = (CACHE_READ), |
| 111 | }; | 113 | }; |
| 112 | 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", default_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", default_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 | static int valid_debugfs_mount(void) | ||
| 134 | { | ||
| 135 | struct statfs st_fs; | ||
| 136 | |||
| 137 | if (statfs(default_debugfs_path, &st_fs) < 0) | ||
| 138 | return -ENOENT; | ||
| 139 | else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | ||
| 140 | return -ENOENT; | ||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | static char *tracepoint_id_to_name(u64 config) | ||
| 145 | { | ||
| 146 | static char tracepoint_name[2 * MAX_EVENT_LENGTH]; | ||
| 147 | DIR *sys_dir, *evt_dir; | ||
| 148 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | ||
| 149 | struct stat st; | ||
| 150 | char id_buf[4]; | ||
| 151 | int fd; | ||
| 152 | u64 id; | ||
| 153 | char evt_path[MAXPATHLEN]; | ||
| 154 | |||
| 155 | if (valid_debugfs_mount()) | ||
| 156 | return "unkown"; | ||
| 157 | |||
| 158 | sys_dir = opendir(default_debugfs_path); | ||
| 159 | if (!sys_dir) | ||
| 160 | goto cleanup; | ||
| 161 | |||
| 162 | for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { | ||
| 163 | evt_dir = opendir(evt_path); | ||
| 164 | if (!evt_dir) | ||
| 165 | goto cleanup; | ||
| 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 | default_debugfs_path, sys_dirent.d_name, | ||
| 170 | evt_dirent.d_name); | ||
| 171 | fd = open(evt_path, O_RDONLY); | ||
| 172 | if (fd < 0) | ||
| 173 | continue; | ||
| 174 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
| 175 | close(fd); | ||
| 176 | continue; | ||
| 177 | } | ||
| 178 | close(fd); | ||
| 179 | id = atoll(id_buf); | ||
| 180 | if (id == config) { | ||
| 181 | closedir(evt_dir); | ||
| 182 | closedir(sys_dir); | ||
| 183 | snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH, | ||
| 184 | "%s:%s", sys_dirent.d_name, | ||
| 185 | evt_dirent.d_name); | ||
| 186 | return tracepoint_name; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | closedir(evt_dir); | ||
| 190 | } | ||
| 191 | |||
| 192 | cleanup: | ||
| 193 | closedir(sys_dir); | ||
| 194 | return "unkown"; | ||
| 195 | } | ||
| 196 | |||
| 113 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) | 197 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) |
| 114 | { | 198 | { |
| 115 | if (hw_cache_stat[cache_type] & COP(cache_op)) | 199 | if (hw_cache_stat[cache_type] & COP(cache_op)) |
| @@ -177,6 +261,9 @@ char *event_name(int counter) | |||
| 177 | return sw_event_names[config]; | 261 | return sw_event_names[config]; |
| 178 | return "unknown-software"; | 262 | return "unknown-software"; |
| 179 | 263 | ||
| 264 | case PERF_TYPE_TRACEPOINT: | ||
| 265 | return tracepoint_id_to_name(config); | ||
| 266 | |||
| 180 | default: | 267 | default: |
| 181 | break; | 268 | break; |
| 182 | } | 269 | } |
| @@ -265,6 +352,53 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | |||
| 265 | return 1; | 352 | return 1; |
| 266 | } | 353 | } |
| 267 | 354 | ||
| 355 | static int parse_tracepoint_event(const char **strp, | ||
| 356 | struct perf_counter_attr *attr) | ||
| 357 | { | ||
| 358 | const char *evt_name; | ||
| 359 | char sys_name[MAX_EVENT_LENGTH]; | ||
| 360 | char id_buf[4]; | ||
| 361 | int fd; | ||
| 362 | unsigned int sys_length, evt_length; | ||
| 363 | u64 id; | ||
| 364 | char evt_path[MAXPATHLEN]; | ||
| 365 | |||
| 366 | if (valid_debugfs_mount()) | ||
| 367 | return 0; | ||
| 368 | |||
| 369 | evt_name = strchr(*strp, ':'); | ||
| 370 | if (!evt_name) | ||
| 371 | return 0; | ||
| 372 | |||
| 373 | sys_length = evt_name - *strp; | ||
| 374 | if (sys_length >= MAX_EVENT_LENGTH) | ||
| 375 | return 0; | ||
| 376 | |||
| 377 | strncpy(sys_name, *strp, sys_length); | ||
| 378 | sys_name[sys_length] = '\0'; | ||
| 379 | evt_name = evt_name + 1; | ||
| 380 | evt_length = strlen(evt_name); | ||
| 381 | if (evt_length >= MAX_EVENT_LENGTH) | ||
| 382 | return 0; | ||
| 383 | |||
| 384 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", default_debugfs_path, | ||
| 385 | sys_name, evt_name); | ||
| 386 | fd = open(evt_path, O_RDONLY); | ||
| 387 | if (fd < 0) | ||
| 388 | return 0; | ||
| 389 | |||
| 390 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
| 391 | close(fd); | ||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | close(fd); | ||
| 395 | id = atoll(id_buf); | ||
| 396 | attr->config = id; | ||
| 397 | attr->type = PERF_TYPE_TRACEPOINT; | ||
| 398 | *strp = evt_name + evt_length; | ||
| 399 | return 1; | ||
| 400 | } | ||
| 401 | |||
| 268 | static int check_events(const char *str, unsigned int i) | 402 | static int check_events(const char *str, unsigned int i) |
| 269 | { | 403 | { |
| 270 | int n; | 404 | int n; |
| @@ -374,7 +508,8 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | |||
| 374 | */ | 508 | */ |
| 375 | static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) | 509 | static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) |
| 376 | { | 510 | { |
| 377 | if (!(parse_raw_event(str, attr) || | 511 | if (!(parse_tracepoint_event(str, attr) || |
| 512 | parse_raw_event(str, attr) || | ||
| 378 | parse_numeric_event(str, attr) || | 513 | parse_numeric_event(str, attr) || |
| 379 | parse_symbolic_event(str, attr) || | 514 | parse_symbolic_event(str, attr) || |
| 380 | parse_generic_hw_event(str, attr))) | 515 | parse_generic_hw_event(str, attr))) |
| @@ -423,6 +558,42 @@ static const char * const event_type_descriptors[] = { | |||
| 423 | }; | 558 | }; |
| 424 | 559 | ||
| 425 | /* | 560 | /* |
| 561 | * Print the events from <debugfs_mount_point>/tracing/events | ||
| 562 | */ | ||
| 563 | |||
| 564 | static void print_tracepoint_events(void) | ||
| 565 | { | ||
| 566 | DIR *sys_dir, *evt_dir; | ||
| 567 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | ||
| 568 | struct stat st; | ||
| 569 | char evt_path[MAXPATHLEN]; | ||
| 570 | |||
| 571 | if (valid_debugfs_mount()) | ||
| 572 | return; | ||
| 573 | |||
| 574 | sys_dir = opendir(default_debugfs_path); | ||
| 575 | if (!sys_dir) | ||
| 576 | goto cleanup; | ||
| 577 | |||
| 578 | for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { | ||
| 579 | evt_dir = opendir(evt_path); | ||
| 580 | if (!evt_dir) | ||
| 581 | goto cleanup; | ||
| 582 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, | ||
| 583 | evt_path, st) { | ||
| 584 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | ||
| 585 | sys_dirent.d_name, evt_dirent.d_name); | ||
| 586 | fprintf(stderr, " %-40s [%s]\n", evt_path, | ||
| 587 | event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); | ||
| 588 | } | ||
| 589 | closedir(evt_dir); | ||
| 590 | } | ||
| 591 | |||
| 592 | cleanup: | ||
| 593 | closedir(sys_dir); | ||
| 594 | } | ||
| 595 | |||
| 596 | /* | ||
| 426 | * Print the help text for the event symbols: | 597 | * Print the help text for the event symbols: |
| 427 | */ | 598 | */ |
| 428 | void print_events(void) | 599 | void print_events(void) |
| @@ -472,5 +643,7 @@ void print_events(void) | |||
| 472 | "rNNN"); | 643 | "rNNN"); |
| 473 | fprintf(stderr, "\n"); | 644 | fprintf(stderr, "\n"); |
| 474 | 645 | ||
| 646 | print_tracepoint_events(); | ||
| 647 | |||
| 475 | exit(129); | 648 | exit(129); |
| 476 | } | 649 | } |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index b4be6071c105..68fe157d72fb 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <unistd.h> | 50 | #include <unistd.h> |
| 51 | #include <stdio.h> | 51 | #include <stdio.h> |
| 52 | #include <sys/stat.h> | 52 | #include <sys/stat.h> |
| 53 | #include <sys/statfs.h> | ||
| 53 | #include <fcntl.h> | 54 | #include <fcntl.h> |
| 54 | #include <stddef.h> | 55 | #include <stddef.h> |
| 55 | #include <stdlib.h> | 56 | #include <stdlib.h> |
| @@ -80,6 +81,7 @@ | |||
| 80 | #include <netdb.h> | 81 | #include <netdb.h> |
| 81 | #include <pwd.h> | 82 | #include <pwd.h> |
| 82 | #include <inttypes.h> | 83 | #include <inttypes.h> |
| 84 | #include "../../../include/linux/magic.h" | ||
| 83 | 85 | ||
| 84 | #ifndef NO_ICONV | 86 | #ifndef NO_ICONV |
| 85 | #include <iconv.h> | 87 | #include <iconv.h> |
