perf_counter: Add tracepoint support to perf list, perf stat

Add support to 'perf list' and 'perf stat' for kernel tracepoints. The
implementation creates a 'for_each_subsystem' and 'for_each_event' for
easy iteration over the tracepoints.

Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <426129bf9fcc8ee63bb094cf736e7316a7dcd77a.1248190728.git.jbaron@redhat.com>

authored by Jason Baron and committed by Peter Zijlstra f6bdafef 28ac909b

+176 -1
+174 -1
tools/perf/util/parse-events.c
··· 12 12 13 13 struct perf_counter_attr attrs[MAX_COUNTERS]; 14 14 15 + static char default_debugfs_path[] = "/sys/kernel/debug/tracing/events"; 16 + 15 17 struct event_symbol { 16 18 u8 type; 17 19 u64 config; ··· 112 110 [C(BPU)] = (CACHE_READ), 113 111 }; 114 112 113 + #define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ 114 + while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ 115 + if (snprintf(file, MAXPATHLEN, "%s/%s", default_debugfs_path, \ 116 + sys_dirent.d_name) && \ 117 + (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ 118 + (strcmp(sys_dirent.d_name, ".")) && \ 119 + (strcmp(sys_dirent.d_name, ".."))) 120 + 121 + #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ 122 + while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ 123 + if (snprintf(file, MAXPATHLEN, "%s/%s/%s", default_debugfs_path, \ 124 + sys_dirent.d_name, evt_dirent.d_name) && \ 125 + (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ 126 + (strcmp(evt_dirent.d_name, ".")) && \ 127 + (strcmp(evt_dirent.d_name, ".."))) 128 + 129 + #define MAX_EVENT_LENGTH 30 130 + 131 + static int valid_debugfs_mount(void) 132 + { 133 + struct statfs st_fs; 134 + 135 + if (statfs(default_debugfs_path, &st_fs) < 0) 136 + return -ENOENT; 137 + else if (st_fs.f_type != (long) DEBUGFS_MAGIC) 138 + return -ENOENT; 139 + return 0; 140 + } 141 + 142 + static char *tracepoint_id_to_name(u64 config) 143 + { 144 + static char tracepoint_name[2 * MAX_EVENT_LENGTH]; 145 + DIR *sys_dir, *evt_dir; 146 + struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 147 + struct stat st; 148 + char id_buf[4]; 149 + int fd; 150 + u64 id; 151 + char evt_path[MAXPATHLEN]; 152 + 153 + if (valid_debugfs_mount()) 154 + return "unkown"; 155 + 156 + sys_dir = opendir(default_debugfs_path); 157 + if (!sys_dir) 158 + goto cleanup; 159 + 160 + for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { 161 + evt_dir = opendir(evt_path); 162 + if (!evt_dir) 163 + goto cleanup; 164 + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, 165 + evt_path, st) { 166 + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", 167 + default_debugfs_path, sys_dirent.d_name, 168 + evt_dirent.d_name); 169 + fd = open(evt_path, O_RDONLY); 170 + if (fd < 0) 171 + continue; 172 + if (read(fd, id_buf, sizeof(id_buf)) < 0) { 173 + close(fd); 174 + continue; 175 + } 176 + close(fd); 177 + id = atoll(id_buf); 178 + if (id == config) { 179 + closedir(evt_dir); 180 + closedir(sys_dir); 181 + snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH, 182 + "%s:%s", sys_dirent.d_name, 183 + evt_dirent.d_name); 184 + return tracepoint_name; 185 + } 186 + } 187 + closedir(evt_dir); 188 + } 189 + 190 + cleanup: 191 + closedir(sys_dir); 192 + return "unkown"; 193 + } 194 + 115 195 static int is_cache_op_valid(u8 cache_type, u8 cache_op) 116 196 { 117 197 if (hw_cache_stat[cache_type] & COP(cache_op)) ··· 260 176 if (config < PERF_COUNT_SW_MAX) 261 177 return sw_event_names[config]; 262 178 return "unknown-software"; 179 + 180 + case PERF_TYPE_TRACEPOINT: 181 + return tracepoint_id_to_name(config); 263 182 264 183 default: 265 184 break; ··· 349 262 attr->type = PERF_TYPE_HW_CACHE; 350 263 351 264 *str = s; 265 + return 1; 266 + } 267 + 268 + static int parse_tracepoint_event(const char **strp, 269 + struct perf_counter_attr *attr) 270 + { 271 + const char *evt_name; 272 + char sys_name[MAX_EVENT_LENGTH]; 273 + char id_buf[4]; 274 + int fd; 275 + unsigned int sys_length, evt_length; 276 + u64 id; 277 + char evt_path[MAXPATHLEN]; 278 + 279 + if (valid_debugfs_mount()) 280 + return 0; 281 + 282 + evt_name = strchr(*strp, ':'); 283 + if (!evt_name) 284 + return 0; 285 + 286 + sys_length = evt_name - *strp; 287 + if (sys_length >= MAX_EVENT_LENGTH) 288 + return 0; 289 + 290 + strncpy(sys_name, *strp, sys_length); 291 + sys_name[sys_length] = '\0'; 292 + evt_name = evt_name + 1; 293 + evt_length = strlen(evt_name); 294 + if (evt_length >= MAX_EVENT_LENGTH) 295 + return 0; 296 + 297 + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", default_debugfs_path, 298 + sys_name, evt_name); 299 + fd = open(evt_path, O_RDONLY); 300 + if (fd < 0) 301 + return 0; 302 + 303 + if (read(fd, id_buf, sizeof(id_buf)) < 0) { 304 + close(fd); 305 + return 0; 306 + } 307 + close(fd); 308 + id = atoll(id_buf); 309 + attr->config = id; 310 + attr->type = PERF_TYPE_TRACEPOINT; 311 + *strp = evt_name + evt_length; 352 312 return 1; 353 313 } 354 314 ··· 508 374 */ 509 375 static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) 510 376 { 511 - if (!(parse_raw_event(str, attr) || 377 + if (!(parse_tracepoint_event(str, attr) || 378 + parse_raw_event(str, attr) || 512 379 parse_numeric_event(str, attr) || 513 380 parse_symbolic_event(str, attr) || 514 381 parse_generic_hw_event(str, attr))) ··· 556 421 "Tracepoint event", 557 422 "Hardware cache event", 558 423 }; 424 + 425 + /* 426 + * Print the events from <debugfs_mount_point>/tracing/events 427 + */ 428 + 429 + static void print_tracepoint_events(void) 430 + { 431 + DIR *sys_dir, *evt_dir; 432 + struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 433 + struct stat st; 434 + char evt_path[MAXPATHLEN]; 435 + 436 + if (valid_debugfs_mount()) 437 + return; 438 + 439 + sys_dir = opendir(default_debugfs_path); 440 + if (!sys_dir) 441 + goto cleanup; 442 + 443 + for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { 444 + evt_dir = opendir(evt_path); 445 + if (!evt_dir) 446 + goto cleanup; 447 + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, 448 + evt_path, st) { 449 + snprintf(evt_path, MAXPATHLEN, "%s:%s", 450 + sys_dirent.d_name, evt_dirent.d_name); 451 + fprintf(stderr, " %-40s [%s]\n", evt_path, 452 + event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 453 + } 454 + closedir(evt_dir); 455 + } 456 + 457 + cleanup: 458 + closedir(sys_dir); 459 + } 559 460 560 461 /* 561 462 * Print the help text for the event symbols: ··· 642 471 fprintf(stderr, " %-40s [raw hardware event descriptor]\n", 643 472 "rNNN"); 644 473 fprintf(stderr, "\n"); 474 + 475 + print_tracepoint_events(); 645 476 646 477 exit(129); 647 478 }
+2
tools/perf/util/util.h
··· 50 50 #include <unistd.h> 51 51 #include <stdio.h> 52 52 #include <sys/stat.h> 53 + #include <sys/statfs.h> 53 54 #include <fcntl.h> 54 55 #include <stddef.h> 55 56 #include <stdlib.h> ··· 81 80 #include <netdb.h> 82 81 #include <pwd.h> 83 82 #include <inttypes.h> 83 + #include "../../../include/linux/magic.h" 84 84 85 85 #ifndef NO_ICONV 86 86 #include <iconv.h>