diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 254 |
1 files changed, 173 insertions, 81 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 74a5af4d33ec..aed38e4b9dfa 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -239,8 +239,11 @@ const char *event_type(int type) | |||
239 | return "unknown"; | 239 | return "unknown"; |
240 | } | 240 | } |
241 | 241 | ||
242 | static int add_event(struct list_head **_list, int *idx, | 242 | |
243 | struct perf_event_attr *attr, char *name) | 243 | |
244 | static int __add_event(struct list_head **_list, int *idx, | ||
245 | struct perf_event_attr *attr, | ||
246 | char *name, struct cpu_map *cpus) | ||
244 | { | 247 | { |
245 | struct perf_evsel *evsel; | 248 | struct perf_evsel *evsel; |
246 | struct list_head *list = *_list; | 249 | struct list_head *list = *_list; |
@@ -260,6 +263,7 @@ static int add_event(struct list_head **_list, int *idx, | |||
260 | return -ENOMEM; | 263 | return -ENOMEM; |
261 | } | 264 | } |
262 | 265 | ||
266 | evsel->cpus = cpus; | ||
263 | if (name) | 267 | if (name) |
264 | evsel->name = strdup(name); | 268 | evsel->name = strdup(name); |
265 | list_add_tail(&evsel->node, list); | 269 | list_add_tail(&evsel->node, list); |
@@ -267,6 +271,12 @@ static int add_event(struct list_head **_list, int *idx, | |||
267 | return 0; | 271 | return 0; |
268 | } | 272 | } |
269 | 273 | ||
274 | static int add_event(struct list_head **_list, int *idx, | ||
275 | struct perf_event_attr *attr, char *name) | ||
276 | { | ||
277 | return __add_event(_list, idx, attr, name, NULL); | ||
278 | } | ||
279 | |||
270 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) | 280 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
271 | { | 281 | { |
272 | int i, j; | 282 | int i, j; |
@@ -308,7 +318,7 @@ int parse_events_add_cache(struct list_head **list, int *idx, | |||
308 | for (i = 0; (i < 2) && (op_result[i]); i++) { | 318 | for (i = 0; (i < 2) && (op_result[i]); i++) { |
309 | char *str = op_result[i]; | 319 | char *str = op_result[i]; |
310 | 320 | ||
311 | snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str); | 321 | n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); |
312 | 322 | ||
313 | if (cache_op == -1) { | 323 | if (cache_op == -1) { |
314 | cache_op = parse_aliases(str, perf_evsel__hw_cache_op, | 324 | cache_op = parse_aliases(str, perf_evsel__hw_cache_op, |
@@ -346,42 +356,28 @@ int parse_events_add_cache(struct list_head **list, int *idx, | |||
346 | return add_event(list, idx, &attr, name); | 356 | return add_event(list, idx, &attr, name); |
347 | } | 357 | } |
348 | 358 | ||
349 | static int add_tracepoint(struct list_head **list, int *idx, | 359 | static int add_tracepoint(struct list_head **listp, int *idx, |
350 | char *sys_name, char *evt_name) | 360 | char *sys_name, char *evt_name) |
351 | { | 361 | { |
352 | struct perf_event_attr attr; | 362 | struct perf_evsel *evsel; |
353 | char name[MAX_NAME_LEN]; | 363 | struct list_head *list = *listp; |
354 | char evt_path[MAXPATHLEN]; | ||
355 | char id_buf[4]; | ||
356 | u64 id; | ||
357 | int fd; | ||
358 | |||
359 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, | ||
360 | sys_name, evt_name); | ||
361 | |||
362 | fd = open(evt_path, O_RDONLY); | ||
363 | if (fd < 0) | ||
364 | return -1; | ||
365 | 364 | ||
366 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | 365 | if (!list) { |
367 | close(fd); | 366 | list = malloc(sizeof(*list)); |
368 | return -1; | 367 | if (!list) |
368 | return -ENOMEM; | ||
369 | INIT_LIST_HEAD(list); | ||
369 | } | 370 | } |
370 | 371 | ||
371 | close(fd); | 372 | evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); |
372 | id = atoll(id_buf); | 373 | if (!evsel) { |
373 | 374 | free(list); | |
374 | memset(&attr, 0, sizeof(attr)); | 375 | return -ENOMEM; |
375 | attr.config = id; | 376 | } |
376 | attr.type = PERF_TYPE_TRACEPOINT; | ||
377 | attr.sample_type |= PERF_SAMPLE_RAW; | ||
378 | attr.sample_type |= PERF_SAMPLE_TIME; | ||
379 | attr.sample_type |= PERF_SAMPLE_CPU; | ||
380 | attr.sample_type |= PERF_SAMPLE_PERIOD; | ||
381 | attr.sample_period = 1; | ||
382 | 377 | ||
383 | snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); | 378 | list_add_tail(&evsel->node, list); |
384 | return add_event(list, idx, &attr, name); | 379 | *listp = list; |
380 | return 0; | ||
385 | } | 381 | } |
386 | 382 | ||
387 | static int add_tracepoint_multi(struct list_head **list, int *idx, | 383 | static int add_tracepoint_multi(struct list_head **list, int *idx, |
@@ -551,7 +547,7 @@ static int config_attr(struct perf_event_attr *attr, | |||
551 | } | 547 | } |
552 | 548 | ||
553 | int parse_events_add_numeric(struct list_head **list, int *idx, | 549 | int parse_events_add_numeric(struct list_head **list, int *idx, |
554 | unsigned long type, unsigned long config, | 550 | u32 type, u64 config, |
555 | struct list_head *head_config) | 551 | struct list_head *head_config) |
556 | { | 552 | { |
557 | struct perf_event_attr attr; | 553 | struct perf_event_attr attr; |
@@ -607,8 +603,23 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
607 | if (perf_pmu__config(pmu, &attr, head_config)) | 603 | if (perf_pmu__config(pmu, &attr, head_config)) |
608 | return -EINVAL; | 604 | return -EINVAL; |
609 | 605 | ||
610 | return add_event(list, idx, &attr, | 606 | return __add_event(list, idx, &attr, pmu_event_name(head_config), |
611 | pmu_event_name(head_config)); | 607 | pmu->cpus); |
608 | } | ||
609 | |||
610 | int parse_events__modifier_group(struct list_head *list, | ||
611 | char *event_mod) | ||
612 | { | ||
613 | return parse_events__modifier_event(list, event_mod, true); | ||
614 | } | ||
615 | |||
616 | void parse_events__set_leader(char *name, struct list_head *list) | ||
617 | { | ||
618 | struct perf_evsel *leader; | ||
619 | |||
620 | __perf_evlist__set_leader(list); | ||
621 | leader = list_entry(list->next, struct perf_evsel, node); | ||
622 | leader->group_name = name ? strdup(name) : NULL; | ||
612 | } | 623 | } |
613 | 624 | ||
614 | void parse_events_update_lists(struct list_head *list_event, | 625 | void parse_events_update_lists(struct list_head *list_event, |
@@ -616,21 +627,45 @@ void parse_events_update_lists(struct list_head *list_event, | |||
616 | { | 627 | { |
617 | /* | 628 | /* |
618 | * Called for single event definition. Update the | 629 | * Called for single event definition. Update the |
619 | * 'all event' list, and reinit the 'signle event' | 630 | * 'all event' list, and reinit the 'single event' |
620 | * list, for next event definition. | 631 | * list, for next event definition. |
621 | */ | 632 | */ |
622 | list_splice_tail(list_event, list_all); | 633 | list_splice_tail(list_event, list_all); |
623 | free(list_event); | 634 | free(list_event); |
624 | } | 635 | } |
625 | 636 | ||
626 | int parse_events_modifier(struct list_head *list, char *str) | 637 | struct event_modifier { |
638 | int eu; | ||
639 | int ek; | ||
640 | int eh; | ||
641 | int eH; | ||
642 | int eG; | ||
643 | int precise; | ||
644 | int exclude_GH; | ||
645 | }; | ||
646 | |||
647 | static int get_event_modifier(struct event_modifier *mod, char *str, | ||
648 | struct perf_evsel *evsel) | ||
627 | { | 649 | { |
628 | struct perf_evsel *evsel; | 650 | int eu = evsel ? evsel->attr.exclude_user : 0; |
629 | int exclude = 0, exclude_GH = 0; | 651 | int ek = evsel ? evsel->attr.exclude_kernel : 0; |
630 | int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0; | 652 | int eh = evsel ? evsel->attr.exclude_hv : 0; |
653 | int eH = evsel ? evsel->attr.exclude_host : 0; | ||
654 | int eG = evsel ? evsel->attr.exclude_guest : 0; | ||
655 | int precise = evsel ? evsel->attr.precise_ip : 0; | ||
631 | 656 | ||
632 | if (str == NULL) | 657 | int exclude = eu | ek | eh; |
633 | return 0; | 658 | int exclude_GH = evsel ? evsel->exclude_GH : 0; |
659 | |||
660 | /* | ||
661 | * We are here for group and 'GH' was not set as event | ||
662 | * modifier and whatever event/group modifier override | ||
663 | * default 'GH' setup. | ||
664 | */ | ||
665 | if (evsel && !exclude_GH) | ||
666 | eH = eG = 0; | ||
667 | |||
668 | memset(mod, 0, sizeof(*mod)); | ||
634 | 669 | ||
635 | while (*str) { | 670 | while (*str) { |
636 | if (*str == 'u') { | 671 | if (*str == 'u') { |
@@ -674,13 +709,51 @@ int parse_events_modifier(struct list_head *list, char *str) | |||
674 | if (precise > 3) | 709 | if (precise > 3) |
675 | return -EINVAL; | 710 | return -EINVAL; |
676 | 711 | ||
712 | mod->eu = eu; | ||
713 | mod->ek = ek; | ||
714 | mod->eh = eh; | ||
715 | mod->eH = eH; | ||
716 | mod->eG = eG; | ||
717 | mod->precise = precise; | ||
718 | mod->exclude_GH = exclude_GH; | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | int parse_events__modifier_event(struct list_head *list, char *str, bool add) | ||
723 | { | ||
724 | struct perf_evsel *evsel; | ||
725 | struct event_modifier mod; | ||
726 | |||
727 | if (str == NULL) | ||
728 | return 0; | ||
729 | |||
730 | if (!add && get_event_modifier(&mod, str, NULL)) | ||
731 | return -EINVAL; | ||
732 | |||
677 | list_for_each_entry(evsel, list, node) { | 733 | list_for_each_entry(evsel, list, node) { |
678 | evsel->attr.exclude_user = eu; | 734 | |
679 | evsel->attr.exclude_kernel = ek; | 735 | if (add && get_event_modifier(&mod, str, evsel)) |
680 | evsel->attr.exclude_hv = eh; | 736 | return -EINVAL; |
681 | evsel->attr.precise_ip = precise; | 737 | |
682 | evsel->attr.exclude_host = eH; | 738 | evsel->attr.exclude_user = mod.eu; |
683 | evsel->attr.exclude_guest = eG; | 739 | evsel->attr.exclude_kernel = mod.ek; |
740 | evsel->attr.exclude_hv = mod.eh; | ||
741 | evsel->attr.precise_ip = mod.precise; | ||
742 | evsel->attr.exclude_host = mod.eH; | ||
743 | evsel->attr.exclude_guest = mod.eG; | ||
744 | evsel->exclude_GH = mod.exclude_GH; | ||
745 | } | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | int parse_events_name(struct list_head *list, char *name) | ||
751 | { | ||
752 | struct perf_evsel *evsel; | ||
753 | |||
754 | list_for_each_entry(evsel, list, node) { | ||
755 | if (!evsel->name) | ||
756 | evsel->name = strdup(name); | ||
684 | } | 757 | } |
685 | 758 | ||
686 | return 0; | 759 | return 0; |
@@ -730,7 +803,8 @@ int parse_events_terms(struct list_head *terms, const char *str) | |||
730 | return ret; | 803 | return ret; |
731 | } | 804 | } |
732 | 805 | ||
733 | int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) | 806 | int parse_events(struct perf_evlist *evlist, const char *str, |
807 | int unset __maybe_unused) | ||
734 | { | 808 | { |
735 | struct parse_events_data__events data = { | 809 | struct parse_events_data__events data = { |
736 | .list = LIST_HEAD_INIT(data.list), | 810 | .list = LIST_HEAD_INIT(data.list), |
@@ -756,20 +830,20 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) | |||
756 | } | 830 | } |
757 | 831 | ||
758 | int parse_events_option(const struct option *opt, const char *str, | 832 | int parse_events_option(const struct option *opt, const char *str, |
759 | int unset __used) | 833 | int unset __maybe_unused) |
760 | { | 834 | { |
761 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | 835 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
762 | return parse_events(evlist, str, unset); | 836 | return parse_events(evlist, str, unset); |
763 | } | 837 | } |
764 | 838 | ||
765 | int parse_filter(const struct option *opt, const char *str, | 839 | int parse_filter(const struct option *opt, const char *str, |
766 | int unset __used) | 840 | int unset __maybe_unused) |
767 | { | 841 | { |
768 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | 842 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
769 | struct perf_evsel *last = NULL; | 843 | struct perf_evsel *last = NULL; |
770 | 844 | ||
771 | if (evlist->nr_entries > 0) | 845 | if (evlist->nr_entries > 0) |
772 | last = list_entry(evlist->entries.prev, struct perf_evsel, node); | 846 | last = perf_evlist__last(evlist); |
773 | 847 | ||
774 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { | 848 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { |
775 | fprintf(stderr, | 849 | fprintf(stderr, |
@@ -799,7 +873,8 @@ static const char * const event_type_descriptors[] = { | |||
799 | * Print the events from <debugfs_mount_point>/tracing/events | 873 | * Print the events from <debugfs_mount_point>/tracing/events |
800 | */ | 874 | */ |
801 | 875 | ||
802 | void print_tracepoint_events(const char *subsys_glob, const char *event_glob) | 876 | void print_tracepoint_events(const char *subsys_glob, const char *event_glob, |
877 | bool name_only) | ||
803 | { | 878 | { |
804 | DIR *sys_dir, *evt_dir; | 879 | DIR *sys_dir, *evt_dir; |
805 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 880 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; |
@@ -829,6 +904,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) | |||
829 | !strglobmatch(evt_dirent.d_name, event_glob)) | 904 | !strglobmatch(evt_dirent.d_name, event_glob)) |
830 | continue; | 905 | continue; |
831 | 906 | ||
907 | if (name_only) { | ||
908 | printf("%s:%s ", sys_dirent.d_name, evt_dirent.d_name); | ||
909 | continue; | ||
910 | } | ||
911 | |||
832 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 912 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
833 | sys_dirent.d_name, evt_dirent.d_name); | 913 | sys_dirent.d_name, evt_dirent.d_name); |
834 | printf(" %-50s [%s]\n", evt_path, | 914 | printf(" %-50s [%s]\n", evt_path, |
@@ -906,7 +986,7 @@ void print_events_type(u8 type) | |||
906 | __print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX); | 986 | __print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX); |
907 | } | 987 | } |
908 | 988 | ||
909 | int print_hwcache_events(const char *event_glob) | 989 | int print_hwcache_events(const char *event_glob, bool name_only) |
910 | { | 990 | { |
911 | unsigned int type, op, i, printed = 0; | 991 | unsigned int type, op, i, printed = 0; |
912 | char name[64]; | 992 | char name[64]; |
@@ -923,8 +1003,11 @@ int print_hwcache_events(const char *event_glob) | |||
923 | if (event_glob != NULL && !strglobmatch(name, event_glob)) | 1003 | if (event_glob != NULL && !strglobmatch(name, event_glob)) |
924 | continue; | 1004 | continue; |
925 | 1005 | ||
926 | printf(" %-50s [%s]\n", name, | 1006 | if (name_only) |
927 | event_type_descriptors[PERF_TYPE_HW_CACHE]); | 1007 | printf("%s ", name); |
1008 | else | ||
1009 | printf(" %-50s [%s]\n", name, | ||
1010 | event_type_descriptors[PERF_TYPE_HW_CACHE]); | ||
928 | ++printed; | 1011 | ++printed; |
929 | } | 1012 | } |
930 | } | 1013 | } |
@@ -934,7 +1017,8 @@ int print_hwcache_events(const char *event_glob) | |||
934 | } | 1017 | } |
935 | 1018 | ||
936 | static void print_symbol_events(const char *event_glob, unsigned type, | 1019 | static void print_symbol_events(const char *event_glob, unsigned type, |
937 | struct event_symbol *syms, unsigned max) | 1020 | struct event_symbol *syms, unsigned max, |
1021 | bool name_only) | ||
938 | { | 1022 | { |
939 | unsigned i, printed = 0; | 1023 | unsigned i, printed = 0; |
940 | char name[MAX_NAME_LEN]; | 1024 | char name[MAX_NAME_LEN]; |
@@ -946,6 +1030,11 @@ static void print_symbol_events(const char *event_glob, unsigned type, | |||
946 | (syms->alias && strglobmatch(syms->alias, event_glob)))) | 1030 | (syms->alias && strglobmatch(syms->alias, event_glob)))) |
947 | continue; | 1031 | continue; |
948 | 1032 | ||
1033 | if (name_only) { | ||
1034 | printf("%s ", syms->symbol); | ||
1035 | continue; | ||
1036 | } | ||
1037 | |||
949 | if (strlen(syms->alias)) | 1038 | if (strlen(syms->alias)) |
950 | snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); | 1039 | snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); |
951 | else | 1040 | else |
@@ -963,39 +1052,42 @@ static void print_symbol_events(const char *event_glob, unsigned type, | |||
963 | /* | 1052 | /* |
964 | * Print the help text for the event symbols: | 1053 | * Print the help text for the event symbols: |
965 | */ | 1054 | */ |
966 | void print_events(const char *event_glob) | 1055 | void print_events(const char *event_glob, bool name_only) |
967 | { | 1056 | { |
968 | 1057 | if (!name_only) { | |
969 | printf("\n"); | 1058 | printf("\n"); |
970 | printf("List of pre-defined events (to be used in -e):\n"); | 1059 | printf("List of pre-defined events (to be used in -e):\n"); |
1060 | } | ||
971 | 1061 | ||
972 | print_symbol_events(event_glob, PERF_TYPE_HARDWARE, | 1062 | print_symbol_events(event_glob, PERF_TYPE_HARDWARE, |
973 | event_symbols_hw, PERF_COUNT_HW_MAX); | 1063 | event_symbols_hw, PERF_COUNT_HW_MAX, name_only); |
974 | 1064 | ||
975 | print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, | 1065 | print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, |
976 | event_symbols_sw, PERF_COUNT_SW_MAX); | 1066 | event_symbols_sw, PERF_COUNT_SW_MAX, name_only); |
977 | 1067 | ||
978 | print_hwcache_events(event_glob); | 1068 | print_hwcache_events(event_glob, name_only); |
979 | 1069 | ||
980 | if (event_glob != NULL) | 1070 | if (event_glob != NULL) |
981 | return; | 1071 | return; |
982 | 1072 | ||
983 | printf("\n"); | 1073 | if (!name_only) { |
984 | printf(" %-50s [%s]\n", | 1074 | printf("\n"); |
985 | "rNNN", | 1075 | printf(" %-50s [%s]\n", |
986 | event_type_descriptors[PERF_TYPE_RAW]); | 1076 | "rNNN", |
987 | printf(" %-50s [%s]\n", | 1077 | event_type_descriptors[PERF_TYPE_RAW]); |
988 | "cpu/t1=v1[,t2=v2,t3 ...]/modifier", | 1078 | printf(" %-50s [%s]\n", |
989 | event_type_descriptors[PERF_TYPE_RAW]); | 1079 | "cpu/t1=v1[,t2=v2,t3 ...]/modifier", |
990 | printf(" (see 'perf list --help' on how to encode it)\n"); | 1080 | event_type_descriptors[PERF_TYPE_RAW]); |
991 | printf("\n"); | 1081 | printf(" (see 'perf list --help' on how to encode it)\n"); |
992 | 1082 | printf("\n"); | |
993 | printf(" %-50s [%s]\n", | 1083 | |
994 | "mem:<addr>[:access]", | 1084 | printf(" %-50s [%s]\n", |
1085 | "mem:<addr>[:access]", | ||
995 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); | 1086 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); |
996 | printf("\n"); | 1087 | printf("\n"); |
1088 | } | ||
997 | 1089 | ||
998 | print_tracepoint_events(NULL, NULL); | 1090 | print_tracepoint_events(NULL, NULL, name_only); |
999 | } | 1091 | } |
1000 | 1092 | ||
1001 | int parse_events__is_hardcoded_term(struct parse_events__term *term) | 1093 | int parse_events__is_hardcoded_term(struct parse_events__term *term) |
@@ -1005,7 +1097,7 @@ int parse_events__is_hardcoded_term(struct parse_events__term *term) | |||
1005 | 1097 | ||
1006 | static int new_term(struct parse_events__term **_term, int type_val, | 1098 | static int new_term(struct parse_events__term **_term, int type_val, |
1007 | int type_term, char *config, | 1099 | int type_term, char *config, |
1008 | char *str, long num) | 1100 | char *str, u64 num) |
1009 | { | 1101 | { |
1010 | struct parse_events__term *term; | 1102 | struct parse_events__term *term; |
1011 | 1103 | ||
@@ -1034,7 +1126,7 @@ static int new_term(struct parse_events__term **_term, int type_val, | |||
1034 | } | 1126 | } |
1035 | 1127 | ||
1036 | int parse_events__term_num(struct parse_events__term **term, | 1128 | int parse_events__term_num(struct parse_events__term **term, |
1037 | int type_term, char *config, long num) | 1129 | int type_term, char *config, u64 num) |
1038 | { | 1130 | { |
1039 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, | 1131 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, |
1040 | config, NULL, num); | 1132 | config, NULL, num); |