diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 162 |
1 files changed, 132 insertions, 30 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1e15df10a88..c659a3ca128 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -6,10 +6,11 @@ #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" +#include "debug.h" #include <api/fs/debugfs.h> #include "parse-events-bison.h" #define YY_EXTRA_TYPE int @@ -29,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", @@ -633,18 +643,28 @@ int parse_events_add_pmu(struct list_head *list, int *idx, char *name, struct list_head *head_config) { struct perf_event_attr attr; + struct perf_pmu_info info; struct perf_pmu *pmu; struct perf_evsel *evsel; - const char *unit; - double scale; pmu = perf_pmu__find(name); if (!pmu) return -EINVAL; - memset(&attr, 0, sizeof(attr)); + if (pmu->default_config) { + memcpy(&attr, pmu->default_config, + sizeof(struct perf_event_attr)); + } else { + memset(&attr, 0, sizeof(attr)); + } - if (perf_pmu__check_alias(pmu, head_config, &unit, &scale)) + if (!head_config) { + attr.type = pmu->type; + evsel = __add_event(list, idx, &attr, NULL, pmu->cpus); + return evsel ? 0 : -ENOMEM; + } + + if (perf_pmu__check_alias(pmu, head_config, &info)) return -EINVAL; /* @@ -659,8 +679,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx, evsel = __add_event(list, idx, &attr, pmu_event_name(head_config), pmu->cpus); if (evsel) { - evsel->unit = unit; - evsel->scale = scale; + evsel->unit = info.unit; + evsel->scale = info.scale; } return evsel ? 0 : -ENOMEM; @@ -852,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) @@ -898,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; } @@ -934,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); @@ -973,7 +1073,7 @@ int parse_filter(const struct option *opt, const char *str, if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { fprintf(stderr, - "-F option should follow a -e tracepoint option\n"); + "--filter option should follow a -e tracepoint option\n"); return -1; } @@ -1006,9 +1106,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; + char sbuf[STRERR_BUFSIZE]; if (debugfs_valid_mountpoint(tracing_events_path)) { - printf(" [ Tracepoints not available: %s ]\n", strerror(errno)); + printf(" [ Tracepoints not available: %s ]\n", + strerror_r(errno, sbuf, sizeof(sbuf))); return; } |