diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
| -rw-r--r-- | tools/perf/util/parse-events.c | 175 |
1 files changed, 106 insertions, 69 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 135f69baf96..54a7e2634d5 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #include "../../../include/linux/hw_breakpoint.h" | 1 | #include "../../../include/linux/hw_breakpoint.h" |
| 2 | #include "util.h" | 2 | #include "util.h" |
| 3 | #include "../perf.h" | 3 | #include "../perf.h" |
| 4 | #include "evlist.h" | ||
| 4 | #include "evsel.h" | 5 | #include "evsel.h" |
| 5 | #include "parse-options.h" | 6 | #include "parse-options.h" |
| 6 | #include "parse-events.h" | 7 | #include "parse-events.h" |
| @@ -11,10 +12,6 @@ | |||
| 11 | #include "header.h" | 12 | #include "header.h" |
| 12 | #include "debugfs.h" | 13 | #include "debugfs.h" |
| 13 | 14 | ||
| 14 | int nr_counters; | ||
| 15 | |||
| 16 | LIST_HEAD(evsel_list); | ||
| 17 | |||
| 18 | struct event_symbol { | 15 | struct event_symbol { |
| 19 | u8 type; | 16 | u8 type; |
| 20 | u64 config; | 17 | u64 config; |
| @@ -271,6 +268,9 @@ const char *event_name(struct perf_evsel *evsel) | |||
| 271 | u64 config = evsel->attr.config; | 268 | u64 config = evsel->attr.config; |
| 272 | int type = evsel->attr.type; | 269 | int type = evsel->attr.type; |
| 273 | 270 | ||
| 271 | if (evsel->name) | ||
| 272 | return evsel->name; | ||
| 273 | |||
| 274 | return __event_name(type, config); | 274 | return __event_name(type, config); |
| 275 | } | 275 | } |
| 276 | 276 | ||
| @@ -449,8 +449,8 @@ parse_single_tracepoint_event(char *sys_name, | |||
| 449 | /* sys + ':' + event + ':' + flags*/ | 449 | /* sys + ':' + event + ':' + flags*/ |
| 450 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) | 450 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) |
| 451 | static enum event_result | 451 | static enum event_result |
| 452 | parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, | 452 | parse_multiple_tracepoint_event(const struct option *opt, char *sys_name, |
| 453 | char *flags) | 453 | const char *evt_exp, char *flags) |
| 454 | { | 454 | { |
| 455 | char evt_path[MAXPATHLEN]; | 455 | char evt_path[MAXPATHLEN]; |
| 456 | struct dirent *evt_ent; | 456 | struct dirent *evt_ent; |
| @@ -483,15 +483,16 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, | |||
| 483 | if (len < 0) | 483 | if (len < 0) |
| 484 | return EVT_FAILED; | 484 | return EVT_FAILED; |
| 485 | 485 | ||
| 486 | if (parse_events(NULL, event_opt, 0)) | 486 | if (parse_events(opt, event_opt, 0)) |
| 487 | return EVT_FAILED; | 487 | return EVT_FAILED; |
| 488 | } | 488 | } |
| 489 | 489 | ||
| 490 | return EVT_HANDLED_ALL; | 490 | return EVT_HANDLED_ALL; |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | static enum event_result parse_tracepoint_event(const char **strp, | 493 | static enum event_result |
| 494 | struct perf_event_attr *attr) | 494 | parse_tracepoint_event(const struct option *opt, const char **strp, |
| 495 | struct perf_event_attr *attr) | ||
| 495 | { | 496 | { |
| 496 | const char *evt_name; | 497 | const char *evt_name; |
| 497 | char *flags = NULL, *comma_loc; | 498 | char *flags = NULL, *comma_loc; |
| @@ -530,7 +531,7 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
| 530 | return EVT_FAILED; | 531 | return EVT_FAILED; |
| 531 | if (strpbrk(evt_name, "*?")) { | 532 | if (strpbrk(evt_name, "*?")) { |
| 532 | *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ | 533 | *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ |
| 533 | return parse_multiple_tracepoint_event(sys_name, evt_name, | 534 | return parse_multiple_tracepoint_event(opt, sys_name, evt_name, |
| 534 | flags); | 535 | flags); |
| 535 | } else { | 536 | } else { |
| 536 | return parse_single_tracepoint_event(sys_name, evt_name, | 537 | return parse_single_tracepoint_event(sys_name, evt_name, |
| @@ -740,11 +741,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) | |||
| 740 | * Symbolic names are (almost) exactly matched. | 741 | * Symbolic names are (almost) exactly matched. |
| 741 | */ | 742 | */ |
| 742 | static enum event_result | 743 | static enum event_result |
| 743 | parse_event_symbols(const char **str, struct perf_event_attr *attr) | 744 | parse_event_symbols(const struct option *opt, const char **str, |
| 745 | struct perf_event_attr *attr) | ||
| 744 | { | 746 | { |
| 745 | enum event_result ret; | 747 | enum event_result ret; |
| 746 | 748 | ||
| 747 | ret = parse_tracepoint_event(str, attr); | 749 | ret = parse_tracepoint_event(opt, str, attr); |
| 748 | if (ret != EVT_FAILED) | 750 | if (ret != EVT_FAILED) |
| 749 | goto modifier; | 751 | goto modifier; |
| 750 | 752 | ||
| @@ -778,14 +780,17 @@ modifier: | |||
| 778 | return ret; | 780 | return ret; |
| 779 | } | 781 | } |
| 780 | 782 | ||
| 781 | int parse_events(const struct option *opt __used, const char *str, int unset __used) | 783 | int parse_events(const struct option *opt, const char *str, int unset __used) |
| 782 | { | 784 | { |
| 785 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | ||
| 783 | struct perf_event_attr attr; | 786 | struct perf_event_attr attr; |
| 784 | enum event_result ret; | 787 | enum event_result ret; |
| 788 | const char *ostr; | ||
| 785 | 789 | ||
| 786 | for (;;) { | 790 | for (;;) { |
| 791 | ostr = str; | ||
| 787 | memset(&attr, 0, sizeof(attr)); | 792 | memset(&attr, 0, sizeof(attr)); |
| 788 | ret = parse_event_symbols(&str, &attr); | 793 | ret = parse_event_symbols(opt, &str, &attr); |
| 789 | if (ret == EVT_FAILED) | 794 | if (ret == EVT_FAILED) |
| 790 | return -1; | 795 | return -1; |
| 791 | 796 | ||
| @@ -794,12 +799,15 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
| 794 | 799 | ||
| 795 | if (ret != EVT_HANDLED_ALL) { | 800 | if (ret != EVT_HANDLED_ALL) { |
| 796 | struct perf_evsel *evsel; | 801 | struct perf_evsel *evsel; |
| 797 | evsel = perf_evsel__new(&attr, | 802 | evsel = perf_evsel__new(&attr, evlist->nr_entries); |
| 798 | nr_counters); | ||
| 799 | if (evsel == NULL) | 803 | if (evsel == NULL) |
| 800 | return -1; | 804 | return -1; |
| 801 | list_add_tail(&evsel->node, &evsel_list); | 805 | perf_evlist__add(evlist, evsel); |
| 802 | ++nr_counters; | 806 | |
| 807 | evsel->name = calloc(str - ostr + 1, 1); | ||
| 808 | if (!evsel->name) | ||
| 809 | return -1; | ||
| 810 | strncpy(evsel->name, ostr, str - ostr); | ||
| 803 | } | 811 | } |
| 804 | 812 | ||
| 805 | if (*str == 0) | 813 | if (*str == 0) |
| @@ -813,13 +821,14 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
| 813 | return 0; | 821 | return 0; |
| 814 | } | 822 | } |
| 815 | 823 | ||
| 816 | int parse_filter(const struct option *opt __used, const char *str, | 824 | int parse_filter(const struct option *opt, const char *str, |
| 817 | int unset __used) | 825 | int unset __used) |
| 818 | { | 826 | { |
| 827 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | ||
| 819 | struct perf_evsel *last = NULL; | 828 | struct perf_evsel *last = NULL; |
| 820 | 829 | ||
| 821 | if (!list_empty(&evsel_list)) | 830 | if (evlist->nr_entries > 0) |
| 822 | last = list_entry(evsel_list.prev, struct perf_evsel, node); | 831 | last = list_entry(evlist->entries.prev, struct perf_evsel, node); |
| 823 | 832 | ||
| 824 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { | 833 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { |
| 825 | fprintf(stderr, | 834 | fprintf(stderr, |
| @@ -849,7 +858,7 @@ static const char * const event_type_descriptors[] = { | |||
| 849 | * Print the events from <debugfs_mount_point>/tracing/events | 858 | * Print the events from <debugfs_mount_point>/tracing/events |
| 850 | */ | 859 | */ |
| 851 | 860 | ||
| 852 | static void print_tracepoint_events(void) | 861 | void print_tracepoint_events(const char *subsys_glob, const char *event_glob) |
| 853 | { | 862 | { |
| 854 | DIR *sys_dir, *evt_dir; | 863 | DIR *sys_dir, *evt_dir; |
| 855 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 864 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; |
| @@ -864,6 +873,9 @@ static void print_tracepoint_events(void) | |||
| 864 | return; | 873 | return; |
| 865 | 874 | ||
| 866 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 875 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { |
| 876 | if (subsys_glob != NULL && | ||
| 877 | !strglobmatch(sys_dirent.d_name, subsys_glob)) | ||
| 878 | continue; | ||
| 867 | 879 | ||
| 868 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, | 880 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, |
| 869 | sys_dirent.d_name); | 881 | sys_dirent.d_name); |
| @@ -872,6 +884,10 @@ static void print_tracepoint_events(void) | |||
| 872 | continue; | 884 | continue; |
| 873 | 885 | ||
| 874 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 886 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { |
| 887 | if (event_glob != NULL && | ||
| 888 | !strglobmatch(evt_dirent.d_name, event_glob)) | ||
| 889 | continue; | ||
| 890 | |||
| 875 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 891 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
| 876 | sys_dirent.d_name, evt_dirent.d_name); | 892 | sys_dirent.d_name, evt_dirent.d_name); |
| 877 | printf(" %-42s [%s]\n", evt_path, | 893 | printf(" %-42s [%s]\n", evt_path, |
| @@ -923,13 +939,61 @@ int is_valid_tracepoint(const char *event_string) | |||
| 923 | return 0; | 939 | return 0; |
| 924 | } | 940 | } |
| 925 | 941 | ||
| 942 | void print_events_type(u8 type) | ||
| 943 | { | ||
| 944 | struct event_symbol *syms = event_symbols; | ||
| 945 | unsigned int i; | ||
| 946 | char name[64]; | ||
| 947 | |||
| 948 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | ||
| 949 | if (type != syms->type) | ||
| 950 | continue; | ||
| 951 | |||
| 952 | if (strlen(syms->alias)) | ||
| 953 | snprintf(name, sizeof(name), "%s OR %s", | ||
| 954 | syms->symbol, syms->alias); | ||
| 955 | else | ||
| 956 | snprintf(name, sizeof(name), "%s", syms->symbol); | ||
| 957 | |||
| 958 | printf(" %-42s [%s]\n", name, | ||
| 959 | event_type_descriptors[type]); | ||
| 960 | } | ||
| 961 | } | ||
| 962 | |||
| 963 | int print_hwcache_events(const char *event_glob) | ||
| 964 | { | ||
| 965 | unsigned int type, op, i, printed = 0; | ||
| 966 | |||
| 967 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { | ||
| 968 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { | ||
| 969 | /* skip invalid cache type */ | ||
| 970 | if (!is_cache_op_valid(type, op)) | ||
| 971 | continue; | ||
| 972 | |||
| 973 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | ||
| 974 | char *name = event_cache_name(type, op, i); | ||
| 975 | |||
| 976 | if (event_glob != NULL && | ||
| 977 | !strglobmatch(name, event_glob)) | ||
| 978 | continue; | ||
| 979 | |||
| 980 | printf(" %-42s [%s]\n", name, | ||
| 981 | event_type_descriptors[PERF_TYPE_HW_CACHE]); | ||
| 982 | ++printed; | ||
| 983 | } | ||
| 984 | } | ||
| 985 | } | ||
| 986 | |||
| 987 | return printed; | ||
| 988 | } | ||
| 989 | |||
| 926 | /* | 990 | /* |
| 927 | * Print the help text for the event symbols: | 991 | * Print the help text for the event symbols: |
| 928 | */ | 992 | */ |
| 929 | void print_events(void) | 993 | void print_events(const char *event_glob) |
| 930 | { | 994 | { |
| 931 | struct event_symbol *syms = event_symbols; | 995 | struct event_symbol *syms = event_symbols; |
| 932 | unsigned int i, type, op, prev_type = -1; | 996 | unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0; |
| 933 | char name[40]; | 997 | char name[40]; |
| 934 | 998 | ||
| 935 | printf("\n"); | 999 | printf("\n"); |
| @@ -938,8 +1002,16 @@ void print_events(void) | |||
| 938 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | 1002 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { |
| 939 | type = syms->type; | 1003 | type = syms->type; |
| 940 | 1004 | ||
| 941 | if (type != prev_type) | 1005 | if (type != prev_type && printed) { |
| 942 | printf("\n"); | 1006 | printf("\n"); |
| 1007 | printed = 0; | ||
| 1008 | ntypes_printed++; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | if (event_glob != NULL && | ||
| 1012 | !(strglobmatch(syms->symbol, event_glob) || | ||
| 1013 | (syms->alias && strglobmatch(syms->alias, event_glob)))) | ||
| 1014 | continue; | ||
| 943 | 1015 | ||
| 944 | if (strlen(syms->alias)) | 1016 | if (strlen(syms->alias)) |
| 945 | sprintf(name, "%s OR %s", syms->symbol, syms->alias); | 1017 | sprintf(name, "%s OR %s", syms->symbol, syms->alias); |
| @@ -949,22 +1021,17 @@ void print_events(void) | |||
| 949 | event_type_descriptors[type]); | 1021 | event_type_descriptors[type]); |
| 950 | 1022 | ||
| 951 | prev_type = type; | 1023 | prev_type = type; |
| 1024 | ++printed; | ||
| 952 | } | 1025 | } |
| 953 | 1026 | ||
| 954 | printf("\n"); | 1027 | if (ntypes_printed) { |
| 955 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { | 1028 | printed = 0; |
| 956 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { | 1029 | printf("\n"); |
| 957 | /* skip invalid cache type */ | ||
| 958 | if (!is_cache_op_valid(type, op)) | ||
| 959 | continue; | ||
| 960 | |||
| 961 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | ||
| 962 | printf(" %-42s [%s]\n", | ||
| 963 | event_cache_name(type, op, i), | ||
| 964 | event_type_descriptors[PERF_TYPE_HW_CACHE]); | ||
| 965 | } | ||
| 966 | } | ||
| 967 | } | 1030 | } |
| 1031 | print_hwcache_events(event_glob); | ||
| 1032 | |||
| 1033 | if (event_glob != NULL) | ||
| 1034 | return; | ||
| 968 | 1035 | ||
| 969 | printf("\n"); | 1036 | printf("\n"); |
| 970 | printf(" %-42s [%s]\n", | 1037 | printf(" %-42s [%s]\n", |
| @@ -977,37 +1044,7 @@ void print_events(void) | |||
| 977 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); | 1044 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); |
| 978 | printf("\n"); | 1045 | printf("\n"); |
| 979 | 1046 | ||
| 980 | print_tracepoint_events(); | 1047 | print_tracepoint_events(NULL, NULL); |
| 981 | 1048 | ||
| 982 | exit(129); | 1049 | exit(129); |
| 983 | } | 1050 | } |
| 984 | |||
| 985 | int perf_evsel_list__create_default(void) | ||
| 986 | { | ||
| 987 | struct perf_evsel *evsel; | ||
| 988 | struct perf_event_attr attr; | ||
| 989 | |||
| 990 | memset(&attr, 0, sizeof(attr)); | ||
| 991 | attr.type = PERF_TYPE_HARDWARE; | ||
| 992 | attr.config = PERF_COUNT_HW_CPU_CYCLES; | ||
| 993 | |||
| 994 | evsel = perf_evsel__new(&attr, 0); | ||
| 995 | |||
| 996 | if (evsel == NULL) | ||
| 997 | return -ENOMEM; | ||
| 998 | |||
| 999 | list_add(&evsel->node, &evsel_list); | ||
| 1000 | ++nr_counters; | ||
| 1001 | return 0; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | void perf_evsel_list__delete(void) | ||
| 1005 | { | ||
| 1006 | struct perf_evsel *pos, *n; | ||
| 1007 | |||
| 1008 | list_for_each_entry_safe(pos, n, &evsel_list, node) { | ||
| 1009 | list_del_init(&pos->node); | ||
| 1010 | perf_evsel__delete(pos); | ||
| 1011 | } | ||
| 1012 | nr_counters = 0; | ||
| 1013 | } | ||
