aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/parse-events.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r--tools/perf/util/parse-events.c206
1 files changed, 201 insertions, 5 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5184959e0615..4858d83b3b67 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -5,6 +5,7 @@
5#include "parse-events.h" 5#include "parse-events.h"
6#include "exec_cmd.h" 6#include "exec_cmd.h"
7#include "string.h" 7#include "string.h"
8#include "cache.h"
8 9
9extern char *strcasestr(const char *haystack, const char *needle); 10extern char *strcasestr(const char *haystack, const char *needle);
10 11
@@ -19,6 +20,8 @@ struct event_symbol {
19 char *alias; 20 char *alias;
20}; 21};
21 22
23char debugfs_path[MAXPATHLEN];
24
22#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 25#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
23#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 26#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
24 27
@@ -71,8 +74,8 @@ static char *sw_event_names[] = {
71#define MAX_ALIASES 8 74#define MAX_ALIASES 8
72 75
73static char *hw_cache[][MAX_ALIASES] = { 76static char *hw_cache[][MAX_ALIASES] = {
74 { "L1-d$", "l1-d", "l1d", "L1-data", }, 77 { "L1-dcache", "l1-d", "l1d", "L1-data", },
75 { "L1-i$", "l1-i", "l1i", "L1-instruction", }, 78 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
76 { "LLC", "L2" }, 79 { "LLC", "L2" },
77 { "dTLB", "d-tlb", "Data-TLB", }, 80 { "dTLB", "d-tlb", "Data-TLB", },
78 { "iTLB", "i-tlb", "Instruction-TLB", }, 81 { "iTLB", "i-tlb", "Instruction-TLB", },
@@ -110,6 +113,104 @@ static unsigned long hw_cache_stat[C(MAX)] = {
110 [C(BPU)] = (CACHE_READ), 113 [C(BPU)] = (CACHE_READ),
111}; 114};
112 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", 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
124static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
125{
126 char evt_path[MAXPATHLEN];
127 int fd;
128
129 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
130 sys_dir->d_name, evt_dir->d_name);
131 fd = open(evt_path, O_RDONLY);
132 if (fd < 0)
133 return -EINVAL;
134 close(fd);
135
136 return 0;
137}
138
139#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \
140 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
141 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \
142 sys_dirent.d_name, evt_dirent.d_name) && \
143 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
144 (strcmp(evt_dirent.d_name, ".")) && \
145 (strcmp(evt_dirent.d_name, "..")) && \
146 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
147
148#define MAX_EVENT_LENGTH 30
149
150int valid_debugfs_mount(const char *debugfs)
151{
152 struct statfs st_fs;
153
154 if (statfs(debugfs, &st_fs) < 0)
155 return -ENOENT;
156 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
157 return -ENOENT;
158 return 0;
159}
160
161static char *tracepoint_id_to_name(u64 config)
162{
163 static char tracepoint_name[2 * MAX_EVENT_LENGTH];
164 DIR *sys_dir, *evt_dir;
165 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
166 struct stat st;
167 char id_buf[4];
168 int fd;
169 u64 id;
170 char evt_path[MAXPATHLEN];
171
172 if (valid_debugfs_mount(debugfs_path))
173 return "unkown";
174
175 sys_dir = opendir(debugfs_path);
176 if (!sys_dir)
177 goto cleanup;
178
179 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
180 evt_dir = opendir(evt_path);
181 if (!evt_dir)
182 goto cleanup;
183 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
184 evt_path, st) {
185 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
186 debugfs_path, sys_dirent.d_name,
187 evt_dirent.d_name);
188 fd = open(evt_path, O_RDONLY);
189 if (fd < 0)
190 continue;
191 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
192 close(fd);
193 continue;
194 }
195 close(fd);
196 id = atoll(id_buf);
197 if (id == config) {
198 closedir(evt_dir);
199 closedir(sys_dir);
200 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
201 "%s:%s", sys_dirent.d_name,
202 evt_dirent.d_name);
203 return tracepoint_name;
204 }
205 }
206 closedir(evt_dir);
207 }
208
209cleanup:
210 closedir(sys_dir);
211 return "unkown";
212}
213
113static int is_cache_op_valid(u8 cache_type, u8 cache_op) 214static int is_cache_op_valid(u8 cache_type, u8 cache_op)
114{ 215{
115 if (hw_cache_stat[cache_type] & COP(cache_op)) 216 if (hw_cache_stat[cache_type] & COP(cache_op))
@@ -138,9 +239,15 @@ char *event_name(int counter)
138{ 239{
139 u64 config = attrs[counter].config; 240 u64 config = attrs[counter].config;
140 int type = attrs[counter].type; 241 int type = attrs[counter].type;
242
243 return __event_name(type, config);
244}
245
246char *__event_name(int type, u64 config)
247{
141 static char buf[32]; 248 static char buf[32];
142 249
143 if (attrs[counter].type == PERF_TYPE_RAW) { 250 if (type == PERF_TYPE_RAW) {
144 sprintf(buf, "raw 0x%llx", config); 251 sprintf(buf, "raw 0x%llx", config);
145 return buf; 252 return buf;
146 } 253 }
@@ -177,6 +284,9 @@ char *event_name(int counter)
177 return sw_event_names[config]; 284 return sw_event_names[config];
178 return "unknown-software"; 285 return "unknown-software";
179 286
287 case PERF_TYPE_TRACEPOINT:
288 return tracepoint_id_to_name(config);
289
180 default: 290 default:
181 break; 291 break;
182 } 292 }
@@ -265,6 +375,53 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
265 return 1; 375 return 1;
266} 376}
267 377
378static int parse_tracepoint_event(const char **strp,
379 struct perf_counter_attr *attr)
380{
381 const char *evt_name;
382 char sys_name[MAX_EVENT_LENGTH];
383 char id_buf[4];
384 int fd;
385 unsigned int sys_length, evt_length;
386 u64 id;
387 char evt_path[MAXPATHLEN];
388
389 if (valid_debugfs_mount(debugfs_path))
390 return 0;
391
392 evt_name = strchr(*strp, ':');
393 if (!evt_name)
394 return 0;
395
396 sys_length = evt_name - *strp;
397 if (sys_length >= MAX_EVENT_LENGTH)
398 return 0;
399
400 strncpy(sys_name, *strp, sys_length);
401 sys_name[sys_length] = '\0';
402 evt_name = evt_name + 1;
403 evt_length = strlen(evt_name);
404 if (evt_length >= MAX_EVENT_LENGTH)
405 return 0;
406
407 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
408 sys_name, evt_name);
409 fd = open(evt_path, O_RDONLY);
410 if (fd < 0)
411 return 0;
412
413 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
414 close(fd);
415 return 0;
416 }
417 close(fd);
418 id = atoll(id_buf);
419 attr->config = id;
420 attr->type = PERF_TYPE_TRACEPOINT;
421 *strp = evt_name + evt_length;
422 return 1;
423}
424
268static int check_events(const char *str, unsigned int i) 425static int check_events(const char *str, unsigned int i)
269{ 426{
270 int n; 427 int n;
@@ -374,7 +531,8 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
374 */ 531 */
375static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) 532static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
376{ 533{
377 if (!(parse_raw_event(str, attr) || 534 if (!(parse_tracepoint_event(str, attr) ||
535 parse_raw_event(str, attr) ||
378 parse_numeric_event(str, attr) || 536 parse_numeric_event(str, attr) ||
379 parse_symbolic_event(str, attr) || 537 parse_symbolic_event(str, attr) ||
380 parse_generic_hw_event(str, attr))) 538 parse_generic_hw_event(str, attr)))
@@ -423,6 +581,42 @@ static const char * const event_type_descriptors[] = {
423}; 581};
424 582
425/* 583/*
584 * Print the events from <debugfs_mount_point>/tracing/events
585 */
586
587static void print_tracepoint_events(void)
588{
589 DIR *sys_dir, *evt_dir;
590 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
591 struct stat st;
592 char evt_path[MAXPATHLEN];
593
594 if (valid_debugfs_mount(debugfs_path))
595 return;
596
597 sys_dir = opendir(debugfs_path);
598 if (!sys_dir)
599 goto cleanup;
600
601 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
602 evt_dir = opendir(evt_path);
603 if (!evt_dir)
604 goto cleanup;
605 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
606 evt_path, st) {
607 snprintf(evt_path, MAXPATHLEN, "%s:%s",
608 sys_dirent.d_name, evt_dirent.d_name);
609 fprintf(stderr, " %-40s [%s]\n", evt_path,
610 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
611 }
612 closedir(evt_dir);
613 }
614
615cleanup:
616 closedir(sys_dir);
617}
618
619/*
426 * Print the help text for the event symbols: 620 * Print the help text for the event symbols:
427 */ 621 */
428void print_events(void) 622void print_events(void)
@@ -436,7 +630,7 @@ void print_events(void)
436 630
437 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 631 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
438 type = syms->type + 1; 632 type = syms->type + 1;
439 if (type > ARRAY_SIZE(event_type_descriptors)) 633 if (type >= ARRAY_SIZE(event_type_descriptors))
440 type = 0; 634 type = 0;
441 635
442 if (type != prev_type) 636 if (type != prev_type)
@@ -472,5 +666,7 @@ void print_events(void)
472 "rNNN"); 666 "rNNN");
473 fprintf(stderr, "\n"); 667 fprintf(stderr, "\n");
474 668
669 print_tracepoint_events();
670
475 exit(129); 671 exit(129);
476} 672}