diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 230 |
1 files changed, 130 insertions, 100 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5cb6f4bde905..952b4ae3d954 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; |
@@ -266,11 +263,36 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) | |||
266 | return name; | 263 | return name; |
267 | } | 264 | } |
268 | 265 | ||
266 | const char *event_type(int type) | ||
267 | { | ||
268 | switch (type) { | ||
269 | case PERF_TYPE_HARDWARE: | ||
270 | return "hardware"; | ||
271 | |||
272 | case PERF_TYPE_SOFTWARE: | ||
273 | return "software"; | ||
274 | |||
275 | case PERF_TYPE_TRACEPOINT: | ||
276 | return "tracepoint"; | ||
277 | |||
278 | case PERF_TYPE_HW_CACHE: | ||
279 | return "hardware-cache"; | ||
280 | |||
281 | default: | ||
282 | break; | ||
283 | } | ||
284 | |||
285 | return "unknown"; | ||
286 | } | ||
287 | |||
269 | const char *event_name(struct perf_evsel *evsel) | 288 | const char *event_name(struct perf_evsel *evsel) |
270 | { | 289 | { |
271 | u64 config = evsel->attr.config; | 290 | u64 config = evsel->attr.config; |
272 | int type = evsel->attr.type; | 291 | int type = evsel->attr.type; |
273 | 292 | ||
293 | if (evsel->name) | ||
294 | return evsel->name; | ||
295 | |||
274 | return __event_name(type, config); | 296 | return __event_name(type, config); |
275 | } | 297 | } |
276 | 298 | ||
@@ -279,7 +301,7 @@ const char *__event_name(int type, u64 config) | |||
279 | static char buf[32]; | 301 | static char buf[32]; |
280 | 302 | ||
281 | if (type == PERF_TYPE_RAW) { | 303 | if (type == PERF_TYPE_RAW) { |
282 | sprintf(buf, "raw 0x%llx", config); | 304 | sprintf(buf, "raw 0x%" PRIx64, config); |
283 | return buf; | 305 | return buf; |
284 | } | 306 | } |
285 | 307 | ||
@@ -449,8 +471,8 @@ parse_single_tracepoint_event(char *sys_name, | |||
449 | /* sys + ':' + event + ':' + flags*/ | 471 | /* sys + ':' + event + ':' + flags*/ |
450 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) | 472 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) |
451 | static enum event_result | 473 | static enum event_result |
452 | parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, | 474 | parse_multiple_tracepoint_event(const struct option *opt, char *sys_name, |
453 | char *flags) | 475 | const char *evt_exp, char *flags) |
454 | { | 476 | { |
455 | char evt_path[MAXPATHLEN]; | 477 | char evt_path[MAXPATHLEN]; |
456 | struct dirent *evt_ent; | 478 | struct dirent *evt_ent; |
@@ -483,41 +505,16 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, | |||
483 | if (len < 0) | 505 | if (len < 0) |
484 | return EVT_FAILED; | 506 | return EVT_FAILED; |
485 | 507 | ||
486 | if (parse_events(NULL, event_opt, 0)) | 508 | if (parse_events(opt, event_opt, 0)) |
487 | return EVT_FAILED; | 509 | return EVT_FAILED; |
488 | } | 510 | } |
489 | 511 | ||
490 | return EVT_HANDLED_ALL; | 512 | return EVT_HANDLED_ALL; |
491 | } | 513 | } |
492 | 514 | ||
493 | static int store_event_type(const char *orgname) | 515 | static enum event_result |
494 | { | 516 | parse_tracepoint_event(const struct option *opt, const char **strp, |
495 | char filename[PATH_MAX], *c; | 517 | struct perf_event_attr *attr) |
496 | FILE *file; | ||
497 | int id, n; | ||
498 | |||
499 | sprintf(filename, "%s/", debugfs_path); | ||
500 | strncat(filename, orgname, strlen(orgname)); | ||
501 | strcat(filename, "/id"); | ||
502 | |||
503 | c = strchr(filename, ':'); | ||
504 | if (c) | ||
505 | *c = '/'; | ||
506 | |||
507 | file = fopen(filename, "r"); | ||
508 | if (!file) | ||
509 | return 0; | ||
510 | n = fscanf(file, "%i", &id); | ||
511 | fclose(file); | ||
512 | if (n < 1) { | ||
513 | pr_err("cannot store event ID\n"); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | return perf_header__push_event(id, orgname); | ||
517 | } | ||
518 | |||
519 | static enum event_result parse_tracepoint_event(const char **strp, | ||
520 | struct perf_event_attr *attr) | ||
521 | { | 518 | { |
522 | const char *evt_name; | 519 | const char *evt_name; |
523 | char *flags = NULL, *comma_loc; | 520 | char *flags = NULL, *comma_loc; |
@@ -555,13 +552,10 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
555 | if (evt_length >= MAX_EVENT_LENGTH) | 552 | if (evt_length >= MAX_EVENT_LENGTH) |
556 | return EVT_FAILED; | 553 | return EVT_FAILED; |
557 | if (strpbrk(evt_name, "*?")) { | 554 | if (strpbrk(evt_name, "*?")) { |
558 | *strp += strlen(sys_name) + evt_length; | 555 | *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ |
559 | return parse_multiple_tracepoint_event(sys_name, evt_name, | 556 | return parse_multiple_tracepoint_event(opt, sys_name, evt_name, |
560 | flags); | 557 | flags); |
561 | } else { | 558 | } else { |
562 | if (store_event_type(evt_name) < 0) | ||
563 | return EVT_FAILED; | ||
564 | |||
565 | return parse_single_tracepoint_event(sys_name, evt_name, | 559 | return parse_single_tracepoint_event(sys_name, evt_name, |
566 | evt_length, attr, strp); | 560 | evt_length, attr, strp); |
567 | } | 561 | } |
@@ -769,11 +763,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) | |||
769 | * Symbolic names are (almost) exactly matched. | 763 | * Symbolic names are (almost) exactly matched. |
770 | */ | 764 | */ |
771 | static enum event_result | 765 | static enum event_result |
772 | parse_event_symbols(const char **str, struct perf_event_attr *attr) | 766 | parse_event_symbols(const struct option *opt, const char **str, |
767 | struct perf_event_attr *attr) | ||
773 | { | 768 | { |
774 | enum event_result ret; | 769 | enum event_result ret; |
775 | 770 | ||
776 | ret = parse_tracepoint_event(str, attr); | 771 | ret = parse_tracepoint_event(opt, str, attr); |
777 | if (ret != EVT_FAILED) | 772 | if (ret != EVT_FAILED) |
778 | goto modifier; | 773 | goto modifier; |
779 | 774 | ||
@@ -807,14 +802,17 @@ modifier: | |||
807 | return ret; | 802 | return ret; |
808 | } | 803 | } |
809 | 804 | ||
810 | int parse_events(const struct option *opt __used, const char *str, int unset __used) | 805 | int parse_events(const struct option *opt, const char *str, int unset __used) |
811 | { | 806 | { |
807 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | ||
812 | struct perf_event_attr attr; | 808 | struct perf_event_attr attr; |
813 | enum event_result ret; | 809 | enum event_result ret; |
810 | const char *ostr; | ||
814 | 811 | ||
815 | for (;;) { | 812 | for (;;) { |
813 | ostr = str; | ||
816 | memset(&attr, 0, sizeof(attr)); | 814 | memset(&attr, 0, sizeof(attr)); |
817 | ret = parse_event_symbols(&str, &attr); | 815 | ret = parse_event_symbols(opt, &str, &attr); |
818 | if (ret == EVT_FAILED) | 816 | if (ret == EVT_FAILED) |
819 | return -1; | 817 | return -1; |
820 | 818 | ||
@@ -823,12 +821,15 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
823 | 821 | ||
824 | if (ret != EVT_HANDLED_ALL) { | 822 | if (ret != EVT_HANDLED_ALL) { |
825 | struct perf_evsel *evsel; | 823 | struct perf_evsel *evsel; |
826 | evsel = perf_evsel__new(&attr, | 824 | evsel = perf_evsel__new(&attr, evlist->nr_entries); |
827 | nr_counters); | ||
828 | if (evsel == NULL) | 825 | if (evsel == NULL) |
829 | return -1; | 826 | return -1; |
830 | list_add_tail(&evsel->node, &evsel_list); | 827 | perf_evlist__add(evlist, evsel); |
831 | ++nr_counters; | 828 | |
829 | evsel->name = calloc(str - ostr + 1, 1); | ||
830 | if (!evsel->name) | ||
831 | return -1; | ||
832 | strncpy(evsel->name, ostr, str - ostr); | ||
832 | } | 833 | } |
833 | 834 | ||
834 | if (*str == 0) | 835 | if (*str == 0) |
@@ -842,13 +843,14 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
842 | return 0; | 843 | return 0; |
843 | } | 844 | } |
844 | 845 | ||
845 | int parse_filter(const struct option *opt __used, const char *str, | 846 | int parse_filter(const struct option *opt, const char *str, |
846 | int unset __used) | 847 | int unset __used) |
847 | { | 848 | { |
849 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | ||
848 | struct perf_evsel *last = NULL; | 850 | struct perf_evsel *last = NULL; |
849 | 851 | ||
850 | if (!list_empty(&evsel_list)) | 852 | if (evlist->nr_entries > 0) |
851 | last = list_entry(evsel_list.prev, struct perf_evsel, node); | 853 | last = list_entry(evlist->entries.prev, struct perf_evsel, node); |
852 | 854 | ||
853 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { | 855 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { |
854 | fprintf(stderr, | 856 | fprintf(stderr, |
@@ -878,7 +880,7 @@ static const char * const event_type_descriptors[] = { | |||
878 | * Print the events from <debugfs_mount_point>/tracing/events | 880 | * Print the events from <debugfs_mount_point>/tracing/events |
879 | */ | 881 | */ |
880 | 882 | ||
881 | static void print_tracepoint_events(void) | 883 | void print_tracepoint_events(const char *subsys_glob, const char *event_glob) |
882 | { | 884 | { |
883 | DIR *sys_dir, *evt_dir; | 885 | DIR *sys_dir, *evt_dir; |
884 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 886 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; |
@@ -893,6 +895,9 @@ static void print_tracepoint_events(void) | |||
893 | return; | 895 | return; |
894 | 896 | ||
895 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 897 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { |
898 | if (subsys_glob != NULL && | ||
899 | !strglobmatch(sys_dirent.d_name, subsys_glob)) | ||
900 | continue; | ||
896 | 901 | ||
897 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, | 902 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, |
898 | sys_dirent.d_name); | 903 | sys_dirent.d_name); |
@@ -901,6 +906,10 @@ static void print_tracepoint_events(void) | |||
901 | continue; | 906 | continue; |
902 | 907 | ||
903 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 908 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { |
909 | if (event_glob != NULL && | ||
910 | !strglobmatch(evt_dirent.d_name, event_glob)) | ||
911 | continue; | ||
912 | |||
904 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 913 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
905 | sys_dirent.d_name, evt_dirent.d_name); | 914 | sys_dirent.d_name, evt_dirent.d_name); |
906 | printf(" %-42s [%s]\n", evt_path, | 915 | printf(" %-42s [%s]\n", evt_path, |
@@ -952,13 +961,61 @@ int is_valid_tracepoint(const char *event_string) | |||
952 | return 0; | 961 | return 0; |
953 | } | 962 | } |
954 | 963 | ||
964 | void print_events_type(u8 type) | ||
965 | { | ||
966 | struct event_symbol *syms = event_symbols; | ||
967 | unsigned int i; | ||
968 | char name[64]; | ||
969 | |||
970 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | ||
971 | if (type != syms->type) | ||
972 | continue; | ||
973 | |||
974 | if (strlen(syms->alias)) | ||
975 | snprintf(name, sizeof(name), "%s OR %s", | ||
976 | syms->symbol, syms->alias); | ||
977 | else | ||
978 | snprintf(name, sizeof(name), "%s", syms->symbol); | ||
979 | |||
980 | printf(" %-42s [%s]\n", name, | ||
981 | event_type_descriptors[type]); | ||
982 | } | ||
983 | } | ||
984 | |||
985 | int print_hwcache_events(const char *event_glob) | ||
986 | { | ||
987 | unsigned int type, op, i, printed = 0; | ||
988 | |||
989 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { | ||
990 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { | ||
991 | /* skip invalid cache type */ | ||
992 | if (!is_cache_op_valid(type, op)) | ||
993 | continue; | ||
994 | |||
995 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | ||
996 | char *name = event_cache_name(type, op, i); | ||
997 | |||
998 | if (event_glob != NULL && | ||
999 | !strglobmatch(name, event_glob)) | ||
1000 | continue; | ||
1001 | |||
1002 | printf(" %-42s [%s]\n", name, | ||
1003 | event_type_descriptors[PERF_TYPE_HW_CACHE]); | ||
1004 | ++printed; | ||
1005 | } | ||
1006 | } | ||
1007 | } | ||
1008 | |||
1009 | return printed; | ||
1010 | } | ||
1011 | |||
955 | /* | 1012 | /* |
956 | * Print the help text for the event symbols: | 1013 | * Print the help text for the event symbols: |
957 | */ | 1014 | */ |
958 | void print_events(void) | 1015 | void print_events(const char *event_glob) |
959 | { | 1016 | { |
960 | struct event_symbol *syms = event_symbols; | 1017 | struct event_symbol *syms = event_symbols; |
961 | unsigned int i, type, op, prev_type = -1; | 1018 | unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0; |
962 | char name[40]; | 1019 | char name[40]; |
963 | 1020 | ||
964 | printf("\n"); | 1021 | printf("\n"); |
@@ -967,8 +1024,16 @@ void print_events(void) | |||
967 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | 1024 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { |
968 | type = syms->type; | 1025 | type = syms->type; |
969 | 1026 | ||
970 | if (type != prev_type) | 1027 | if (type != prev_type && printed) { |
971 | printf("\n"); | 1028 | printf("\n"); |
1029 | printed = 0; | ||
1030 | ntypes_printed++; | ||
1031 | } | ||
1032 | |||
1033 | if (event_glob != NULL && | ||
1034 | !(strglobmatch(syms->symbol, event_glob) || | ||
1035 | (syms->alias && strglobmatch(syms->alias, event_glob)))) | ||
1036 | continue; | ||
972 | 1037 | ||
973 | if (strlen(syms->alias)) | 1038 | if (strlen(syms->alias)) |
974 | sprintf(name, "%s OR %s", syms->symbol, syms->alias); | 1039 | sprintf(name, "%s OR %s", syms->symbol, syms->alias); |
@@ -978,22 +1043,17 @@ void print_events(void) | |||
978 | event_type_descriptors[type]); | 1043 | event_type_descriptors[type]); |
979 | 1044 | ||
980 | prev_type = type; | 1045 | prev_type = type; |
1046 | ++printed; | ||
981 | } | 1047 | } |
982 | 1048 | ||
983 | printf("\n"); | 1049 | if (ntypes_printed) { |
984 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { | 1050 | printed = 0; |
985 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { | 1051 | printf("\n"); |
986 | /* skip invalid cache type */ | ||
987 | if (!is_cache_op_valid(type, op)) | ||
988 | continue; | ||
989 | |||
990 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | ||
991 | printf(" %-42s [%s]\n", | ||
992 | event_cache_name(type, op, i), | ||
993 | event_type_descriptors[PERF_TYPE_HW_CACHE]); | ||
994 | } | ||
995 | } | ||
996 | } | 1052 | } |
1053 | print_hwcache_events(event_glob); | ||
1054 | |||
1055 | if (event_glob != NULL) | ||
1056 | return; | ||
997 | 1057 | ||
998 | printf("\n"); | 1058 | printf("\n"); |
999 | printf(" %-42s [%s]\n", | 1059 | printf(" %-42s [%s]\n", |
@@ -1006,37 +1066,7 @@ void print_events(void) | |||
1006 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); | 1066 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); |
1007 | printf("\n"); | 1067 | printf("\n"); |
1008 | 1068 | ||
1009 | print_tracepoint_events(); | 1069 | print_tracepoint_events(NULL, NULL); |
1010 | 1070 | ||
1011 | exit(129); | 1071 | exit(129); |
1012 | } | 1072 | } |
1013 | |||
1014 | int perf_evsel_list__create_default(void) | ||
1015 | { | ||
1016 | struct perf_evsel *evsel; | ||
1017 | struct perf_event_attr attr; | ||
1018 | |||
1019 | memset(&attr, 0, sizeof(attr)); | ||
1020 | attr.type = PERF_TYPE_HARDWARE; | ||
1021 | attr.config = PERF_COUNT_HW_CPU_CYCLES; | ||
1022 | |||
1023 | evsel = perf_evsel__new(&attr, 0); | ||
1024 | |||
1025 | if (evsel == NULL) | ||
1026 | return -ENOMEM; | ||
1027 | |||
1028 | list_add(&evsel->node, &evsel_list); | ||
1029 | ++nr_counters; | ||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | void perf_evsel_list__delete(void) | ||
1034 | { | ||
1035 | struct perf_evsel *pos, *n; | ||
1036 | |||
1037 | list_for_each_entry_safe(pos, n, &evsel_list, node) { | ||
1038 | list_del_init(&pos->node); | ||
1039 | perf_evsel__delete(pos); | ||
1040 | } | ||
1041 | nr_counters = 0; | ||
1042 | } | ||