diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 404 |
1 files changed, 284 insertions, 120 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 044178408783..8cfb48cbbea0 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -1,23 +1,28 @@ | |||
1 | 1 | ||
2 | #include "../perf.h" | ||
3 | #include "util.h" | 2 | #include "util.h" |
3 | #include "../perf.h" | ||
4 | #include "parse-options.h" | 4 | #include "parse-options.h" |
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 | #include "cache.h" |
9 | 9 | #include "header.h" | |
10 | extern char *strcasestr(const char *haystack, const char *needle); | ||
11 | 10 | ||
12 | int nr_counters; | 11 | int nr_counters; |
13 | 12 | ||
14 | struct perf_counter_attr attrs[MAX_COUNTERS]; | 13 | struct perf_event_attr attrs[MAX_COUNTERS]; |
15 | 14 | ||
16 | struct event_symbol { | 15 | struct event_symbol { |
17 | u8 type; | 16 | u8 type; |
18 | u64 config; | 17 | u64 config; |
19 | char *symbol; | 18 | const char *symbol; |
20 | char *alias; | 19 | const char *alias; |
20 | }; | ||
21 | |||
22 | enum event_result { | ||
23 | EVT_FAILED, | ||
24 | EVT_HANDLED, | ||
25 | EVT_HANDLED_ALL | ||
21 | }; | 26 | }; |
22 | 27 | ||
23 | char debugfs_path[MAXPATHLEN]; | 28 | char debugfs_path[MAXPATHLEN]; |
@@ -43,15 +48,15 @@ static struct event_symbol event_symbols[] = { | |||
43 | { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, | 48 | { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, |
44 | }; | 49 | }; |
45 | 50 | ||
46 | #define __PERF_COUNTER_FIELD(config, name) \ | 51 | #define __PERF_EVENT_FIELD(config, name) \ |
47 | ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT) | 52 | ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) |
48 | 53 | ||
49 | #define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW) | 54 | #define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) |
50 | #define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG) | 55 | #define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) |
51 | #define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) | 56 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) |
52 | #define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) | 57 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) |
53 | 58 | ||
54 | static char *hw_event_names[] = { | 59 | static const char *hw_event_names[] = { |
55 | "cycles", | 60 | "cycles", |
56 | "instructions", | 61 | "instructions", |
57 | "cache-references", | 62 | "cache-references", |
@@ -61,7 +66,7 @@ static char *hw_event_names[] = { | |||
61 | "bus-cycles", | 66 | "bus-cycles", |
62 | }; | 67 | }; |
63 | 68 | ||
64 | static char *sw_event_names[] = { | 69 | static const char *sw_event_names[] = { |
65 | "cpu-clock-msecs", | 70 | "cpu-clock-msecs", |
66 | "task-clock-msecs", | 71 | "task-clock-msecs", |
67 | "page-faults", | 72 | "page-faults", |
@@ -73,7 +78,7 @@ static char *sw_event_names[] = { | |||
73 | 78 | ||
74 | #define MAX_ALIASES 8 | 79 | #define MAX_ALIASES 8 |
75 | 80 | ||
76 | static char *hw_cache[][MAX_ALIASES] = { | 81 | static const char *hw_cache[][MAX_ALIASES] = { |
77 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, | 82 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, |
78 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, | 83 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, |
79 | { "LLC", "L2" }, | 84 | { "LLC", "L2" }, |
@@ -82,13 +87,13 @@ static char *hw_cache[][MAX_ALIASES] = { | |||
82 | { "branch", "branches", "bpu", "btb", "bpc", }, | 87 | { "branch", "branches", "bpu", "btb", "bpc", }, |
83 | }; | 88 | }; |
84 | 89 | ||
85 | static char *hw_cache_op[][MAX_ALIASES] = { | 90 | static const char *hw_cache_op[][MAX_ALIASES] = { |
86 | { "load", "loads", "read", }, | 91 | { "load", "loads", "read", }, |
87 | { "store", "stores", "write", }, | 92 | { "store", "stores", "write", }, |
88 | { "prefetch", "prefetches", "speculative-read", "speculative-load", }, | 93 | { "prefetch", "prefetches", "speculative-read", "speculative-load", }, |
89 | }; | 94 | }; |
90 | 95 | ||
91 | static char *hw_cache_result[][MAX_ALIASES] = { | 96 | static const char *hw_cache_result[][MAX_ALIASES] = { |
92 | { "refs", "Reference", "ops", "access", }, | 97 | { "refs", "Reference", "ops", "access", }, |
93 | { "misses", "miss", }, | 98 | { "misses", "miss", }, |
94 | }; | 99 | }; |
@@ -113,11 +118,9 @@ static unsigned long hw_cache_stat[C(MAX)] = { | |||
113 | [C(BPU)] = (CACHE_READ), | 118 | [C(BPU)] = (CACHE_READ), |
114 | }; | 119 | }; |
115 | 120 | ||
116 | #define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ | 121 | #define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ |
117 | while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ | 122 | while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ |
118 | if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \ | 123 | if (sys_dirent.d_type == DT_DIR && \ |
119 | sys_dirent.d_name) && \ | ||
120 | (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ | ||
121 | (strcmp(sys_dirent.d_name, ".")) && \ | 124 | (strcmp(sys_dirent.d_name, ".")) && \ |
122 | (strcmp(sys_dirent.d_name, ".."))) | 125 | (strcmp(sys_dirent.d_name, ".."))) |
123 | 126 | ||
@@ -136,16 +139,14 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) | |||
136 | return 0; | 139 | return 0; |
137 | } | 140 | } |
138 | 141 | ||
139 | #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ | 142 | #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \ |
140 | while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ | 143 | while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ |
141 | if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ | 144 | if (evt_dirent.d_type == DT_DIR && \ |
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, ".")) && \ |
145 | (strcmp(evt_dirent.d_name, "..")) && \ | 146 | (strcmp(evt_dirent.d_name, "..")) && \ |
146 | (!tp_event_has_id(&sys_dirent, &evt_dirent))) | 147 | (!tp_event_has_id(&sys_dirent, &evt_dirent))) |
147 | 148 | ||
148 | #define MAX_EVENT_LENGTH 30 | 149 | #define MAX_EVENT_LENGTH 512 |
149 | 150 | ||
150 | int valid_debugfs_mount(const char *debugfs) | 151 | int valid_debugfs_mount(const char *debugfs) |
151 | { | 152 | { |
@@ -158,32 +159,35 @@ int valid_debugfs_mount(const char *debugfs) | |||
158 | return 0; | 159 | return 0; |
159 | } | 160 | } |
160 | 161 | ||
161 | static char *tracepoint_id_to_name(u64 config) | 162 | struct tracepoint_path *tracepoint_id_to_path(u64 config) |
162 | { | 163 | { |
163 | static char tracepoint_name[2 * MAX_EVENT_LENGTH]; | 164 | struct tracepoint_path *path = NULL; |
164 | DIR *sys_dir, *evt_dir; | 165 | DIR *sys_dir, *evt_dir; |
165 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 166 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; |
166 | struct stat st; | ||
167 | char id_buf[4]; | 167 | char id_buf[4]; |
168 | int fd; | 168 | int fd; |
169 | u64 id; | 169 | u64 id; |
170 | char evt_path[MAXPATHLEN]; | 170 | char evt_path[MAXPATHLEN]; |
171 | char dir_path[MAXPATHLEN]; | ||
171 | 172 | ||
172 | if (valid_debugfs_mount(debugfs_path)) | 173 | if (valid_debugfs_mount(debugfs_path)) |
173 | return "unkown"; | 174 | return NULL; |
174 | 175 | ||
175 | sys_dir = opendir(debugfs_path); | 176 | sys_dir = opendir(debugfs_path); |
176 | if (!sys_dir) | 177 | if (!sys_dir) |
177 | goto cleanup; | 178 | return NULL; |
179 | |||
180 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | ||
178 | 181 | ||
179 | for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { | 182 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, |
180 | evt_dir = opendir(evt_path); | 183 | sys_dirent.d_name); |
184 | evt_dir = opendir(dir_path); | ||
181 | if (!evt_dir) | 185 | if (!evt_dir) |
182 | goto cleanup; | 186 | continue; |
183 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, | 187 | |
184 | evt_path, st) { | 188 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { |
185 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", | 189 | |
186 | debugfs_path, sys_dirent.d_name, | 190 | snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, |
187 | evt_dirent.d_name); | 191 | evt_dirent.d_name); |
188 | fd = open(evt_path, O_RDONLY); | 192 | fd = open(evt_path, O_RDONLY); |
189 | if (fd < 0) | 193 | if (fd < 0) |
@@ -197,18 +201,48 @@ static char *tracepoint_id_to_name(u64 config) | |||
197 | if (id == config) { | 201 | if (id == config) { |
198 | closedir(evt_dir); | 202 | closedir(evt_dir); |
199 | closedir(sys_dir); | 203 | closedir(sys_dir); |
200 | snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH, | 204 | path = calloc(1, sizeof(path)); |
201 | "%s:%s", sys_dirent.d_name, | 205 | path->system = malloc(MAX_EVENT_LENGTH); |
202 | evt_dirent.d_name); | 206 | if (!path->system) { |
203 | return tracepoint_name; | 207 | free(path); |
208 | return NULL; | ||
209 | } | ||
210 | path->name = malloc(MAX_EVENT_LENGTH); | ||
211 | if (!path->name) { | ||
212 | free(path->system); | ||
213 | free(path); | ||
214 | return NULL; | ||
215 | } | ||
216 | strncpy(path->system, sys_dirent.d_name, | ||
217 | MAX_EVENT_LENGTH); | ||
218 | strncpy(path->name, evt_dirent.d_name, | ||
219 | MAX_EVENT_LENGTH); | ||
220 | return path; | ||
204 | } | 221 | } |
205 | } | 222 | } |
206 | closedir(evt_dir); | 223 | closedir(evt_dir); |
207 | } | 224 | } |
208 | 225 | ||
209 | cleanup: | ||
210 | closedir(sys_dir); | 226 | closedir(sys_dir); |
211 | return "unkown"; | 227 | return NULL; |
228 | } | ||
229 | |||
230 | #define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1) | ||
231 | static const char *tracepoint_id_to_name(u64 config) | ||
232 | { | ||
233 | static char buf[TP_PATH_LEN]; | ||
234 | struct tracepoint_path *path; | ||
235 | |||
236 | path = tracepoint_id_to_path(config); | ||
237 | if (path) { | ||
238 | snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name); | ||
239 | free(path->name); | ||
240 | free(path->system); | ||
241 | free(path); | ||
242 | } else | ||
243 | snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown"); | ||
244 | |||
245 | return buf; | ||
212 | } | 246 | } |
213 | 247 | ||
214 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) | 248 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) |
@@ -235,7 +269,7 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) | |||
235 | return name; | 269 | return name; |
236 | } | 270 | } |
237 | 271 | ||
238 | char *event_name(int counter) | 272 | const char *event_name(int counter) |
239 | { | 273 | { |
240 | u64 config = attrs[counter].config; | 274 | u64 config = attrs[counter].config; |
241 | int type = attrs[counter].type; | 275 | int type = attrs[counter].type; |
@@ -243,7 +277,7 @@ char *event_name(int counter) | |||
243 | return __event_name(type, config); | 277 | return __event_name(type, config); |
244 | } | 278 | } |
245 | 279 | ||
246 | char *__event_name(int type, u64 config) | 280 | const char *__event_name(int type, u64 config) |
247 | { | 281 | { |
248 | static char buf[32]; | 282 | static char buf[32]; |
249 | 283 | ||
@@ -294,7 +328,7 @@ char *__event_name(int type, u64 config) | |||
294 | return "unknown"; | 328 | return "unknown"; |
295 | } | 329 | } |
296 | 330 | ||
297 | static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size) | 331 | static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size) |
298 | { | 332 | { |
299 | int i, j; | 333 | int i, j; |
300 | int n, longest = -1; | 334 | int n, longest = -1; |
@@ -314,8 +348,8 @@ static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size) | |||
314 | return -1; | 348 | return -1; |
315 | } | 349 | } |
316 | 350 | ||
317 | static int | 351 | static enum event_result |
318 | parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | 352 | parse_generic_hw_event(const char **str, struct perf_event_attr *attr) |
319 | { | 353 | { |
320 | const char *s = *str; | 354 | const char *s = *str; |
321 | int cache_type = -1, cache_op = -1, cache_result = -1; | 355 | int cache_type = -1, cache_op = -1, cache_result = -1; |
@@ -326,7 +360,7 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | |||
326 | * then bail out: | 360 | * then bail out: |
327 | */ | 361 | */ |
328 | if (cache_type == -1) | 362 | if (cache_type == -1) |
329 | return 0; | 363 | return EVT_FAILED; |
330 | 364 | ||
331 | while ((cache_op == -1 || cache_result == -1) && *s == '-') { | 365 | while ((cache_op == -1 || cache_result == -1) && *s == '-') { |
332 | ++s; | 366 | ++s; |
@@ -372,27 +406,115 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | |||
372 | attr->type = PERF_TYPE_HW_CACHE; | 406 | attr->type = PERF_TYPE_HW_CACHE; |
373 | 407 | ||
374 | *str = s; | 408 | *str = s; |
375 | return 1; | 409 | return EVT_HANDLED; |
410 | } | ||
411 | |||
412 | static enum event_result | ||
413 | parse_single_tracepoint_event(char *sys_name, | ||
414 | const char *evt_name, | ||
415 | unsigned int evt_length, | ||
416 | char *flags, | ||
417 | struct perf_event_attr *attr, | ||
418 | const char **strp) | ||
419 | { | ||
420 | char evt_path[MAXPATHLEN]; | ||
421 | char id_buf[4]; | ||
422 | u64 id; | ||
423 | int fd; | ||
424 | |||
425 | if (flags) { | ||
426 | if (!strncmp(flags, "record", strlen(flags))) { | ||
427 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
428 | attr->sample_type |= PERF_SAMPLE_TIME; | ||
429 | attr->sample_type |= PERF_SAMPLE_CPU; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | ||
434 | sys_name, evt_name); | ||
435 | |||
436 | fd = open(evt_path, O_RDONLY); | ||
437 | if (fd < 0) | ||
438 | return EVT_FAILED; | ||
439 | |||
440 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
441 | close(fd); | ||
442 | return EVT_FAILED; | ||
443 | } | ||
444 | |||
445 | close(fd); | ||
446 | id = atoll(id_buf); | ||
447 | attr->config = id; | ||
448 | attr->type = PERF_TYPE_TRACEPOINT; | ||
449 | *strp = evt_name + evt_length; | ||
450 | |||
451 | return EVT_HANDLED; | ||
376 | } | 452 | } |
377 | 453 | ||
378 | static int parse_tracepoint_event(const char **strp, | 454 | /* sys + ':' + event + ':' + flags*/ |
379 | struct perf_counter_attr *attr) | 455 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) |
456 | static enum event_result | ||
457 | parse_subsystem_tracepoint_event(char *sys_name, char *flags) | ||
458 | { | ||
459 | char evt_path[MAXPATHLEN]; | ||
460 | struct dirent *evt_ent; | ||
461 | DIR *evt_dir; | ||
462 | |||
463 | snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name); | ||
464 | evt_dir = opendir(evt_path); | ||
465 | |||
466 | if (!evt_dir) { | ||
467 | perror("Can't open event dir"); | ||
468 | return EVT_FAILED; | ||
469 | } | ||
470 | |||
471 | while ((evt_ent = readdir(evt_dir))) { | ||
472 | char event_opt[MAX_EVOPT_LEN + 1]; | ||
473 | int len; | ||
474 | unsigned int rem = MAX_EVOPT_LEN; | ||
475 | |||
476 | if (!strcmp(evt_ent->d_name, ".") | ||
477 | || !strcmp(evt_ent->d_name, "..") | ||
478 | || !strcmp(evt_ent->d_name, "enable") | ||
479 | || !strcmp(evt_ent->d_name, "filter")) | ||
480 | continue; | ||
481 | |||
482 | len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, | ||
483 | evt_ent->d_name); | ||
484 | if (len < 0) | ||
485 | return EVT_FAILED; | ||
486 | |||
487 | rem -= len; | ||
488 | if (flags) { | ||
489 | if (rem < strlen(flags) + 1) | ||
490 | return EVT_FAILED; | ||
491 | |||
492 | strcat(event_opt, ":"); | ||
493 | strcat(event_opt, flags); | ||
494 | } | ||
495 | |||
496 | if (parse_events(NULL, event_opt, 0)) | ||
497 | return EVT_FAILED; | ||
498 | } | ||
499 | |||
500 | return EVT_HANDLED_ALL; | ||
501 | } | ||
502 | |||
503 | |||
504 | static enum event_result parse_tracepoint_event(const char **strp, | ||
505 | struct perf_event_attr *attr) | ||
380 | { | 506 | { |
381 | const char *evt_name; | 507 | const char *evt_name; |
382 | char *flags; | 508 | char *flags; |
383 | char sys_name[MAX_EVENT_LENGTH]; | 509 | char sys_name[MAX_EVENT_LENGTH]; |
384 | char id_buf[4]; | ||
385 | int fd; | ||
386 | unsigned int sys_length, evt_length; | 510 | unsigned int sys_length, evt_length; |
387 | u64 id; | ||
388 | char evt_path[MAXPATHLEN]; | ||
389 | 511 | ||
390 | if (valid_debugfs_mount(debugfs_path)) | 512 | if (valid_debugfs_mount(debugfs_path)) |
391 | return 0; | 513 | return 0; |
392 | 514 | ||
393 | evt_name = strchr(*strp, ':'); | 515 | evt_name = strchr(*strp, ':'); |
394 | if (!evt_name) | 516 | if (!evt_name) |
395 | return 0; | 517 | return EVT_FAILED; |
396 | 518 | ||
397 | sys_length = evt_name - *strp; | 519 | sys_length = evt_name - *strp; |
398 | if (sys_length >= MAX_EVENT_LENGTH) | 520 | if (sys_length >= MAX_EVENT_LENGTH) |
@@ -404,32 +526,22 @@ static int parse_tracepoint_event(const char **strp, | |||
404 | 526 | ||
405 | flags = strchr(evt_name, ':'); | 527 | flags = strchr(evt_name, ':'); |
406 | if (flags) { | 528 | if (flags) { |
407 | *flags = '\0'; | 529 | /* split it out: */ |
530 | evt_name = strndup(evt_name, flags - evt_name); | ||
408 | flags++; | 531 | flags++; |
409 | if (!strncmp(flags, "record", strlen(flags))) | ||
410 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
411 | } | 532 | } |
412 | 533 | ||
413 | evt_length = strlen(evt_name); | 534 | evt_length = strlen(evt_name); |
414 | if (evt_length >= MAX_EVENT_LENGTH) | 535 | if (evt_length >= MAX_EVENT_LENGTH) |
415 | return 0; | 536 | return EVT_FAILED; |
416 | 537 | ||
417 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | 538 | if (!strcmp(evt_name, "*")) { |
418 | sys_name, evt_name); | 539 | *strp = evt_name + evt_length; |
419 | fd = open(evt_path, O_RDONLY); | 540 | return parse_subsystem_tracepoint_event(sys_name, flags); |
420 | if (fd < 0) | 541 | } else |
421 | return 0; | 542 | return parse_single_tracepoint_event(sys_name, evt_name, |
422 | 543 | evt_length, flags, | |
423 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | 544 | attr, strp); |
424 | close(fd); | ||
425 | return 0; | ||
426 | } | ||
427 | close(fd); | ||
428 | id = atoll(id_buf); | ||
429 | attr->config = id; | ||
430 | attr->type = PERF_TYPE_TRACEPOINT; | ||
431 | *strp = evt_name + evt_length; | ||
432 | return 1; | ||
433 | } | 545 | } |
434 | 546 | ||
435 | static int check_events(const char *str, unsigned int i) | 547 | static int check_events(const char *str, unsigned int i) |
@@ -447,8 +559,8 @@ static int check_events(const char *str, unsigned int i) | |||
447 | return 0; | 559 | return 0; |
448 | } | 560 | } |
449 | 561 | ||
450 | static int | 562 | static enum event_result |
451 | parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) | 563 | parse_symbolic_event(const char **strp, struct perf_event_attr *attr) |
452 | { | 564 | { |
453 | const char *str = *strp; | 565 | const char *str = *strp; |
454 | unsigned int i; | 566 | unsigned int i; |
@@ -460,32 +572,33 @@ parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) | |||
460 | attr->type = event_symbols[i].type; | 572 | attr->type = event_symbols[i].type; |
461 | attr->config = event_symbols[i].config; | 573 | attr->config = event_symbols[i].config; |
462 | *strp = str + n; | 574 | *strp = str + n; |
463 | return 1; | 575 | return EVT_HANDLED; |
464 | } | 576 | } |
465 | } | 577 | } |
466 | return 0; | 578 | return EVT_FAILED; |
467 | } | 579 | } |
468 | 580 | ||
469 | static int parse_raw_event(const char **strp, struct perf_counter_attr *attr) | 581 | static enum event_result |
582 | parse_raw_event(const char **strp, struct perf_event_attr *attr) | ||
470 | { | 583 | { |
471 | const char *str = *strp; | 584 | const char *str = *strp; |
472 | u64 config; | 585 | u64 config; |
473 | int n; | 586 | int n; |
474 | 587 | ||
475 | if (*str != 'r') | 588 | if (*str != 'r') |
476 | return 0; | 589 | return EVT_FAILED; |
477 | n = hex2u64(str + 1, &config); | 590 | n = hex2u64(str + 1, &config); |
478 | if (n > 0) { | 591 | if (n > 0) { |
479 | *strp = str + n + 1; | 592 | *strp = str + n + 1; |
480 | attr->type = PERF_TYPE_RAW; | 593 | attr->type = PERF_TYPE_RAW; |
481 | attr->config = config; | 594 | attr->config = config; |
482 | return 1; | 595 | return EVT_HANDLED; |
483 | } | 596 | } |
484 | return 0; | 597 | return EVT_FAILED; |
485 | } | 598 | } |
486 | 599 | ||
487 | static int | 600 | static enum event_result |
488 | parse_numeric_event(const char **strp, struct perf_counter_attr *attr) | 601 | parse_numeric_event(const char **strp, struct perf_event_attr *attr) |
489 | { | 602 | { |
490 | const char *str = *strp; | 603 | const char *str = *strp; |
491 | char *endp; | 604 | char *endp; |
@@ -500,14 +613,14 @@ parse_numeric_event(const char **strp, struct perf_counter_attr *attr) | |||
500 | attr->type = type; | 613 | attr->type = type; |
501 | attr->config = config; | 614 | attr->config = config; |
502 | *strp = endp; | 615 | *strp = endp; |
503 | return 1; | 616 | return EVT_HANDLED; |
504 | } | 617 | } |
505 | } | 618 | } |
506 | return 0; | 619 | return EVT_FAILED; |
507 | } | 620 | } |
508 | 621 | ||
509 | static int | 622 | static enum event_result |
510 | parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | 623 | parse_event_modifier(const char **strp, struct perf_event_attr *attr) |
511 | { | 624 | { |
512 | const char *str = *strp; | 625 | const char *str = *strp; |
513 | int eu = 1, ek = 1, eh = 1; | 626 | int eu = 1, ek = 1, eh = 1; |
@@ -539,37 +652,87 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | |||
539 | * Each event can have multiple symbolic names. | 652 | * Each event can have multiple symbolic names. |
540 | * Symbolic names are (almost) exactly matched. | 653 | * Symbolic names are (almost) exactly matched. |
541 | */ | 654 | */ |
542 | static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) | 655 | static enum event_result |
656 | parse_event_symbols(const char **str, struct perf_event_attr *attr) | ||
543 | { | 657 | { |
544 | if (!(parse_tracepoint_event(str, attr) || | 658 | enum event_result ret; |
545 | parse_raw_event(str, attr) || | 659 | |
546 | parse_numeric_event(str, attr) || | 660 | ret = parse_tracepoint_event(str, attr); |
547 | parse_symbolic_event(str, attr) || | 661 | if (ret != EVT_FAILED) |
548 | parse_generic_hw_event(str, attr))) | 662 | goto modifier; |
549 | return 0; | 663 | |
664 | ret = parse_raw_event(str, attr); | ||
665 | if (ret != EVT_FAILED) | ||
666 | goto modifier; | ||
550 | 667 | ||
668 | ret = parse_numeric_event(str, attr); | ||
669 | if (ret != EVT_FAILED) | ||
670 | goto modifier; | ||
671 | |||
672 | ret = parse_symbolic_event(str, attr); | ||
673 | if (ret != EVT_FAILED) | ||
674 | goto modifier; | ||
675 | |||
676 | ret = parse_generic_hw_event(str, attr); | ||
677 | if (ret != EVT_FAILED) | ||
678 | goto modifier; | ||
679 | |||
680 | return EVT_FAILED; | ||
681 | |||
682 | modifier: | ||
551 | parse_event_modifier(str, attr); | 683 | parse_event_modifier(str, attr); |
552 | 684 | ||
553 | return 1; | 685 | return ret; |
554 | } | 686 | } |
555 | 687 | ||
688 | static void store_event_type(const char *orgname) | ||
689 | { | ||
690 | char filename[PATH_MAX], *c; | ||
691 | FILE *file; | ||
692 | int id; | ||
693 | |||
694 | sprintf(filename, "%s/", debugfs_path); | ||
695 | strncat(filename, orgname, strlen(orgname)); | ||
696 | strcat(filename, "/id"); | ||
697 | |||
698 | c = strchr(filename, ':'); | ||
699 | if (c) | ||
700 | *c = '/'; | ||
701 | |||
702 | file = fopen(filename, "r"); | ||
703 | if (!file) | ||
704 | return; | ||
705 | if (fscanf(file, "%i", &id) < 1) | ||
706 | die("cannot store event ID"); | ||
707 | fclose(file); | ||
708 | perf_header__push_event(id, orgname); | ||
709 | } | ||
710 | |||
711 | |||
556 | int parse_events(const struct option *opt __used, const char *str, int unset __used) | 712 | int parse_events(const struct option *opt __used, const char *str, int unset __used) |
557 | { | 713 | { |
558 | struct perf_counter_attr attr; | 714 | struct perf_event_attr attr; |
715 | enum event_result ret; | ||
716 | |||
717 | if (strchr(str, ':')) | ||
718 | store_event_type(str); | ||
559 | 719 | ||
560 | for (;;) { | 720 | for (;;) { |
561 | if (nr_counters == MAX_COUNTERS) | 721 | if (nr_counters == MAX_COUNTERS) |
562 | return -1; | 722 | return -1; |
563 | 723 | ||
564 | memset(&attr, 0, sizeof(attr)); | 724 | memset(&attr, 0, sizeof(attr)); |
565 | if (!parse_event_symbols(&str, &attr)) | 725 | ret = parse_event_symbols(&str, &attr); |
726 | if (ret == EVT_FAILED) | ||
566 | return -1; | 727 | return -1; |
567 | 728 | ||
568 | if (!(*str == 0 || *str == ',' || isspace(*str))) | 729 | if (!(*str == 0 || *str == ',' || isspace(*str))) |
569 | return -1; | 730 | return -1; |
570 | 731 | ||
571 | attrs[nr_counters] = attr; | 732 | if (ret != EVT_HANDLED_ALL) { |
572 | nr_counters++; | 733 | attrs[nr_counters] = attr; |
734 | nr_counters++; | ||
735 | } | ||
573 | 736 | ||
574 | if (*str == 0) | 737 | if (*str == 0) |
575 | break; | 738 | break; |
@@ -598,31 +761,32 @@ static void print_tracepoint_events(void) | |||
598 | { | 761 | { |
599 | DIR *sys_dir, *evt_dir; | 762 | DIR *sys_dir, *evt_dir; |
600 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 763 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; |
601 | struct stat st; | ||
602 | char evt_path[MAXPATHLEN]; | 764 | char evt_path[MAXPATHLEN]; |
765 | char dir_path[MAXPATHLEN]; | ||
603 | 766 | ||
604 | if (valid_debugfs_mount(debugfs_path)) | 767 | if (valid_debugfs_mount(debugfs_path)) |
605 | return; | 768 | return; |
606 | 769 | ||
607 | sys_dir = opendir(debugfs_path); | 770 | sys_dir = opendir(debugfs_path); |
608 | if (!sys_dir) | 771 | if (!sys_dir) |
609 | goto cleanup; | 772 | return; |
610 | 773 | ||
611 | for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { | 774 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { |
612 | evt_dir = opendir(evt_path); | 775 | |
776 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, | ||
777 | sys_dirent.d_name); | ||
778 | evt_dir = opendir(dir_path); | ||
613 | if (!evt_dir) | 779 | if (!evt_dir) |
614 | goto cleanup; | 780 | continue; |
615 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, | 781 | |
616 | evt_path, st) { | 782 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { |
617 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 783 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
618 | sys_dirent.d_name, evt_dirent.d_name); | 784 | sys_dirent.d_name, evt_dirent.d_name); |
619 | fprintf(stderr, " %-40s [%s]\n", evt_path, | 785 | fprintf(stderr, " %-42s [%s]\n", evt_path, |
620 | event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); | 786 | event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); |
621 | } | 787 | } |
622 | closedir(evt_dir); | 788 | closedir(evt_dir); |
623 | } | 789 | } |
624 | |||
625 | cleanup: | ||
626 | closedir(sys_dir); | 790 | closedir(sys_dir); |
627 | } | 791 | } |
628 | 792 | ||
@@ -650,7 +814,7 @@ void print_events(void) | |||
650 | sprintf(name, "%s OR %s", syms->symbol, syms->alias); | 814 | sprintf(name, "%s OR %s", syms->symbol, syms->alias); |
651 | else | 815 | else |
652 | strcpy(name, syms->symbol); | 816 | strcpy(name, syms->symbol); |
653 | fprintf(stderr, " %-40s [%s]\n", name, | 817 | fprintf(stderr, " %-42s [%s]\n", name, |
654 | event_type_descriptors[type]); | 818 | event_type_descriptors[type]); |
655 | 819 | ||
656 | prev_type = type; | 820 | prev_type = type; |
@@ -664,7 +828,7 @@ void print_events(void) | |||
664 | continue; | 828 | continue; |
665 | 829 | ||
666 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | 830 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { |
667 | fprintf(stderr, " %-40s [%s]\n", | 831 | fprintf(stderr, " %-42s [%s]\n", |
668 | event_cache_name(type, op, i), | 832 | event_cache_name(type, op, i), |
669 | event_type_descriptors[4]); | 833 | event_type_descriptors[4]); |
670 | } | 834 | } |
@@ -672,7 +836,7 @@ void print_events(void) | |||
672 | } | 836 | } |
673 | 837 | ||
674 | fprintf(stderr, "\n"); | 838 | fprintf(stderr, "\n"); |
675 | fprintf(stderr, " %-40s [raw hardware event descriptor]\n", | 839 | fprintf(stderr, " %-42s [raw hardware event descriptor]\n", |
676 | "rNNN"); | 840 | "rNNN"); |
677 | fprintf(stderr, "\n"); | 841 | fprintf(stderr, "\n"); |
678 | 842 | ||