diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 133 |
1 files changed, 111 insertions, 22 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d76aa30cb1fb..c659a3ca1283 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 "linux/string.h" | 9 | #include "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" |
@@ -30,6 +30,15 @@ extern int parse_events_debug; | |||
30 | #endif | 30 | #endif |
31 | int parse_events_parse(void *data, void *scanner); | 31 | int parse_events_parse(void *data, void *scanner); |
32 | 32 | ||
33 | static struct perf_pmu_event_symbol *perf_pmu_events_list; | ||
34 | /* | ||
35 | * The variable indicates the number of supported pmu event symbols. | ||
36 | * 0 means not initialized and ready to init | ||
37 | * -1 means failed to init, don't try anymore | ||
38 | * >0 is the number of supported pmu event symbols | ||
39 | */ | ||
40 | static int perf_pmu_events_list_num; | ||
41 | |||
33 | static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { | 42 | static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { |
34 | [PERF_COUNT_HW_CPU_CYCLES] = { | 43 | [PERF_COUNT_HW_CPU_CYCLES] = { |
35 | .symbol = "cpu-cycles", | 44 | .symbol = "cpu-cycles", |
@@ -863,30 +872,111 @@ int parse_events_name(struct list_head *list, char *name) | |||
863 | return 0; | 872 | return 0; |
864 | } | 873 | } |
865 | 874 | ||
866 | static int parse_events__scanner(const char *str, void *data, int start_token); | 875 | static int |
876 | comp_pmu(const void *p1, const void *p2) | ||
877 | { | ||
878 | struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1; | ||
879 | struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2; | ||
867 | 880 | ||
868 | static int parse_events_fixup(int ret, const char *str, void *data, | 881 | return strcmp(pmu1->symbol, pmu2->symbol); |
869 | int start_token) | 882 | } |
883 | |||
884 | static void perf_pmu__parse_cleanup(void) | ||
870 | { | 885 | { |
871 | char *o = strdup(str); | 886 | if (perf_pmu_events_list_num > 0) { |
872 | char *s = NULL; | 887 | struct perf_pmu_event_symbol *p; |
873 | char *t = o; | 888 | int i; |
874 | char *p; | 889 | |
890 | for (i = 0; i < perf_pmu_events_list_num; i++) { | ||
891 | p = perf_pmu_events_list + i; | ||
892 | free(p->symbol); | ||
893 | } | ||
894 | free(perf_pmu_events_list); | ||
895 | perf_pmu_events_list = NULL; | ||
896 | perf_pmu_events_list_num = 0; | ||
897 | } | ||
898 | } | ||
899 | |||
900 | #define SET_SYMBOL(str, stype) \ | ||
901 | do { \ | ||
902 | p->symbol = str; \ | ||
903 | if (!p->symbol) \ | ||
904 | goto err; \ | ||
905 | p->type = stype; \ | ||
906 | } while (0) | ||
907 | |||
908 | /* | ||
909 | * Read the pmu events list from sysfs | ||
910 | * Save it into perf_pmu_events_list | ||
911 | */ | ||
912 | static void perf_pmu__parse_init(void) | ||
913 | { | ||
914 | |||
915 | struct perf_pmu *pmu = NULL; | ||
916 | struct perf_pmu_alias *alias; | ||
875 | int len = 0; | 917 | int len = 0; |
876 | 918 | ||
877 | if (!o) | 919 | pmu = perf_pmu__find("cpu"); |
878 | return ret; | 920 | if ((pmu == NULL) || list_empty(&pmu->aliases)) { |
879 | while ((p = strsep(&t, ",")) != NULL) { | 921 | perf_pmu_events_list_num = -1; |
880 | if (s) | 922 | return; |
881 | str_append(&s, &len, ","); | ||
882 | str_append(&s, &len, "cpu/"); | ||
883 | str_append(&s, &len, p); | ||
884 | str_append(&s, &len, "/"); | ||
885 | } | 923 | } |
886 | free(o); | 924 | list_for_each_entry(alias, &pmu->aliases, list) { |
887 | if (!s) | 925 | if (strchr(alias->name, '-')) |
888 | return -ENOMEM; | 926 | len++; |
889 | return parse_events__scanner(s, data, start_token); | 927 | len++; |
928 | } | ||
929 | perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len); | ||
930 | if (!perf_pmu_events_list) | ||
931 | return; | ||
932 | perf_pmu_events_list_num = len; | ||
933 | |||
934 | len = 0; | ||
935 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
936 | struct perf_pmu_event_symbol *p = perf_pmu_events_list + len; | ||
937 | char *tmp = strchr(alias->name, '-'); | ||
938 | |||
939 | if (tmp != NULL) { | ||
940 | SET_SYMBOL(strndup(alias->name, tmp - alias->name), | ||
941 | PMU_EVENT_SYMBOL_PREFIX); | ||
942 | p++; | ||
943 | SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX); | ||
944 | len += 2; | ||
945 | } else { | ||
946 | SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL); | ||
947 | len++; | ||
948 | } | ||
949 | } | ||
950 | qsort(perf_pmu_events_list, len, | ||
951 | sizeof(struct perf_pmu_event_symbol), comp_pmu); | ||
952 | |||
953 | return; | ||
954 | err: | ||
955 | perf_pmu__parse_cleanup(); | ||
956 | } | ||
957 | |||
958 | enum perf_pmu_event_symbol_type | ||
959 | perf_pmu__parse_check(const char *name) | ||
960 | { | ||
961 | struct perf_pmu_event_symbol p, *r; | ||
962 | |||
963 | /* scan kernel pmu events from sysfs if needed */ | ||
964 | if (perf_pmu_events_list_num == 0) | ||
965 | perf_pmu__parse_init(); | ||
966 | /* | ||
967 | * name "cpu" could be prefix of cpu-cycles or cpu// events. | ||
968 | * cpu-cycles has been handled by hardcode. | ||
969 | * So it must be cpu// events, not kernel pmu event. | ||
970 | */ | ||
971 | if ((perf_pmu_events_list_num <= 0) || !strcmp(name, "cpu")) | ||
972 | return PMU_EVENT_SYMBOL_ERR; | ||
973 | |||
974 | p.symbol = strdup(name); | ||
975 | r = bsearch(&p, perf_pmu_events_list, | ||
976 | (size_t) perf_pmu_events_list_num, | ||
977 | sizeof(struct perf_pmu_event_symbol), comp_pmu); | ||
978 | free(p.symbol); | ||
979 | return r ? r->type : PMU_EVENT_SYMBOL_ERR; | ||
890 | } | 980 | } |
891 | 981 | ||
892 | static int parse_events__scanner(const char *str, void *data, int start_token) | 982 | static int parse_events__scanner(const char *str, void *data, int start_token) |
@@ -909,8 +999,6 @@ static int parse_events__scanner(const char *str, void *data, int start_token) | |||
909 | parse_events__flush_buffer(buffer, scanner); | 999 | parse_events__flush_buffer(buffer, scanner); |
910 | parse_events__delete_buffer(buffer, scanner); | 1000 | parse_events__delete_buffer(buffer, scanner); |
911 | parse_events_lex_destroy(scanner); | 1001 | parse_events_lex_destroy(scanner); |
912 | if (ret && !strchr(str, '/')) | ||
913 | ret = parse_events_fixup(ret, str, data, start_token); | ||
914 | return ret; | 1002 | return ret; |
915 | } | 1003 | } |
916 | 1004 | ||
@@ -945,6 +1033,7 @@ int parse_events(struct perf_evlist *evlist, const char *str) | |||
945 | int ret; | 1033 | int ret; |
946 | 1034 | ||
947 | ret = parse_events__scanner(str, &data, PE_START_EVENTS); | 1035 | ret = parse_events__scanner(str, &data, PE_START_EVENTS); |
1036 | perf_pmu__parse_cleanup(); | ||
948 | if (!ret) { | 1037 | if (!ret) { |
949 | int entries = data.idx - evlist->nr_entries; | 1038 | int entries = data.idx - evlist->nr_entries; |
950 | perf_evlist__splice_list_tail(evlist, &data.list, entries); | 1039 | perf_evlist__splice_list_tail(evlist, &data.list, entries); |