diff options
Diffstat (limited to 'tools/perf/util/pmu.c')
-rw-r--r-- | tools/perf/util/pmu.c | 172 |
1 files changed, 136 insertions, 36 deletions
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index cc349d9cb0..888ce99122 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -194,7 +194,7 @@ static void perf_pmu_format__load(const struct perf_pmu *pmu, struct perf_pmu_fo * Parse & process all the sysfs attributes located under * the directory specified in 'dir' parameter. */ -int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load) +static int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load) { struct dirent *evt_ent; DIR *format_dir; @@ -244,7 +244,7 @@ int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load) * located at: * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. */ -static int pmu_format(struct perf_pmu *pmu, int dirfd, const char *name) +static int pmu_format(struct perf_pmu *pmu, int dirfd, const char *name, bool eager_load) { int fd; @@ -253,7 +253,7 @@ static int pmu_format(struct perf_pmu *pmu, int dirfd, const char *name) return 0; /* it'll close the fd */ - if (perf_pmu__format_parse(pmu, fd, /*eager_load=*/false)) + if (perf_pmu__format_parse(pmu, fd, eager_load)) return -1; return 0; @@ -551,7 +551,8 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name, unit = pe->unit; perpkg = pe->perpkg; deprecated = pe->deprecated; - pmu_name = pe->pmu; + if (pe->pmu && strcmp(pe->pmu, "default_core")) + pmu_name = pe->pmu; } alias = zalloc(sizeof(*alias)); @@ -634,33 +635,18 @@ static inline bool pmu_alias_info_file(const char *name) * Reading the pmu event aliases definition, which should be located at: * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. */ -static int pmu_aliases_parse(struct perf_pmu *pmu) +static int __pmu_aliases_parse(struct perf_pmu *pmu, int events_dir_fd) { - char path[PATH_MAX]; struct dirent *evt_ent; DIR *event_dir; - size_t len; - int fd, dir_fd; - - len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path)); - if (!len) - return 0; - scnprintf(path + len, sizeof(path) - len, "%s/events", pmu->name); - - dir_fd = open(path, O_DIRECTORY); - if (dir_fd == -1) { - pmu->sysfs_aliases_loaded = true; - return 0; - } - event_dir = fdopendir(dir_fd); - if (!event_dir){ - close (dir_fd); + event_dir = fdopendir(events_dir_fd); + if (!event_dir) return -EINVAL; - } while ((evt_ent = readdir(event_dir))) { char *name = evt_ent->d_name; + int fd; FILE *file; if (!strcmp(name, ".") || !strcmp(name, "..")) @@ -672,7 +658,7 @@ static int pmu_aliases_parse(struct perf_pmu *pmu) if (pmu_alias_info_file(name)) continue; - fd = openat(dir_fd, name, O_RDONLY); + fd = openat(events_dir_fd, name, O_RDONLY); if (fd == -1) { pr_debug("Cannot open %s\n", name); continue; @@ -691,11 +677,50 @@ static int pmu_aliases_parse(struct perf_pmu *pmu) } closedir(event_dir); - close (dir_fd); pmu->sysfs_aliases_loaded = true; return 0; } +static int pmu_aliases_parse(struct perf_pmu *pmu) +{ + char path[PATH_MAX]; + size_t len; + int events_dir_fd, ret; + + if (pmu->sysfs_aliases_loaded) + return 0; + + len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path)); + if (!len) + return 0; + scnprintf(path + len, sizeof(path) - len, "%s/events", pmu->name); + + events_dir_fd = open(path, O_DIRECTORY); + if (events_dir_fd == -1) { + pmu->sysfs_aliases_loaded = true; + return 0; + } + ret = __pmu_aliases_parse(pmu, events_dir_fd); + close(events_dir_fd); + return ret; +} + +static int pmu_aliases_parse_eager(struct perf_pmu *pmu, int sysfs_fd) +{ + char path[FILENAME_MAX + 7]; + int ret, events_dir_fd; + + scnprintf(path, sizeof(path), "%s/events", pmu->name); + events_dir_fd = openat(sysfs_fd, path, O_DIRECTORY, 0); + if (events_dir_fd == -1) { + pmu->sysfs_aliases_loaded = true; + return 0; + } + ret = __pmu_aliases_parse(pmu, events_dir_fd); + close(events_dir_fd); + return ret; +} + static int pmu_alias_terms(struct perf_pmu_alias *alias, int err_loc, struct list_head *terms) { struct parse_events_term *term, *cloned; @@ -1034,7 +1059,8 @@ perf_pmu__arch_init(struct perf_pmu *pmu) pmu->mem_events = perf_mem_events; } -struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *name) +struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *name, + bool eager_load) { struct perf_pmu *pmu; __u32 type; @@ -1063,7 +1089,7 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char * type value and format definitions. Load both right * now. */ - if (pmu_format(pmu, dirfd, name)) + if (pmu_format(pmu, dirfd, name, eager_load)) goto err; pmu->is_core = is_pmu_core(name); @@ -1087,6 +1113,9 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char perf_pmu__arch_init(pmu); + if (eager_load) + pmu_aliases_parse_eager(pmu, dirfd); + return pmu; err: zfree(&pmu->name); @@ -1649,6 +1678,62 @@ bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name) return false; } +int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb) +{ + static const char *const terms[] = { + "config=0..0xffffffffffffffff", + "config1=0..0xffffffffffffffff", + "config2=0..0xffffffffffffffff", + "config3=0..0xffffffffffffffff", + "name=string", + "period=number", + "freq=number", + "branch_type=(u|k|hv|any|...)", + "time", + "call-graph=(fp|dwarf|lbr)", + "stack-size=number", + "max-stack=number", + "nr=number", + "inherit", + "no-inherit", + "overwrite", + "no-overwrite", + "percore", + "aux-output", + "aux-sample-size=number", + }; + struct perf_pmu_format *format; + int ret; + + /* + * max-events and driver-config are missing above as are the internal + * types user, metric-id, raw, legacy cache and hardware. Assert against + * the enum parse_events__term_type so they are kept in sync. + */ + _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6, + "perf_pmu__for_each_format()'s terms must be kept in sync with enum parse_events__term_type"); + list_for_each_entry(format, &pmu->format, list) { + perf_pmu_format__load(pmu, format); + ret = cb(state, format->name, (int)format->value, format->bits); + if (ret) + return ret; + } + if (!pmu->is_core) + return 0; + + for (size_t i = 0; i < ARRAY_SIZE(terms); i++) { + int config = PERF_PMU_FORMAT_VALUE_CONFIG; + + if (i < PERF_PMU_FORMAT_VALUE_CONFIG_END) + config = i; + + ret = cb(state, terms[i], config, /*bits=*/NULL); + if (ret) + return ret; + } + return 0; +} + bool is_pmu_core(const char *name) { return !strcmp(name, "cpu") || !strcmp(name, "cpum_cf") || is_sysfs_pmu_core(name); @@ -1744,8 +1829,12 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus, pmu_add_cpu_aliases(pmu); list_for_each_entry(event, &pmu->aliases, list) { size_t buf_used; + int pmu_name_len; info.pmu_name = event->pmu_name ?: pmu->name; + pmu_name_len = skip_duplicate_pmus + ? pmu_name_len_no_suffix(info.pmu_name, /*num=*/NULL) + : (int)strlen(info.pmu_name); info.alias = NULL; if (event->desc) { info.name = event->name; @@ -1770,7 +1859,7 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus, info.encoding_desc = buf + buf_used; parse_events_terms__to_strbuf(&event->terms, &sb); buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, - "%s/%s/", info.pmu_name, sb.buf) + 1; + "%.*s/%s/", pmu_name_len, info.pmu_name, sb.buf) + 1; info.topic = event->topic; info.str = sb.buf; info.deprecated = event->deprecated; @@ -2051,18 +2140,29 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, name ?: "N/A", buf, config_name, config); } -int perf_pmu__match(const char *pattern, const char *name, const char *tok) +bool perf_pmu__match(const struct perf_pmu *pmu, const char *tok) { - if (!name) - return -1; + const char *name = pmu->name; + bool need_fnmatch = strchr(tok, '*') != NULL; - if (fnmatch(pattern, name, 0)) - return -1; + if (!strncmp(tok, "uncore_", 7)) + tok += 7; + if (!strncmp(name, "uncore_", 7)) + name += 7; - if (tok && !perf_pmu__match_ignoring_suffix(name, tok)) - return -1; + if (perf_pmu__match_ignoring_suffix(name, tok) || + (need_fnmatch && !fnmatch(tok, name, 0))) + return true; - return 0; + name = pmu->alias_name; + if (!name) + return false; + + if (!strncmp(name, "uncore_", 7)) + name += 7; + + return perf_pmu__match_ignoring_suffix(name, tok) || + (need_fnmatch && !fnmatch(tok, name, 0)); } double __weak perf_pmu__cpu_slots_per_cycle(void) |