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 | |||
