Skip to content

Commit

Permalink
perf_counter: Add tracepoint support to perf list, perf stat
Browse files Browse the repository at this point in the history
Add support to 'perf list' and 'perf stat' for kernel tracepoints. The
implementation creates a 'for_each_subsystem' and 'for_each_event' for
easy iteration over the tracepoints.

Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <426129bf9fcc8ee63bb094cf736e7316a7dcd77a.1248190728.git.jbaron@redhat.com>
  • Loading branch information
Jason Baron authored and Peter Zijlstra committed Jul 22, 2009
1 parent 28ac909 commit f6bdafe
Showing 2 changed files with 176 additions and 1 deletion.
175 changes: 174 additions & 1 deletion tools/perf/util/parse-events.c
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@ int nr_counters;

struct perf_counter_attr attrs[MAX_COUNTERS];

static char default_debugfs_path[] = "/sys/kernel/debug/tracing/events";

struct event_symbol {
u8 type;
u64 config;
@@ -110,6 +112,88 @@ 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", default_debugfs_path, \
sys_dirent.d_name) && \
(!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
(strcmp(sys_dirent.d_name, ".")) && \
(strcmp(sys_dirent.d_name, "..")))

#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", default_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, "..")))

#define MAX_EVENT_LENGTH 30

static int valid_debugfs_mount(void)
{
struct statfs st_fs;

if (statfs(default_debugfs_path, &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())
return "unkown";

sys_dir = opendir(default_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",
default_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))
@@ -177,6 +261,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 +352,53 @@ 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 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())
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;
evt_length = strlen(evt_name);
if (evt_length >= MAX_EVENT_LENGTH)
return 0;

snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", default_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 +508,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)))
@@ -422,6 +557,42 @@ static const char * const event_type_descriptors[] = {
"Hardware cache event",
};

/*
* 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())
return;

sys_dir = opendir(default_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:
*/
@@ -472,5 +643,7 @@ void print_events(void)
"rNNN");
fprintf(stderr, "\n");

print_tracepoint_events();

exit(129);
}
2 changes: 2 additions & 0 deletions tools/perf/util/util.h
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
@@ -80,6 +81,7 @@
#include <netdb.h>
#include <pwd.h>
#include <inttypes.h>
#include "../../../include/linux/magic.h"

#ifndef NO_ICONV
#include <iconv.h>

0 comments on commit f6bdafe

Please sign in to comment.