aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorKan Liang <kan.liang@intel.com>2014-10-07 11:08:50 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2014-10-15 15:05:01 -0400
commitdcb4e1022b40d886027500821a592dd8f8ccde8f (patch)
tree45db2ff649f7a4b447e8274e307d001a468c07f0 /tools
parent42f60c2d63b0d3f7230d28ac37c1da4885d4ee65 (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.c117
-rw-r--r--tools/perf/util/parse-events.h14
-rw-r--r--tools/perf/util/pmu.c10
-rw-r--r--tools/perf/util/pmu.h10
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
31int parse_events_parse(void *data, void *scanner); 31int parse_events_parse(void *data, void *scanner);
32 32
33static 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 */
40static int perf_pmu_events_list_num;
41
33static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { 42static 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
875static int
876comp_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
884static 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) \
901do { \
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 */
912static 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;
954err:
955 perf_pmu__parse_cleanup();
956}
957
958enum perf_pmu_event_symbol_type
959perf_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
866static int parse_events__scanner(const char *str, void *data, int start_token) 982static 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
38enum 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
45struct perf_pmu_event_symbol {
46 char *symbol;
47 enum perf_pmu_event_symbol_type type;
48};
49
38enum { 50enum {
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);
96int parse_events_add_pmu(struct list_head *list, int *idx, 108int 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);
110enum perf_pmu_event_symbol_type
111perf_pmu__parse_check(const char *name);
98void parse_events__set_leader(char *name, struct list_head *list); 112void parse_events__set_leader(char *name, struct list_head *list);
99void parse_events_update_lists(struct list_head *list_event, 113void 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
17struct 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
25struct perf_pmu_format { 15struct 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
35struct 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
33struct perf_pmu *perf_pmu__find(const char *name); 43struct perf_pmu *perf_pmu__find(const char *name);
34int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 44int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
35 struct list_head *head_terms); 45 struct list_head *head_terms);