diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 174 |
1 files changed, 131 insertions, 43 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 995fc25db8c6..98125319b158 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include "parse-options.h" | 6 | #include "parse-options.h" |
7 | #include "parse-events.h" | 7 | #include "parse-events.h" |
8 | #include "exec_cmd.h" | 8 | #include "exec_cmd.h" |
9 | #include "string.h" | 9 | #include "linux/string.h" |
10 | #include "symbol.h" | 10 | #include "symbol.h" |
11 | #include "cache.h" | 11 | #include "cache.h" |
12 | #include "header.h" | 12 | #include "header.h" |
@@ -15,6 +15,7 @@ | |||
15 | #define YY_EXTRA_TYPE int | 15 | #define YY_EXTRA_TYPE int |
16 | #include "parse-events-flex.h" | 16 | #include "parse-events-flex.h" |
17 | #include "pmu.h" | 17 | #include "pmu.h" |
18 | #include "thread_map.h" | ||
18 | 19 | ||
19 | #define MAX_NAME_LEN 100 | 20 | #define MAX_NAME_LEN 100 |
20 | 21 | ||
@@ -108,6 +109,10 @@ static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { | |||
108 | .symbol = "emulation-faults", | 109 | .symbol = "emulation-faults", |
109 | .alias = "", | 110 | .alias = "", |
110 | }, | 111 | }, |
112 | [PERF_COUNT_SW_DUMMY] = { | ||
113 | .symbol = "dummy", | ||
114 | .alias = "", | ||
115 | }, | ||
111 | }; | 116 | }; |
112 | 117 | ||
113 | #define __PERF_EVENT_FIELD(config, name) \ | 118 | #define __PERF_EVENT_FIELD(config, name) \ |
@@ -217,6 +222,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
217 | return NULL; | 222 | return NULL; |
218 | } | 223 | } |
219 | 224 | ||
225 | struct tracepoint_path *tracepoint_name_to_path(const char *name) | ||
226 | { | ||
227 | struct tracepoint_path *path = zalloc(sizeof(*path)); | ||
228 | char *str = strchr(name, ':'); | ||
229 | |||
230 | if (path == NULL || str == NULL) { | ||
231 | free(path); | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | path->system = strndup(name, str - name); | ||
236 | path->name = strdup(str+1); | ||
237 | |||
238 | if (path->system == NULL || path->name == NULL) { | ||
239 | free(path->system); | ||
240 | free(path->name); | ||
241 | free(path); | ||
242 | path = NULL; | ||
243 | } | ||
244 | |||
245 | return path; | ||
246 | } | ||
247 | |||
220 | const char *event_type(int type) | 248 | const char *event_type(int type) |
221 | { | 249 | { |
222 | switch (type) { | 250 | switch (type) { |
@@ -241,40 +269,29 @@ const char *event_type(int type) | |||
241 | 269 | ||
242 | 270 | ||
243 | 271 | ||
244 | static int __add_event(struct list_head **_list, int *idx, | 272 | static int __add_event(struct list_head *list, int *idx, |
245 | struct perf_event_attr *attr, | 273 | struct perf_event_attr *attr, |
246 | char *name, struct cpu_map *cpus) | 274 | char *name, struct cpu_map *cpus) |
247 | { | 275 | { |
248 | struct perf_evsel *evsel; | 276 | struct perf_evsel *evsel; |
249 | struct list_head *list = *_list; | ||
250 | |||
251 | if (!list) { | ||
252 | list = malloc(sizeof(*list)); | ||
253 | if (!list) | ||
254 | return -ENOMEM; | ||
255 | INIT_LIST_HEAD(list); | ||
256 | } | ||
257 | 277 | ||
258 | event_attr_init(attr); | 278 | event_attr_init(attr); |
259 | 279 | ||
260 | evsel = perf_evsel__new(attr, (*idx)++); | 280 | evsel = perf_evsel__new(attr, (*idx)++); |
261 | if (!evsel) { | 281 | if (!evsel) |
262 | free(list); | ||
263 | return -ENOMEM; | 282 | return -ENOMEM; |
264 | } | ||
265 | 283 | ||
266 | evsel->cpus = cpus; | 284 | evsel->cpus = cpus; |
267 | if (name) | 285 | if (name) |
268 | evsel->name = strdup(name); | 286 | evsel->name = strdup(name); |
269 | list_add_tail(&evsel->node, list); | 287 | list_add_tail(&evsel->node, list); |
270 | *_list = list; | ||
271 | return 0; | 288 | return 0; |
272 | } | 289 | } |
273 | 290 | ||
274 | static int add_event(struct list_head **_list, int *idx, | 291 | static int add_event(struct list_head *list, int *idx, |
275 | struct perf_event_attr *attr, char *name) | 292 | struct perf_event_attr *attr, char *name) |
276 | { | 293 | { |
277 | return __add_event(_list, idx, attr, name, NULL); | 294 | return __add_event(list, idx, attr, name, NULL); |
278 | } | 295 | } |
279 | 296 | ||
280 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) | 297 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
@@ -295,7 +312,7 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES] | |||
295 | return -1; | 312 | return -1; |
296 | } | 313 | } |
297 | 314 | ||
298 | int parse_events_add_cache(struct list_head **list, int *idx, | 315 | int parse_events_add_cache(struct list_head *list, int *idx, |
299 | char *type, char *op_result1, char *op_result2) | 316 | char *type, char *op_result1, char *op_result2) |
300 | { | 317 | { |
301 | struct perf_event_attr attr; | 318 | struct perf_event_attr attr; |
@@ -356,31 +373,21 @@ int parse_events_add_cache(struct list_head **list, int *idx, | |||
356 | return add_event(list, idx, &attr, name); | 373 | return add_event(list, idx, &attr, name); |
357 | } | 374 | } |
358 | 375 | ||
359 | static int add_tracepoint(struct list_head **listp, int *idx, | 376 | static int add_tracepoint(struct list_head *list, int *idx, |
360 | char *sys_name, char *evt_name) | 377 | char *sys_name, char *evt_name) |
361 | { | 378 | { |
362 | struct perf_evsel *evsel; | 379 | struct perf_evsel *evsel; |
363 | struct list_head *list = *listp; | ||
364 | |||
365 | if (!list) { | ||
366 | list = malloc(sizeof(*list)); | ||
367 | if (!list) | ||
368 | return -ENOMEM; | ||
369 | INIT_LIST_HEAD(list); | ||
370 | } | ||
371 | 380 | ||
372 | evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); | 381 | evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); |
373 | if (!evsel) { | 382 | if (!evsel) |
374 | free(list); | ||
375 | return -ENOMEM; | 383 | return -ENOMEM; |
376 | } | ||
377 | 384 | ||
378 | list_add_tail(&evsel->node, list); | 385 | list_add_tail(&evsel->node, list); |
379 | *listp = list; | 386 | |
380 | return 0; | 387 | return 0; |
381 | } | 388 | } |
382 | 389 | ||
383 | static int add_tracepoint_multi_event(struct list_head **list, int *idx, | 390 | static int add_tracepoint_multi_event(struct list_head *list, int *idx, |
384 | char *sys_name, char *evt_name) | 391 | char *sys_name, char *evt_name) |
385 | { | 392 | { |
386 | char evt_path[MAXPATHLEN]; | 393 | char evt_path[MAXPATHLEN]; |
@@ -412,7 +419,7 @@ static int add_tracepoint_multi_event(struct list_head **list, int *idx, | |||
412 | return ret; | 419 | return ret; |
413 | } | 420 | } |
414 | 421 | ||
415 | static int add_tracepoint_event(struct list_head **list, int *idx, | 422 | static int add_tracepoint_event(struct list_head *list, int *idx, |
416 | char *sys_name, char *evt_name) | 423 | char *sys_name, char *evt_name) |
417 | { | 424 | { |
418 | return strpbrk(evt_name, "*?") ? | 425 | return strpbrk(evt_name, "*?") ? |
@@ -420,7 +427,7 @@ static int add_tracepoint_event(struct list_head **list, int *idx, | |||
420 | add_tracepoint(list, idx, sys_name, evt_name); | 427 | add_tracepoint(list, idx, sys_name, evt_name); |
421 | } | 428 | } |
422 | 429 | ||
423 | static int add_tracepoint_multi_sys(struct list_head **list, int *idx, | 430 | static int add_tracepoint_multi_sys(struct list_head *list, int *idx, |
424 | char *sys_name, char *evt_name) | 431 | char *sys_name, char *evt_name) |
425 | { | 432 | { |
426 | struct dirent *events_ent; | 433 | struct dirent *events_ent; |
@@ -452,7 +459,7 @@ static int add_tracepoint_multi_sys(struct list_head **list, int *idx, | |||
452 | return ret; | 459 | return ret; |
453 | } | 460 | } |
454 | 461 | ||
455 | int parse_events_add_tracepoint(struct list_head **list, int *idx, | 462 | int parse_events_add_tracepoint(struct list_head *list, int *idx, |
456 | char *sys, char *event) | 463 | char *sys, char *event) |
457 | { | 464 | { |
458 | int ret; | 465 | int ret; |
@@ -507,7 +514,7 @@ do { \ | |||
507 | return 0; | 514 | return 0; |
508 | } | 515 | } |
509 | 516 | ||
510 | int parse_events_add_breakpoint(struct list_head **list, int *idx, | 517 | int parse_events_add_breakpoint(struct list_head *list, int *idx, |
511 | void *ptr, char *type) | 518 | void *ptr, char *type) |
512 | { | 519 | { |
513 | struct perf_event_attr attr; | 520 | struct perf_event_attr attr; |
@@ -588,7 +595,7 @@ static int config_attr(struct perf_event_attr *attr, | |||
588 | return 0; | 595 | return 0; |
589 | } | 596 | } |
590 | 597 | ||
591 | int parse_events_add_numeric(struct list_head **list, int *idx, | 598 | int parse_events_add_numeric(struct list_head *list, int *idx, |
592 | u32 type, u64 config, | 599 | u32 type, u64 config, |
593 | struct list_head *head_config) | 600 | struct list_head *head_config) |
594 | { | 601 | { |
@@ -621,7 +628,7 @@ static char *pmu_event_name(struct list_head *head_terms) | |||
621 | return NULL; | 628 | return NULL; |
622 | } | 629 | } |
623 | 630 | ||
624 | int parse_events_add_pmu(struct list_head **list, int *idx, | 631 | int parse_events_add_pmu(struct list_head *list, int *idx, |
625 | char *name, struct list_head *head_config) | 632 | char *name, struct list_head *head_config) |
626 | { | 633 | { |
627 | struct perf_event_attr attr; | 634 | struct perf_event_attr attr; |
@@ -664,6 +671,7 @@ void parse_events__set_leader(char *name, struct list_head *list) | |||
664 | leader->group_name = name ? strdup(name) : NULL; | 671 | leader->group_name = name ? strdup(name) : NULL; |
665 | } | 672 | } |
666 | 673 | ||
674 | /* list_event is assumed to point to malloc'ed memory */ | ||
667 | void parse_events_update_lists(struct list_head *list_event, | 675 | void parse_events_update_lists(struct list_head *list_event, |
668 | struct list_head *list_all) | 676 | struct list_head *list_all) |
669 | { | 677 | { |
@@ -684,6 +692,8 @@ struct event_modifier { | |||
684 | int eG; | 692 | int eG; |
685 | int precise; | 693 | int precise; |
686 | int exclude_GH; | 694 | int exclude_GH; |
695 | int sample_read; | ||
696 | int pinned; | ||
687 | }; | 697 | }; |
688 | 698 | ||
689 | static int get_event_modifier(struct event_modifier *mod, char *str, | 699 | static int get_event_modifier(struct event_modifier *mod, char *str, |
@@ -695,6 +705,8 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
695 | int eH = evsel ? evsel->attr.exclude_host : 0; | 705 | int eH = evsel ? evsel->attr.exclude_host : 0; |
696 | int eG = evsel ? evsel->attr.exclude_guest : 0; | 706 | int eG = evsel ? evsel->attr.exclude_guest : 0; |
697 | int precise = evsel ? evsel->attr.precise_ip : 0; | 707 | int precise = evsel ? evsel->attr.precise_ip : 0; |
708 | int sample_read = 0; | ||
709 | int pinned = evsel ? evsel->attr.pinned : 0; | ||
698 | 710 | ||
699 | int exclude = eu | ek | eh; | 711 | int exclude = eu | ek | eh; |
700 | int exclude_GH = evsel ? evsel->exclude_GH : 0; | 712 | int exclude_GH = evsel ? evsel->exclude_GH : 0; |
@@ -727,6 +739,10 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
727 | /* use of precise requires exclude_guest */ | 739 | /* use of precise requires exclude_guest */ |
728 | if (!exclude_GH) | 740 | if (!exclude_GH) |
729 | eG = 1; | 741 | eG = 1; |
742 | } else if (*str == 'S') { | ||
743 | sample_read = 1; | ||
744 | } else if (*str == 'D') { | ||
745 | pinned = 1; | ||
730 | } else | 746 | } else |
731 | break; | 747 | break; |
732 | 748 | ||
@@ -753,6 +769,9 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
753 | mod->eG = eG; | 769 | mod->eG = eG; |
754 | mod->precise = precise; | 770 | mod->precise = precise; |
755 | mod->exclude_GH = exclude_GH; | 771 | mod->exclude_GH = exclude_GH; |
772 | mod->sample_read = sample_read; | ||
773 | mod->pinned = pinned; | ||
774 | |||
756 | return 0; | 775 | return 0; |
757 | } | 776 | } |
758 | 777 | ||
@@ -765,7 +784,7 @@ static int check_modifier(char *str) | |||
765 | char *p = str; | 784 | char *p = str; |
766 | 785 | ||
767 | /* The sizeof includes 0 byte as well. */ | 786 | /* The sizeof includes 0 byte as well. */ |
768 | if (strlen(str) > (sizeof("ukhGHppp") - 1)) | 787 | if (strlen(str) > (sizeof("ukhGHpppSD") - 1)) |
769 | return -1; | 788 | return -1; |
770 | 789 | ||
771 | while (*p) { | 790 | while (*p) { |
@@ -803,6 +822,10 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) | |||
803 | evsel->attr.exclude_host = mod.eH; | 822 | evsel->attr.exclude_host = mod.eH; |
804 | evsel->attr.exclude_guest = mod.eG; | 823 | evsel->attr.exclude_guest = mod.eG; |
805 | evsel->exclude_GH = mod.exclude_GH; | 824 | evsel->exclude_GH = mod.exclude_GH; |
825 | evsel->sample_read = mod.sample_read; | ||
826 | |||
827 | if (perf_evsel__is_group_leader(evsel)) | ||
828 | evsel->attr.pinned = mod.pinned; | ||
806 | } | 829 | } |
807 | 830 | ||
808 | return 0; | 831 | return 0; |
@@ -820,6 +843,32 @@ int parse_events_name(struct list_head *list, char *name) | |||
820 | return 0; | 843 | return 0; |
821 | } | 844 | } |
822 | 845 | ||
846 | static int parse_events__scanner(const char *str, void *data, int start_token); | ||
847 | |||
848 | static int parse_events_fixup(int ret, const char *str, void *data, | ||
849 | int start_token) | ||
850 | { | ||
851 | char *o = strdup(str); | ||
852 | char *s = NULL; | ||
853 | char *t = o; | ||
854 | char *p; | ||
855 | int len = 0; | ||
856 | |||
857 | if (!o) | ||
858 | return ret; | ||
859 | while ((p = strsep(&t, ",")) != NULL) { | ||
860 | if (s) | ||
861 | str_append(&s, &len, ","); | ||
862 | str_append(&s, &len, "cpu/"); | ||
863 | str_append(&s, &len, p); | ||
864 | str_append(&s, &len, "/"); | ||
865 | } | ||
866 | free(o); | ||
867 | if (!s) | ||
868 | return -ENOMEM; | ||
869 | return parse_events__scanner(s, data, start_token); | ||
870 | } | ||
871 | |||
823 | static int parse_events__scanner(const char *str, void *data, int start_token) | 872 | static int parse_events__scanner(const char *str, void *data, int start_token) |
824 | { | 873 | { |
825 | YY_BUFFER_STATE buffer; | 874 | YY_BUFFER_STATE buffer; |
@@ -840,6 +889,8 @@ static int parse_events__scanner(const char *str, void *data, int start_token) | |||
840 | parse_events__flush_buffer(buffer, scanner); | 889 | parse_events__flush_buffer(buffer, scanner); |
841 | parse_events__delete_buffer(buffer, scanner); | 890 | parse_events__delete_buffer(buffer, scanner); |
842 | parse_events_lex_destroy(scanner); | 891 | parse_events_lex_destroy(scanner); |
892 | if (ret && !strchr(str, '/')) | ||
893 | ret = parse_events_fixup(ret, str, data, start_token); | ||
843 | return ret; | 894 | return ret; |
844 | } | 895 | } |
845 | 896 | ||
@@ -1026,6 +1077,33 @@ int is_valid_tracepoint(const char *event_string) | |||
1026 | return 0; | 1077 | return 0; |
1027 | } | 1078 | } |
1028 | 1079 | ||
1080 | static bool is_event_supported(u8 type, unsigned config) | ||
1081 | { | ||
1082 | bool ret = true; | ||
1083 | struct perf_evsel *evsel; | ||
1084 | struct perf_event_attr attr = { | ||
1085 | .type = type, | ||
1086 | .config = config, | ||
1087 | .disabled = 1, | ||
1088 | .exclude_kernel = 1, | ||
1089 | }; | ||
1090 | struct { | ||
1091 | struct thread_map map; | ||
1092 | int threads[1]; | ||
1093 | } tmap = { | ||
1094 | .map.nr = 1, | ||
1095 | .threads = { 0 }, | ||
1096 | }; | ||
1097 | |||
1098 | evsel = perf_evsel__new(&attr, 0); | ||
1099 | if (evsel) { | ||
1100 | ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; | ||
1101 | perf_evsel__delete(evsel); | ||
1102 | } | ||
1103 | |||
1104 | return ret; | ||
1105 | } | ||
1106 | |||
1029 | static void __print_events_type(u8 type, struct event_symbol *syms, | 1107 | static void __print_events_type(u8 type, struct event_symbol *syms, |
1030 | unsigned max) | 1108 | unsigned max) |
1031 | { | 1109 | { |
@@ -1033,14 +1111,16 @@ static void __print_events_type(u8 type, struct event_symbol *syms, | |||
1033 | unsigned i; | 1111 | unsigned i; |
1034 | 1112 | ||
1035 | for (i = 0; i < max ; i++, syms++) { | 1113 | for (i = 0; i < max ; i++, syms++) { |
1114 | if (!is_event_supported(type, i)) | ||
1115 | continue; | ||
1116 | |||
1036 | if (strlen(syms->alias)) | 1117 | if (strlen(syms->alias)) |
1037 | snprintf(name, sizeof(name), "%s OR %s", | 1118 | snprintf(name, sizeof(name), "%s OR %s", |
1038 | syms->symbol, syms->alias); | 1119 | syms->symbol, syms->alias); |
1039 | else | 1120 | else |
1040 | snprintf(name, sizeof(name), "%s", syms->symbol); | 1121 | snprintf(name, sizeof(name), "%s", syms->symbol); |
1041 | 1122 | ||
1042 | printf(" %-50s [%s]\n", name, | 1123 | printf(" %-50s [%s]\n", name, event_type_descriptors[type]); |
1043 | event_type_descriptors[type]); | ||
1044 | } | 1124 | } |
1045 | } | 1125 | } |
1046 | 1126 | ||
@@ -1069,6 +1149,10 @@ int print_hwcache_events(const char *event_glob, bool name_only) | |||
1069 | if (event_glob != NULL && !strglobmatch(name, event_glob)) | 1149 | if (event_glob != NULL && !strglobmatch(name, event_glob)) |
1070 | continue; | 1150 | continue; |
1071 | 1151 | ||
1152 | if (!is_event_supported(PERF_TYPE_HW_CACHE, | ||
1153 | type | (op << 8) | (i << 16))) | ||
1154 | continue; | ||
1155 | |||
1072 | if (name_only) | 1156 | if (name_only) |
1073 | printf("%s ", name); | 1157 | printf("%s ", name); |
1074 | else | 1158 | else |
@@ -1079,6 +1163,8 @@ int print_hwcache_events(const char *event_glob, bool name_only) | |||
1079 | } | 1163 | } |
1080 | } | 1164 | } |
1081 | 1165 | ||
1166 | if (printed) | ||
1167 | printf("\n"); | ||
1082 | return printed; | 1168 | return printed; |
1083 | } | 1169 | } |
1084 | 1170 | ||
@@ -1096,6 +1182,9 @@ static void print_symbol_events(const char *event_glob, unsigned type, | |||
1096 | (syms->alias && strglobmatch(syms->alias, event_glob)))) | 1182 | (syms->alias && strglobmatch(syms->alias, event_glob)))) |
1097 | continue; | 1183 | continue; |
1098 | 1184 | ||
1185 | if (!is_event_supported(type, i)) | ||
1186 | continue; | ||
1187 | |||
1099 | if (name_only) { | 1188 | if (name_only) { |
1100 | printf("%s ", syms->symbol); | 1189 | printf("%s ", syms->symbol); |
1101 | continue; | 1190 | continue; |
@@ -1133,11 +1222,12 @@ void print_events(const char *event_glob, bool name_only) | |||
1133 | 1222 | ||
1134 | print_hwcache_events(event_glob, name_only); | 1223 | print_hwcache_events(event_glob, name_only); |
1135 | 1224 | ||
1225 | print_pmu_events(event_glob, name_only); | ||
1226 | |||
1136 | if (event_glob != NULL) | 1227 | if (event_glob != NULL) |
1137 | return; | 1228 | return; |
1138 | 1229 | ||
1139 | if (!name_only) { | 1230 | if (!name_only) { |
1140 | printf("\n"); | ||
1141 | printf(" %-50s [%s]\n", | 1231 | printf(" %-50s [%s]\n", |
1142 | "rNNN", | 1232 | "rNNN", |
1143 | event_type_descriptors[PERF_TYPE_RAW]); | 1233 | event_type_descriptors[PERF_TYPE_RAW]); |
@@ -1237,6 +1327,4 @@ void parse_events__free_terms(struct list_head *terms) | |||
1237 | 1327 | ||
1238 | list_for_each_entry_safe(term, h, terms, list) | 1328 | list_for_each_entry_safe(term, h, terms, list) |
1239 | free(term); | 1329 | free(term); |
1240 | |||
1241 | free(terms); | ||
1242 | } | 1330 | } |