diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 111 |
1 files changed, 91 insertions, 20 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4af5bd59cfd1..649083f27e08 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 "evsel.h" | ||
4 | #include "parse-options.h" | 5 | #include "parse-options.h" |
5 | #include "parse-events.h" | 6 | #include "parse-events.h" |
6 | #include "exec_cmd.h" | 7 | #include "exec_cmd.h" |
@@ -12,8 +13,7 @@ | |||
12 | 13 | ||
13 | int nr_counters; | 14 | int nr_counters; |
14 | 15 | ||
15 | struct perf_event_attr attrs[MAX_COUNTERS]; | 16 | LIST_HEAD(evsel_list); |
16 | char *filters[MAX_COUNTERS]; | ||
17 | 17 | ||
18 | struct event_symbol { | 18 | struct event_symbol { |
19 | u8 type; | 19 | u8 type; |
@@ -266,10 +266,10 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) | |||
266 | return name; | 266 | return name; |
267 | } | 267 | } |
268 | 268 | ||
269 | const char *event_name(int counter) | 269 | const char *event_name(struct perf_evsel *evsel) |
270 | { | 270 | { |
271 | u64 config = attrs[counter].config; | 271 | u64 config = evsel->attr.config; |
272 | int type = attrs[counter].type; | 272 | int type = evsel->attr.type; |
273 | 273 | ||
274 | return __event_name(type, config); | 274 | return __event_name(type, config); |
275 | } | 275 | } |
@@ -434,7 +434,7 @@ parse_single_tracepoint_event(char *sys_name, | |||
434 | id = atoll(id_buf); | 434 | id = atoll(id_buf); |
435 | attr->config = id; | 435 | attr->config = id; |
436 | attr->type = PERF_TYPE_TRACEPOINT; | 436 | attr->type = PERF_TYPE_TRACEPOINT; |
437 | *strp = evt_name + evt_length; | 437 | *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */ |
438 | 438 | ||
439 | attr->sample_type |= PERF_SAMPLE_RAW; | 439 | attr->sample_type |= PERF_SAMPLE_RAW; |
440 | attr->sample_type |= PERF_SAMPLE_TIME; | 440 | attr->sample_type |= PERF_SAMPLE_TIME; |
@@ -495,7 +495,7 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
495 | struct perf_event_attr *attr) | 495 | struct perf_event_attr *attr) |
496 | { | 496 | { |
497 | const char *evt_name; | 497 | const char *evt_name; |
498 | char *flags; | 498 | char *flags = NULL, *comma_loc; |
499 | char sys_name[MAX_EVENT_LENGTH]; | 499 | char sys_name[MAX_EVENT_LENGTH]; |
500 | unsigned int sys_length, evt_length; | 500 | unsigned int sys_length, evt_length; |
501 | 501 | ||
@@ -514,6 +514,11 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
514 | sys_name[sys_length] = '\0'; | 514 | sys_name[sys_length] = '\0'; |
515 | evt_name = evt_name + 1; | 515 | evt_name = evt_name + 1; |
516 | 516 | ||
517 | comma_loc = strchr(evt_name, ','); | ||
518 | if (comma_loc) { | ||
519 | /* take the event name up to the comma */ | ||
520 | evt_name = strndup(evt_name, comma_loc - evt_name); | ||
521 | } | ||
517 | flags = strchr(evt_name, ':'); | 522 | flags = strchr(evt_name, ':'); |
518 | if (flags) { | 523 | if (flags) { |
519 | /* split it out: */ | 524 | /* split it out: */ |
@@ -524,9 +529,8 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
524 | evt_length = strlen(evt_name); | 529 | evt_length = strlen(evt_name); |
525 | if (evt_length >= MAX_EVENT_LENGTH) | 530 | if (evt_length >= MAX_EVENT_LENGTH) |
526 | return EVT_FAILED; | 531 | return EVT_FAILED; |
527 | |||
528 | if (strpbrk(evt_name, "*?")) { | 532 | if (strpbrk(evt_name, "*?")) { |
529 | *strp = evt_name + evt_length; | 533 | *strp += strlen(sys_name) + evt_length; |
530 | return parse_multiple_tracepoint_event(sys_name, evt_name, | 534 | return parse_multiple_tracepoint_event(sys_name, evt_name, |
531 | flags); | 535 | flags); |
532 | } else | 536 | } else |
@@ -810,9 +814,6 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
810 | return -1; | 814 | return -1; |
811 | 815 | ||
812 | for (;;) { | 816 | for (;;) { |
813 | if (nr_counters == MAX_COUNTERS) | ||
814 | return -1; | ||
815 | |||
816 | memset(&attr, 0, sizeof(attr)); | 817 | memset(&attr, 0, sizeof(attr)); |
817 | ret = parse_event_symbols(&str, &attr); | 818 | ret = parse_event_symbols(&str, &attr); |
818 | if (ret == EVT_FAILED) | 819 | if (ret == EVT_FAILED) |
@@ -822,8 +823,13 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
822 | return -1; | 823 | return -1; |
823 | 824 | ||
824 | if (ret != EVT_HANDLED_ALL) { | 825 | if (ret != EVT_HANDLED_ALL) { |
825 | attrs[nr_counters] = attr; | 826 | struct perf_evsel *evsel; |
826 | nr_counters++; | 827 | evsel = perf_evsel__new(attr.type, attr.config, |
828 | nr_counters); | ||
829 | if (evsel == NULL) | ||
830 | return -1; | ||
831 | list_add_tail(&evsel->node, &evsel_list); | ||
832 | ++nr_counters; | ||
827 | } | 833 | } |
828 | 834 | ||
829 | if (*str == 0) | 835 | if (*str == 0) |
@@ -840,21 +846,22 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
840 | int parse_filter(const struct option *opt __used, const char *str, | 846 | int parse_filter(const struct option *opt __used, const char *str, |
841 | int unset __used) | 847 | int unset __used) |
842 | { | 848 | { |
843 | int i = nr_counters - 1; | 849 | struct perf_evsel *last = NULL; |
844 | int len = strlen(str); | ||
845 | 850 | ||
846 | if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) { | 851 | if (!list_empty(&evsel_list)) |
852 | last = list_entry(evsel_list.prev, struct perf_evsel, node); | ||
853 | |||
854 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { | ||
847 | fprintf(stderr, | 855 | fprintf(stderr, |
848 | "-F option should follow a -e tracepoint option\n"); | 856 | "-F option should follow a -e tracepoint option\n"); |
849 | return -1; | 857 | return -1; |
850 | } | 858 | } |
851 | 859 | ||
852 | filters[i] = malloc(len + 1); | 860 | last->filter = strdup(str); |
853 | if (!filters[i]) { | 861 | if (last->filter == NULL) { |
854 | fprintf(stderr, "not enough memory to hold filter string\n"); | 862 | fprintf(stderr, "not enough memory to hold filter string\n"); |
855 | return -1; | 863 | return -1; |
856 | } | 864 | } |
857 | strcpy(filters[i], str); | ||
858 | 865 | ||
859 | return 0; | 866 | return 0; |
860 | } | 867 | } |
@@ -906,6 +913,47 @@ static void print_tracepoint_events(void) | |||
906 | } | 913 | } |
907 | 914 | ||
908 | /* | 915 | /* |
916 | * Check whether event is in <debugfs_mount_point>/tracing/events | ||
917 | */ | ||
918 | |||
919 | int is_valid_tracepoint(const char *event_string) | ||
920 | { | ||
921 | DIR *sys_dir, *evt_dir; | ||
922 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | ||
923 | char evt_path[MAXPATHLEN]; | ||
924 | char dir_path[MAXPATHLEN]; | ||
925 | |||
926 | if (debugfs_valid_mountpoint(debugfs_path)) | ||
927 | return 0; | ||
928 | |||
929 | sys_dir = opendir(debugfs_path); | ||
930 | if (!sys_dir) | ||
931 | return 0; | ||
932 | |||
933 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | ||
934 | |||
935 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, | ||
936 | sys_dirent.d_name); | ||
937 | evt_dir = opendir(dir_path); | ||
938 | if (!evt_dir) | ||
939 | continue; | ||
940 | |||
941 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | ||
942 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | ||
943 | sys_dirent.d_name, evt_dirent.d_name); | ||
944 | if (!strcmp(evt_path, event_string)) { | ||
945 | closedir(evt_dir); | ||
946 | closedir(sys_dir); | ||
947 | return 1; | ||
948 | } | ||
949 | } | ||
950 | closedir(evt_dir); | ||
951 | } | ||
952 | closedir(sys_dir); | ||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | /* | ||
909 | * Print the help text for the event symbols: | 957 | * Print the help text for the event symbols: |
910 | */ | 958 | */ |
911 | void print_events(void) | 959 | void print_events(void) |
@@ -963,3 +1011,26 @@ void print_events(void) | |||
963 | 1011 | ||
964 | exit(129); | 1012 | exit(129); |
965 | } | 1013 | } |
1014 | |||
1015 | int perf_evsel_list__create_default(void) | ||
1016 | { | ||
1017 | struct perf_evsel *evsel = perf_evsel__new(PERF_TYPE_HARDWARE, | ||
1018 | PERF_COUNT_HW_CPU_CYCLES, 0); | ||
1019 | if (evsel == NULL) | ||
1020 | return -ENOMEM; | ||
1021 | |||
1022 | list_add(&evsel->node, &evsel_list); | ||
1023 | ++nr_counters; | ||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | void perf_evsel_list__delete(void) | ||
1028 | { | ||
1029 | struct perf_evsel *pos, *n; | ||
1030 | |||
1031 | list_for_each_entry_safe(pos, n, &evsel_list, node) { | ||
1032 | list_del_init(&pos->node); | ||
1033 | perf_evsel__delete(pos); | ||
1034 | } | ||
1035 | nr_counters = 0; | ||
1036 | } | ||