tools/perf/Makefile | 2 +- tools/perf/util/parse-events.c | 71 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 2d53738..0ffafa0 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -199,7 +199,7 @@ ifndef PERF_DEBUG endif CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -EXTLIBS = -lpthread -lrt -lelf -lm +EXTLIBS = -lpthread -lrt -lelf -lm -ldl ALL_CFLAGS = $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) STRIP ?= strip diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 05d0c5c..ba4a663 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -8,11 +8,13 @@ #include "cache.h" #include "header.h" #include "debugfs.h" +#include "dlfcn.h" int nr_counters; struct perf_event_attr attrs[MAX_COUNTERS]; char *filters[MAX_COUNTERS]; +char *event_names[MAX_COUNTERS]; struct event_symbol { u8 type; @@ -267,10 +269,7 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) const char *event_name(int counter) { - u64 config = attrs[counter].config; - int type = attrs[counter].type; - - return __event_name(type, config); + return event_names[counter]; } const char *__event_name(int type, u64 config) @@ -324,6 +323,38 @@ const char *__event_name(int type, u64 config) return "unknown"; } +#define PERF_ARCH_DEP_LIB_ENV_VAR "PERF_ARCH_DEP_LIB" + +static int arch_dep_lib_initialized = 0; +static int (*parse_arch_dep_event_callout)(const char **strp, + struct perf_event_attr *attr) = NULL; + +static void initialize_arch_dep_lib(void) +{ + char *lib_name = getenv(PERF_ARCH_DEP_LIB_ENV_VAR); + void *lib_handle; + + if (!lib_name) + return; + + lib_handle = dlopen(lib_name, RTLD_NOW); + if (!lib_handle) { + fprintf(stderr, "The environment variable %s is set to %s, " + "but we couldn't open it. error: %s\n", + PERF_ARCH_DEP_LIB_ENV_VAR, lib_name, dlerror()); + exit(1); + } + parse_arch_dep_event_callout = dlsym(lib_handle, "parse_arch_dep_event"); + if (!parse_arch_dep_event_callout) { + fprintf(stderr, "The environment variable %s is set to %s, " + "but we couldn't obtain from it the required function - " + "parse_arch_dep_event. error: %s\n", + PERF_ARCH_DEP_LIB_ENV_VAR, lib_name, dlerror()); + exit(1); + } + arch_dep_lib_initialized = 1; +} + static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size) { int i, j; @@ -686,6 +717,18 @@ parse_numeric_event(const char **strp, struct perf_event_attr *attr) return EVT_FAILED; } +static int +parse_arch_dep_event(const char **strp, struct perf_event_attr *attr) +{ + if (! arch_dep_lib_initialized) + initialize_arch_dep_lib(); + + if (arch_dep_lib_initialized) + return parse_arch_dep_event_callout(strp, attr); + else + return 0; +} + static enum event_result parse_event_modifier(const char **strp, struct perf_event_attr *attr) { @@ -724,6 +767,11 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr) { enum event_result ret; + ret = parse_arch_dep_event(str, attr); + if (ret != EVT_FAILED) + /* modifiers are already processed */ + return ret; + ret = parse_tracepoint_event(str, attr); if (ret != EVT_FAILED) goto modifier; @@ -784,6 +832,17 @@ static int store_event_type(const char *orgname) return perf_header__push_event(id, orgname); } +static char *make_substr(char *start, char *end) +{ + int length = end - start; + char *result = malloc(length + 1); + + strncpy(result, start, length); + result[length] = '\0'; + + return result; +} + int parse_events(const struct option *opt __used, const char *str, int unset __used) { struct perf_event_attr attr; @@ -794,19 +853,23 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u return -1; for (;;) { + char *start, *end; if (nr_counters == MAX_COUNTERS) return -1; memset(&attr, 0, sizeof(attr)); + start = (char *)str; ret = parse_event_symbols(&str, &attr); if (ret == EVT_FAILED) return -1; if (!(*str == 0 || *str == ',' || isspace(*str))) return -1; + end = (char *)str; if (ret != EVT_HANDLED_ALL) { attrs[nr_counters] = attr; + event_names[nr_counters] = make_substr(start, end); nr_counters++; }