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 @@ #include "parse-options.h" #include "parse-events.h" #include "exec_cmd.h" -#include "linux/string.h" +#include "string.h" #include "symbol.h" #include "cache.h" #include "header.h" @@ -30,6 +30,15 @@ extern int parse_events_debug; #endif int parse_events_parse(void *data, void *scanner); +static struct perf_pmu_event_symbol *perf_pmu_events_list; +/* + * The variable indicates the number of supported pmu event symbols. + * 0 means not initialized and ready to init + * -1 means failed to init, don't try anymore + * >0 is the number of supported pmu event symbols + */ +static int perf_pmu_events_list_num; + static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { [PERF_COUNT_HW_CPU_CYCLES] = { .symbol = "cpu-cycles", @@ -863,30 +872,111 @@ int parse_events_name(struct list_head *list, char *name) return 0; } -static int parse_events__scanner(const char *str, void *data, int start_token); +static int +comp_pmu(const void *p1, const void *p2) +{ + struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1; + struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2; -static int parse_events_fixup(int ret, const char *str, void *data, - int start_token) + return strcmp(pmu1->symbol, pmu2->symbol); +} + +static void perf_pmu__parse_cleanup(void) { - char *o = strdup(str); - char *s = NULL; - char *t = o; - char *p; + if (perf_pmu_events_list_num > 0) { + struct perf_pmu_event_symbol *p; + int i; + + for (i = 0; i < perf_pmu_events_list_num; i++) { + p = perf_pmu_events_list + i; + free(p->symbol); + } + free(perf_pmu_events_list); + perf_pmu_events_list = NULL; + perf_pmu_events_list_num = 0; + } +} + +#define SET_SYMBOL(str, stype) \ +do { \ + p->symbol = str; \ + if (!p->symbol) \ + goto err; \ + p->type = stype; \ +} while (0) + +/* + * Read the pmu events list from sysfs + * Save it into perf_pmu_events_list + */ +static void perf_pmu__parse_init(void) +{ + + struct perf_pmu *pmu = NULL; + struct perf_pmu_alias *alias; int len = 0; - if (!o) - return ret; - while ((p = strsep(&t, ",")) != NULL) { - if (s) - str_append(&s, &len, ","); - str_append(&s, &len, "cpu/"); - str_append(&s, &len, p); - str_append(&s, &len, "/"); + pmu = perf_pmu__find("cpu"); + if ((pmu == NULL) || list_empty(&pmu->aliases)) { + perf_pmu_events_list_num = -1; + return; } - free(o); - if (!s) - return -ENOMEM; - return parse_events__scanner(s, data, start_token); + list_for_each_entry(alias, &pmu->aliases, list) { + if (strchr(alias->name, '-')) + len++; + len++; + } + perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len); + if (!perf_pmu_events_list) + return; + perf_pmu_events_list_num = len; + + len = 0; + list_for_each_entry(alias, &pmu->aliases, list) { + struct perf_pmu_event_symbol *p = perf_pmu_events_list + len; + char *tmp = strchr(alias->name, '-'); + + if (tmp != NULL) { + SET_SYMBOL(strndup(alias->name, tmp - alias->name), + PMU_EVENT_SYMBOL_PREFIX); + p++; + SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX); + len += 2; + } else { + SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL); + len++; + } + } + qsort(perf_pmu_events_list, len, + sizeof(struct perf_pmu_event_symbol), comp_pmu); + + return; +err: + perf_pmu__parse_cleanup(); +} + +enum perf_pmu_event_symbol_type +perf_pmu__parse_check(const char *name) +{ + struct perf_pmu_event_symbol p, *r; + + /* scan kernel pmu events from sysfs if needed */ + if (perf_pmu_events_list_num == 0) + perf_pmu__parse_init(); + /* + * name "cpu" could be prefix of cpu-cycles or cpu// events. + * cpu-cycles has been handled by hardcode. + * So it must be cpu// events, not kernel pmu event. + */ + if ((perf_pmu_events_list_num <= 0) || !strcmp(name, "cpu")) + return PMU_EVENT_SYMBOL_ERR; + + p.symbol = strdup(name); + r = bsearch(&p, perf_pmu_events_list, + (size_t) perf_pmu_events_list_num, + sizeof(struct perf_pmu_event_symbol), comp_pmu); + free(p.symbol); + return r ? r->type : PMU_EVENT_SYMBOL_ERR; } 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) parse_events__flush_buffer(buffer, scanner); parse_events__delete_buffer(buffer, scanner); parse_events_lex_destroy(scanner); - if (ret && !strchr(str, '/')) - ret = parse_events_fixup(ret, str, data, start_token); return ret; } @@ -945,6 +1033,7 @@ int parse_events(struct perf_evlist *evlist, const char *str) int ret; ret = parse_events__scanner(str, &data, PE_START_EVENTS); + perf_pmu__parse_cleanup(); if (!ret) { int entries = data.idx - evlist->nr_entries; perf_evlist__splice_list_tail(evlist, &data.list, entries); |