diff options
author | Kan Liang <kan.liang@intel.com> | 2014-10-07 11:08:50 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-10-15 15:05:01 -0400 |
commit | dcb4e1022b40d886027500821a592dd8f8ccde8f (patch) | |
tree | 45db2ff649f7a4b447e8274e307d001a468c07f0 /tools | |
parent | 42f60c2d63b0d3f7230d28ac37c1da4885d4ee65 (diff) |
perf tools: Parse the pmu event prefix and suffix
There are two types of event formats for PMU events. E.g. el-abort OR
cpu/el-abort/. However, the lexer mistakenly recognizes the simple style
format as two events.
The parse_events_pmu_check function uses bsearch to search the name in
known pmu event list. It can tell the lexer that the name is a PE_NAME
or a PMU event name prefix or a PMU event name suffix. All these
information will be used for accurately parsing kernel PMU events.
The pmu events list will be read from sysfs at runtime.
Note: Currently, the patch only want to handle the PMU event name as
"a-b" and "a". The only exception, "stalled-cycles-frontend" and
"stalled-cycles-fronted", are already hardcoded in lexer.
Signed-off-by: Kan Liang <kan.liang@intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/1412694532-23391-3-git-send-email-kan.liang@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/parse-events.c | 117 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 14 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 10 | ||||
-rw-r--r-- | tools/perf/util/pmu.h | 10 |
4 files changed, 141 insertions, 10 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c5642e6748b2..c659a3ca1283 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -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,6 +872,113 @@ int parse_events_name(struct list_head *list, char *name) | |||
863 | return 0; | 872 | return 0; |
864 | } | 873 | } |
865 | 874 | ||
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; | ||
880 | |||
881 | return strcmp(pmu1->symbol, pmu2->symbol); | ||
882 | } | ||
883 | |||
884 | static void perf_pmu__parse_cleanup(void) | ||
885 | { | ||
886 | if (perf_pmu_events_list_num > 0) { | ||
887 | struct perf_pmu_event_symbol *p; | ||
888 | int i; | ||
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; | ||
917 | int len = 0; | ||
918 | |||
919 | pmu = perf_pmu__find("cpu"); | ||
920 | if ((pmu == NULL) || list_empty(&pmu->aliases)) { | ||
921 | perf_pmu_events_list_num = -1; | ||
922 | return; | ||
923 | } | ||
924 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
925 | if (strchr(alias->name, '-')) | ||
926 | len++; | ||
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; | ||
980 | } | ||
981 | |||
866 | 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) |
867 | { | 983 | { |
868 | YY_BUFFER_STATE buffer; | 984 | YY_BUFFER_STATE buffer; |
@@ -917,6 +1033,7 @@ int parse_events(struct perf_evlist *evlist, const char *str) | |||
917 | int ret; | 1033 | int ret; |
918 | 1034 | ||
919 | ret = parse_events__scanner(str, &data, PE_START_EVENTS); | 1035 | ret = parse_events__scanner(str, &data, PE_START_EVENTS); |
1036 | perf_pmu__parse_cleanup(); | ||
920 | if (!ret) { | 1037 | if (!ret) { |
921 | int entries = data.idx - evlist->nr_entries; | 1038 | int entries = data.idx - evlist->nr_entries; |
922 | perf_evlist__splice_list_tail(evlist, &data.list, entries); | 1039 | perf_evlist__splice_list_tail(evlist, &data.list, entries); |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index df094b4ed5ed..db2cf78ff0f3 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -35,6 +35,18 @@ extern int parse_filter(const struct option *opt, const char *str, int unset); | |||
35 | 35 | ||
36 | #define EVENTS_HELP_MAX (128*1024) | 36 | #define EVENTS_HELP_MAX (128*1024) |
37 | 37 | ||
38 | enum perf_pmu_event_symbol_type { | ||
39 | PMU_EVENT_SYMBOL_ERR, /* not a PMU EVENT */ | ||
40 | PMU_EVENT_SYMBOL, /* normal style PMU event */ | ||
41 | PMU_EVENT_SYMBOL_PREFIX, /* prefix of pre-suf style event */ | ||
42 | PMU_EVENT_SYMBOL_SUFFIX, /* suffix of pre-suf style event */ | ||
43 | }; | ||
44 | |||
45 | struct perf_pmu_event_symbol { | ||
46 | char *symbol; | ||
47 | enum perf_pmu_event_symbol_type type; | ||
48 | }; | ||
49 | |||
38 | enum { | 50 | enum { |
39 | PARSE_EVENTS__TERM_TYPE_NUM, | 51 | PARSE_EVENTS__TERM_TYPE_NUM, |
40 | PARSE_EVENTS__TERM_TYPE_STR, | 52 | PARSE_EVENTS__TERM_TYPE_STR, |
@@ -95,6 +107,8 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, | |||
95 | void *ptr, char *type); | 107 | void *ptr, char *type); |
96 | int parse_events_add_pmu(struct list_head *list, int *idx, | 108 | int parse_events_add_pmu(struct list_head *list, int *idx, |
97 | char *pmu , struct list_head *head_config); | 109 | char *pmu , struct list_head *head_config); |
110 | enum perf_pmu_event_symbol_type | ||
111 | perf_pmu__parse_check(const char *name); | ||
98 | void parse_events__set_leader(char *name, struct list_head *list); | 112 | void parse_events__set_leader(char *name, struct list_head *list); |
99 | void parse_events_update_lists(struct list_head *list_event, | 113 | void parse_events_update_lists(struct list_head *list_event, |
100 | struct list_head *list_all); | 114 | struct list_head *list_all); |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 93a41ca96b8e..e243ad962a4d 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -12,16 +12,6 @@ | |||
12 | #include "parse-events.h" | 12 | #include "parse-events.h" |
13 | #include "cpumap.h" | 13 | #include "cpumap.h" |
14 | 14 | ||
15 | #define UNIT_MAX_LEN 31 /* max length for event unit name */ | ||
16 | |||
17 | struct perf_pmu_alias { | ||
18 | char *name; | ||
19 | struct list_head terms; /* HEAD struct parse_events_term -> list */ | ||
20 | struct list_head list; /* ELEM */ | ||
21 | char unit[UNIT_MAX_LEN+1]; | ||
22 | double scale; | ||
23 | }; | ||
24 | |||
25 | struct perf_pmu_format { | 15 | struct perf_pmu_format { |
26 | char *name; | 16 | char *name; |
27 | int value; | 17 | int value; |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index fe90a012c003..fe9dfbee8eed 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -30,6 +30,16 @@ struct perf_pmu_info { | |||
30 | double scale; | 30 | double scale; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #define UNIT_MAX_LEN 31 /* max length for event unit name */ | ||
34 | |||
35 | struct perf_pmu_alias { | ||
36 | char *name; | ||
37 | struct list_head terms; /* HEAD struct parse_events_term -> list */ | ||
38 | struct list_head list; /* ELEM */ | ||
39 | char unit[UNIT_MAX_LEN+1]; | ||
40 | double scale; | ||
41 | }; | ||
42 | |||
33 | struct perf_pmu *perf_pmu__find(const char *name); | 43 | struct perf_pmu *perf_pmu__find(const char *name); |
34 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | 44 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, |
35 | struct list_head *head_terms); | 45 | struct list_head *head_terms); |