[PATCH/RFC v2 3/3] perf: Extended events (platform-specific) support in perf
Tomasz Fujak
t.fujak at samsung.com
Thu Jan 28 04:34:23 EST 2010
Signed-off-by: Tomasz Fujak <t.fujak at samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski at samsung.com>
Reviewed-by: Kyungmin Park <kyungmin.park at samsung.com>
---
tools/perf/util/parse-events.c | 217 ++++++++++++++++++++++++++++++++++++++--
1 files changed, 206 insertions(+), 11 deletions(-)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e5bc0fb..37a9b25 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -9,6 +9,9 @@
#include "header.h"
#include "debugfs.h"
+#define PLATFORM_EVENT_FILE_NAME\
+ "perf_events_platform"
+
int nr_counters;
struct perf_event_attr attrs[MAX_COUNTERS];
@@ -60,6 +63,10 @@ static struct event_symbol event_symbols[] = {
#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
+static struct event_symbol *platform_event_symbols;
+static unsigned int platform_event_count;
+static int platform_events_initialized;
+
static const char *hw_event_names[] = {
"cycles",
"instructions",
@@ -241,6 +248,150 @@ static const char *tracepoint_id_to_name(u64 config)
return buf;
}
+/* o for valid line, 1 for invalid */
+/* each line format should be "0x%llx\t%s\t%lld-%lld\t%s\n" */
+static int parse_platevent_line(char *line, struct event_symbol *symbol)
+{
+ char *name = NULL;
+ char *description, *ptr, *end;
+ int eaten;
+ unsigned long long discard;
+
+ if (1 != sscanf(line + 2, "%llx", &symbol->config))
+ return 1;
+
+ /* skip 0x%llx\t */
+ ptr = strchr(line + 2, '\t') + 1;
+ if (!ptr)
+ return 1;
+
+ end = strchr(ptr, '\t');
+ if (!end)
+ return 1;
+
+ name = strndup(ptr, end - ptr);
+ ptr = end + 1;
+
+ if (2 != sscanf(ptr, "%lld-%lld\t%n", &discard, &discard, &eaten)) {
+ free(name);
+ return 1;
+ }
+
+
+ description = strdup(ptr + eaten);
+ description[strlen(description) - 1] = 0;
+
+ if (name && description) {
+ symbol->symbol = name;
+ symbol->alias = "";
+ /* description gets lost here */
+ } else
+ free(name);
+ free(description);
+
+ return 0;
+}
+
+#define LINE_SIZE_MAX 256
+/* 0 - event ok, < 0 - unrecoverable error, > 0 - eof */
+static int extract_platevent_item(FILE *file, struct event_symbol *symbol)
+{
+ int result = -1;
+
+ do {
+ char line[LINE_SIZE_MAX];
+
+ if (!fgets(line, LINE_SIZE_MAX, file)) {
+ if (feof(file))
+ return 1;
+ if (ferror(file))
+ return -1;
+ continue;
+ }
+ result = parse_platevent_line(line, symbol);
+ } while (0 < result);
+
+ return result;
+}
+
+#define PATH_LEN_MAX 256
+static int load_platform_events(const char *platevent_entry)
+{
+ FILE *file;
+ int count = 0;
+ int capacity = 16;
+ int result;
+ char platevent_file_path[PATH_LEN_MAX];
+
+ struct event_symbol *symbols = NULL;
+
+ /* if the path is of excessive length, skip it */
+ if (debugfs_make_path(platevent_entry, platevent_file_path,
+ ARRAY_SIZE(platevent_file_path)))
+ return -1;
+
+ file = fopen(platevent_file_path, "r");
+ if (!file) {
+ fprintf(stderr, "can't open platform event file '%s'\n",
+ platevent_file_path);
+ return -1;
+ }
+
+ symbols = (struct event_symbol *)
+ calloc(sizeof(struct event_symbol), capacity);
+ if (!symbols) {
+ fclose(file);
+ return -1;
+ }
+
+ do {
+ result = extract_platevent_item(file, &symbols[count]);
+ if (!result)
+ ++count;
+
+ if (capacity == count) {
+ struct event_symbol *tmp =
+ (struct event_symbol *)realloc(symbols,
+ sizeof(struct event_symbol) *
+ (capacity <<= 1));
+
+ if (!tmp) {
+ result = -1;
+ break;
+ }
+ symbols = tmp;
+ }
+ } while (!result);
+ /* <0 - error */
+
+ fclose(file);
+
+ if ((result < 0) || (0 == count)) {
+ /* ditching the collection for there was a parse error */
+ free(symbols);
+ count = 0;
+ } else {
+ /* trim the collection storage */
+ if (count != capacity)
+ platform_event_symbols = realloc(symbols,
+ sizeof(struct event_symbol) * count);
+ else
+ platform_event_symbols = symbols;
+ platform_event_count = count;
+ }
+ return count;
+}
+
+static struct event_symbol *platevent_find_config(u64 config)
+{
+ unsigned int i;
+ for (i = 0; i < platform_event_count; ++i)
+ if (platform_event_symbols[i].config == config)
+ return &platform_event_symbols[i];
+
+ return NULL;
+}
+
static int is_cache_op_valid(u8 cache_type, u8 cache_op)
{
if (hw_cache_stat[cache_type] & COP(cache_op))
@@ -283,10 +434,16 @@ const char *__event_name(int type, u64 config)
}
switch (type) {
- case PERF_TYPE_HARDWARE:
+ case PERF_TYPE_HARDWARE: {
+ const struct event_symbol *event;
+
if (config < PERF_COUNT_HW_MAX)
return hw_event_names[config];
+ event = platevent_find_config(config);
+ if (event)
+ return event->symbol;
return "unknown-hardware";
+ }
case PERF_TYPE_HW_CACHE: {
u8 cache_type, cache_op, cache_result;
@@ -606,33 +763,34 @@ parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
return EVT_HANDLED;
}
-static int check_events(const char *str, unsigned int i)
+static int check_event(const char *str, const struct event_symbol *event)
{
int n;
- n = strlen(event_symbols[i].symbol);
- if (!strncmp(str, event_symbols[i].symbol, n))
+ n = strlen(event->symbol);
+ if (!strncmp(str, event->symbol, n))
return n;
- n = strlen(event_symbols[i].alias);
+ n = strlen(event->alias);
if (n)
- if (!strncmp(str, event_symbols[i].alias, n))
+ if (!strncmp(str, event->alias, n))
return n;
return 0;
}
static enum event_result
-parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
+do_parse_symbolic_event(const char **strp, struct perf_event_attr *attr,
+ const struct event_symbol *symbols, unsigned int count)
{
const char *str = *strp;
unsigned int i;
int n;
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- n = check_events(str, i);
+ for (i = 0; i < count; ++i) {
+ n = check_event(str, &symbols[i]);
if (n > 0) {
- attr->type = event_symbols[i].type;
- attr->config = event_symbols[i].config;
+ attr->type = symbols[i].type;
+ attr->config = symbols[i].config;
*strp = str + n;
return EVT_HANDLED;
}
@@ -641,6 +799,27 @@ parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
}
static enum event_result
+parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
+{
+ return do_parse_symbolic_event(strp, attr,
+ event_symbols, ARRAY_SIZE(event_symbols));
+}
+
+static enum event_result
+parse_platform_event(const char **strp, struct perf_event_attr *attr)
+{
+ if (!platform_events_initialized)
+ platform_events_initialized =
+ load_platform_events(PLATFORM_EVENT_FILE_NAME);
+
+ if (platform_events_initialized < 0)
+ return EVT_FAILED;
+
+ return do_parse_symbolic_event(strp, attr, platform_event_symbols,
+ platform_event_count);
+}
+
+static enum event_result
parse_raw_event(const char **strp, struct perf_event_attr *attr)
{
const char *str = *strp;
@@ -739,6 +918,10 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
if (ret != EVT_FAILED)
goto modifier;
+ ret = parse_platform_event(str, attr);
+ if (ret != EVT_FAILED)
+ goto modifier;
+
ret = parse_breakpoint_event(str, attr);
if (ret != EVT_FAILED)
goto modifier;
@@ -924,6 +1107,18 @@ void print_events(void)
}
}
+ if (!platform_events_initialized)
+ platform_events_initialized =
+ load_platform_events(PLATFORM_EVENT_FILE_NAME);
+
+ if (0 < platform_events_initialized) {
+ for (i = 0; i < platform_event_count; ++i)
+ printf(" %-42s [%s]\n",
+ platform_event_symbols[i].symbol,
+ "Hardware platform-specific event");
+ }
+
+
printf("\n");
printf(" %-42s [raw hardware event descriptor]\n",
"rNNN");
--
1.5.4.3
More information about the linux-arm-kernel
mailing list