Commit dcb4e1022b40d886027500821a592dd8f8ccde8f

Authored by Kan Liang
Committed by Arnaldo Carvalho de Melo
1 parent 42f60c2d63

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>

Showing 4 changed files with 141 additions and 10 deletions Side-by-side Diff

tools/perf/util/parse-events.c
... ... @@ -30,6 +30,15 @@
30 30 #endif
31 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 42 static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = {
34 43 [PERF_COUNT_HW_CPU_CYCLES] = {
35 44 .symbol = "cpu-cycles",
... ... @@ -863,6 +872,113 @@
863 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 982 static int parse_events__scanner(const char *str, void *data, int start_token)
867 983 {
868 984 YY_BUFFER_STATE buffer;
... ... @@ -917,6 +1033,7 @@
917 1033 int ret;
918 1034  
919 1035 ret = parse_events__scanner(str, &data, PE_START_EVENTS);
  1036 + perf_pmu__parse_cleanup();
920 1037 if (!ret) {
921 1038 int entries = data.idx - evlist->nr_entries;
922 1039 perf_evlist__splice_list_tail(evlist, &data.list, entries);
tools/perf/util/parse-events.h
... ... @@ -35,6 +35,18 @@
35 35  
36 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 50 enum {
39 51 PARSE_EVENTS__TERM_TYPE_NUM,
40 52 PARSE_EVENTS__TERM_TYPE_STR,
... ... @@ -95,6 +107,8 @@
95 107 void *ptr, char *type);
96 108 int parse_events_add_pmu(struct list_head *list, int *idx,
97 109 char *pmu , struct list_head *head_config);
  110 +enum perf_pmu_event_symbol_type
  111 +perf_pmu__parse_check(const char *name);
98 112 void parse_events__set_leader(char *name, struct list_head *list);
99 113 void parse_events_update_lists(struct list_head *list_event,
100 114 struct list_head *list_all);
tools/perf/util/pmu.c
... ... @@ -12,16 +12,6 @@
12 12 #include "parse-events.h"
13 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 15 struct perf_pmu_format {
26 16 char *name;
27 17 int value;
tools/perf/util/pmu.h
... ... @@ -30,6 +30,16 @@
30 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 43 struct perf_pmu *perf_pmu__find(const char *name);
34 44 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
35 45 struct list_head *head_terms);