diff options
Diffstat (limited to 'tools/perf/util/pmu.c')
-rw-r--r-- | tools/perf/util/pmu.c | 117 |
1 files changed, 93 insertions, 24 deletions
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 48411674d..7bcb8c315 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1,4 +1,5 @@ #include <linux/list.h> +#include <linux/compiler.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> @@ -112,7 +113,11 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char * if (sret < 0) goto error; - scale[sret] = '\0'; + if (scale[sret - 1] == '\n') + scale[sret - 1] = '\0'; + else + scale[sret] = '\0'; + /* * save current locale */ @@ -154,7 +159,10 @@ static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *n close(fd); - alias->unit[sret] = '\0'; + if (alias->unit[sret - 1] == '\n') + alias->unit[sret - 1] = '\0'; + else + alias->unit[sret] = '\0'; return 0; error: @@ -198,17 +206,12 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, return 0; } -static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) +static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, + char *desc __maybe_unused, char *val) { struct perf_pmu_alias *alias; - char buf[256]; int ret; - ret = fread(buf, 1, sizeof(buf), file); - if (ret == 0) - return -EINVAL; - buf[ret] = 0; - alias = malloc(sizeof(*alias)); if (!alias) return -ENOMEM; @@ -218,26 +221,43 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI alias->unit[0] = '\0'; alias->per_pkg = false; - ret = parse_events_terms(&alias->terms, buf); + ret = parse_events_terms(&alias->terms, val); if (ret) { + pr_err("Cannot parse alias %s: %d\n", val, ret); free(alias); return ret; } alias->name = strdup(name); - /* - * load unit name and scale if available - */ - perf_pmu__parse_unit(alias, dir, name); - perf_pmu__parse_scale(alias, dir, name); - perf_pmu__parse_per_pkg(alias, dir, name); - perf_pmu__parse_snapshot(alias, dir, name); + if (dir) { + /* + * load unit name and scale if available + */ + perf_pmu__parse_unit(alias, dir, name); + perf_pmu__parse_scale(alias, dir, name); + perf_pmu__parse_per_pkg(alias, dir, name); + perf_pmu__parse_snapshot(alias, dir, name); + } list_add_tail(&alias->list, list); return 0; } +static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) +{ + char buf[256]; + int ret; + + ret = fread(buf, 1, sizeof(buf), file); + if (ret == 0) + return -EINVAL; + + buf[ret] = 0; + + return __perf_pmu__new_alias(list, dir, name, NULL, buf); +} + static inline bool pmu_alias_info_file(char *name) { size_t len; @@ -429,7 +449,7 @@ static struct cpu_map *pmu_cpumask(const char *name) return cpus; } -struct perf_event_attr *__attribute__((weak)) +struct perf_event_attr * __weak perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) { return NULL; @@ -442,6 +462,10 @@ static struct perf_pmu *pmu_lookup(const char *name) LIST_HEAD(aliases); __u32 type; + /* No support for intel_bts or intel_pt so disallow them */ + if (!strcmp(name, "intel_bts") || !strcmp(name, "intel_pt")) + return NULL; + /* * The pmu data we store & need consists of the pmu * type value and format definitions. Load both right @@ -579,6 +603,38 @@ static int pmu_resolve_param_term(struct parse_events_term *term, return -1; } +static char *formats_error_string(struct list_head *formats) +{ + struct perf_pmu_format *format; + char *err, *str; + static const char *static_terms = "config,config1,config2,name,period,branch_type\n"; + unsigned i = 0; + + if (!asprintf(&str, "valid terms:")) + return NULL; + + /* sysfs exported terms */ + list_for_each_entry(format, formats, list) { + char c = i++ ? ',' : ' '; + + err = str; + if (!asprintf(&str, "%s%c%s", err, c, format->name)) + goto fail; + free(err); + } + + /* static terms */ + err = str; + if (!asprintf(&str, "%s,%s", err, static_terms)) + goto fail; + + free(err); + return str; +fail: + free(err); + return NULL; +} + /* * Setup one of config[12] attr members based on the * user input data - term parameter. @@ -587,7 +643,7 @@ static int pmu_config_term(struct list_head *formats, struct perf_event_attr *attr, struct parse_events_term *term, struct list_head *head_terms, - bool zero) + bool zero, struct parse_events_error *err) { struct perf_pmu_format *format; __u64 *vp; @@ -611,6 +667,11 @@ static int pmu_config_term(struct list_head *formats, if (!format) { if (verbose) printf("Invalid event/parameter '%s'\n", term->config); + if (err) { + err->idx = term->err_term; + err->str = strdup("unknown term"); + err->help = formats_error_string(formats); + } return -EINVAL; } @@ -636,9 +697,14 @@ static int pmu_config_term(struct list_head *formats, val = term->val.num; else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { if (strcmp(term->val.str, "?")) { - if (verbose) + if (verbose) { pr_info("Invalid sysfs entry %s=%s\n", term->config, term->val.str); + } + if (err) { + err->idx = term->err_val; + err->str = strdup("expected numeric value"); + } return -EINVAL; } @@ -654,12 +720,13 @@ static int pmu_config_term(struct list_head *formats, int perf_pmu__config_terms(struct list_head *formats, struct perf_event_attr *attr, struct list_head *head_terms, - bool zero) + bool zero, struct parse_events_error *err) { struct parse_events_term *term; list_for_each_entry(term, head_terms, list) { - if (pmu_config_term(formats, attr, term, head_terms, zero)) + if (pmu_config_term(formats, attr, term, head_terms, + zero, err)) return -EINVAL; } @@ -672,12 +739,14 @@ int perf_pmu__config_terms(struct list_head *formats, * 2) pmu format definitions - specified by pmu parameter */ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, - struct list_head *head_terms) + struct list_head *head_terms, + struct parse_events_error *err) { bool zero = !!pmu->default_config; attr->type = pmu->type; - return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero); + return perf_pmu__config_terms(&pmu->format, attr, head_terms, + zero, err); } static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, |