aboutsummaryrefslogtreecommitdiff
path: root/tools/perf/util/parse-events.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r--tools/perf/util/parse-events.c216
1 files changed, 211 insertions, 5 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5184959e061..04417840878 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -5,6 +5,7 @@
#include "parse-events.h"
#include "exec_cmd.h"
#include "string.h"
+#include "cache.h"
extern char *strcasestr(const char *haystack, const char *needle);
@@ -19,6 +20,8 @@ struct event_symbol {
char *alias;
};
+char debugfs_path[MAXPATHLEN];
+
#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -71,8 +74,8 @@ static char *sw_event_names[] = {
#define MAX_ALIASES 8
static char *hw_cache[][MAX_ALIASES] = {
- { "L1-d$", "l1-d", "l1d", "L1-data", },
- { "L1-i$", "l1-i", "l1i", "L1-instruction", },
+ { "L1-dcache", "l1-d", "l1d", "L1-data", },
+ { "L1-icache", "l1-i", "l1i", "L1-instruction", },
{ "LLC", "L2" },
{ "dTLB", "d-tlb", "Data-TLB", },
{ "iTLB", "i-tlb", "Instruction-TLB", },
@@ -110,6 +113,104 @@ static unsigned long hw_cache_stat[C(MAX)] = {
[C(BPU)] = (CACHE_READ),
};
+#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \
+ while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
+ if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \
+ sys_dirent.d_name) && \
+ (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
+ (strcmp(sys_dirent.d_name, ".")) && \
+ (strcmp(sys_dirent.d_name, "..")))
+
+static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
+{
+ char evt_path[MAXPATHLEN];
+ int fd;
+
+ snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
+ sys_dir->d_name, evt_dir->d_name);
+ fd = open(evt_path, O_RDONLY);
+ if (fd < 0)
+ return -EINVAL;
+ close(fd);
+
+ return 0;
+}
+
+#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \
+ while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
+ if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \
+ sys_dirent.d_name, evt_dirent.d_name) && \
+ (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
+ (strcmp(evt_dirent.d_name, ".")) && \
+ (strcmp(evt_dirent.d_name, "..")) && \
+ (!tp_event_has_id(&sys_dirent, &evt_dirent)))
+
+#define MAX_EVENT_LENGTH 30
+
+int valid_debugfs_mount(const char *debugfs)
+{
+ struct statfs st_fs;
+
+ if (statfs(debugfs, &st_fs) < 0)
+ return -ENOENT;
+ else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
+ return -ENOENT;
+ return 0;
+}
+
+static char *tracepoint_id_to_name(u64 config)
+{
+ static char tracepoint_name[2 * MAX_EVENT_LENGTH];
+ DIR *sys_dir, *evt_dir;
+ struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
+ struct stat st;
+ char id_buf[4];
+ int fd;
+ u64 id;
+ char evt_path[MAXPATHLEN];
+
+ if (valid_debugfs_mount(debugfs_path))
+ return "unkown";
+
+ sys_dir = opendir(debugfs_path);
+ if (!sys_dir)
+ goto cleanup;
+
+ for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
+ evt_dir = opendir(evt_path);
+ if (!evt_dir)
+ goto cleanup;
+ for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
+ evt_path, st) {
+ snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
+ debugfs_path, sys_dirent.d_name,
+ evt_dirent.d_name);
+ fd = open(evt_path, O_RDONLY);
+ if (fd < 0)
+ continue;
+ if (read(fd, id_buf, sizeof(id_buf)) < 0) {
+ close(fd);
+ continue;
+ }
+ close(fd);
+ id = atoll(id_buf);
+ if (id == config) {
+ closedir(evt_dir);
+ closedir(sys_dir);
+ snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
+ "%s:%s", sys_dirent.d_name,
+ evt_dirent.d_name);
+ return tracepoint_name;
+ }
+ }
+ closedir(evt_dir);
+ }
+
+cleanup:
+ closedir(sys_dir);
+ return "unkown";
+}
+
static int is_cache_op_valid(u8 cache_type, u8 cache_op)
{
if (hw_cache_stat[cache_type] & COP(cache_op))
@@ -138,9 +239,15 @@ char *event_name(int counter)
{
u64 config = attrs[counter].config;
int type = attrs[counter].type;
+
+ return __event_name(type, config);
+}
+
+char *__event_name(int type, u64 config)
+{
static char buf[32];
- if (attrs[counter].type == PERF_TYPE_RAW) {
+ if (type == PERF_TYPE_RAW) {
sprintf(buf, "raw 0x%llx", config);
return buf;
}
@@ -177,6 +284,9 @@ char *event_name(int counter)
return sw_event_names[config];
return "unknown-software";
+ case PERF_TYPE_TRACEPOINT:
+ return tracepoint_id_to_name(config);
+
default:
break;
}
@@ -265,6 +375,63 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
return 1;
}
+static int parse_tracepoint_event(const char **strp,
+ struct perf_counter_attr *attr)
+{
+ const char *evt_name;
+ char *flags;
+ char sys_name[MAX_EVENT_LENGTH];
+ char id_buf[4];
+ int fd;
+ unsigned int sys_length, evt_length;
+ u64 id;
+ char evt_path[MAXPATHLEN];
+
+ if (valid_debugfs_mount(debugfs_path))
+ return 0;
+
+ evt_name = strchr(*strp, ':');
+ if (!evt_name)
+ return 0;
+
+ sys_length = evt_name - *strp;
+ if (sys_length >= MAX_EVENT_LENGTH)
+ return 0;
+
+ strncpy(sys_name, *strp, sys_length);
+ sys_name[sys_length] = '\0';
+ evt_name = evt_name + 1;
+
+ flags = strchr(evt_name, ':');
+ if (flags) {
+ *flags = '\0';
+ flags++;
+ if (!strncmp(flags, "record", strlen(flags)))
+ attr->sample_type |= PERF_SAMPLE_RAW;
+ }
+
+ evt_length = strlen(evt_name);
+ if (evt_length >= MAX_EVENT_LENGTH)
+ return 0;
+
+ snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
+ sys_name, evt_name);
+ fd = open(evt_path, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ if (read(fd, id_buf, sizeof(id_buf)) < 0) {
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ id = atoll(id_buf);
+ attr->config = id;
+ attr->type = PERF_TYPE_TRACEPOINT;
+ *strp = evt_name + evt_length;
+ return 1;
+}
+
static int check_events(const char *str, unsigned int i)
{
int n;
@@ -374,7 +541,8 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
*/
static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
{
- if (!(parse_raw_event(str, attr) ||
+ if (!(parse_tracepoint_event(str, attr) ||
+ parse_raw_event(str, attr) ||
parse_numeric_event(str, attr) ||
parse_symbolic_event(str, attr) ||
parse_generic_hw_event(str, attr)))
@@ -423,6 +591,42 @@ static const char * const event_type_descriptors[] = {
};
/*
+ * Print the events from <debugfs_mount_point>/tracing/events
+ */
+
+static void print_tracepoint_events(void)
+{
+ DIR *sys_dir, *evt_dir;
+ struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
+ struct stat st;
+ char evt_path[MAXPATHLEN];
+
+ if (valid_debugfs_mount(debugfs_path))
+ return;
+
+ sys_dir = opendir(debugfs_path);
+ if (!sys_dir)
+ goto cleanup;
+
+ for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
+ evt_dir = opendir(evt_path);
+ if (!evt_dir)
+ goto cleanup;
+ for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
+ evt_path, st) {
+ snprintf(evt_path, MAXPATHLEN, "%s:%s",
+ sys_dirent.d_name, evt_dirent.d_name);
+ fprintf(stderr, " %-40s [%s]\n", evt_path,
+ event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
+ }
+ closedir(evt_dir);
+ }
+
+cleanup:
+ closedir(sys_dir);
+}
+
+/*
* Print the help text for the event symbols:
*/
void print_events(void)
@@ -436,7 +640,7 @@ void print_events(void)
for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
type = syms->type + 1;
- if (type > ARRAY_SIZE(event_type_descriptors))
+ if (type >= ARRAY_SIZE(event_type_descriptors))
type = 0;
if (type != prev_type)
@@ -472,5 +676,7 @@ void print_events(void)
"rNNN");
fprintf(stderr, "\n");
+ print_tracepoint_events();
+
exit(129);
}