[PATCH 6/6] perf trace: Add filter support

From: Li Zefan
Date: Mon Sep 07 2009 - 04:15:52 EST


#./perf record -f -e irq:irq_handler_entry:irq==18:record
or
#./perf record -f -e irq:irq_handler_entry:irq==18 -R
^C
# ./perf trace
version = 0.5
perf-4303 ... irq_handler_entry: irq=18 handler=eth0
init-0 ... irq_handler_entry: irq=18 handler=eth0
init-0 ... irq_handler_entry: irq=18 handler=eth0
init-0 ... irq_handler_entry: irq=18 handler=eth0
init-0 ... irq_handler_entry: irq=18 handler=eth0

The usage is not changed if filter is not used:

#./perf record -f -e irq:irq_handler_entry:record

Signed-off-by: Li Zefan <lizf@xxxxxxxxxxxxxx>
---
tools/perf/builtin-record.c | 12 ++++++++++
tools/perf/util/parse-events.c | 46 +++++++++++++++++++++++++++++++++------
tools/perf/util/parse-events.h | 1 +
3 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 99a12fe..7749982 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -369,9 +369,11 @@ static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int

static void create_counter(int counter, int cpu, pid_t pid)
{
+ char *filter = filters[counter];
struct perf_counter_attr *attr = attrs + counter;
struct perf_header_attr *h_attr;
int track = !counter; /* only the first counter needs these */
+ int ret;
struct {
u64 count;
u64 time_enabled;
@@ -485,6 +487,16 @@ try_again:
exit(-1);
}

+ if (attr->type == PERF_TYPE_TRACEPOINT && filter != NULL) {
+ ret = ioctl(fd[nr_cpu][counter],
+ PERF_COUNTER_IOC_SET_FILTER, filter);
+ if (ret) {
+ error("failed to set filter with %d (%s)\n", errno,
+ strerror(errno));
+ exit(-1);
+ }
+ }
+
ioctl(fd[nr_cpu][counter], PERF_COUNTER_IOC_ENABLE);
}

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 892d931..a7d2ef6 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -10,6 +10,7 @@
int nr_counters;

struct perf_counter_attr attrs[MAX_COUNTERS];
+char *filters[MAX_COUNTERS];

struct event_symbol {
u8 type;
@@ -405,15 +406,26 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
return 1;
}

+static int tracepoint_event_set_flags(const char *flags,
+ struct perf_counter_attr *attr)
+{
+ if (!strncmp(flags, "record", strlen(flags))) {
+ attr->sample_type |= PERF_SAMPLE_RAW;
+ return 1;
+ }
+ return 0;
+}
+
static int parse_tracepoint_event(const char **strp,
struct perf_counter_attr *attr)
{
+ char sys_name[MAX_EVENT_LENGTH];
const char *evt_name;
+ char *filter;
char *flags;
- char sys_name[MAX_EVENT_LENGTH];
char id_buf[4];
int fd;
- unsigned int sys_length, evt_length;
+ unsigned int sys_length, evt_length, filter_length;
u64 id;
char evt_path[MAXPATHLEN];

@@ -433,13 +445,33 @@ static int parse_tracepoint_event(const char **strp,
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;
+ if (!flags)
+ goto next;
+
+ *flags++ = '\0';
+ if (tracepoint_event_set_flags(flags, attr))
+ goto next;
+
+ filter = flags;
+
+ flags = strchr(filter, ':');
+ if (!flags)
+ filter_length = strlen(filter);
+ else {
+ filter_length = flags++ - filter;
+ if (!tracepoint_event_set_flags(flags, attr))
+ return 0;
+ }
+
+ filters[nr_counters] = malloc(filter_length + 1);
+ if (!filters[nr_counters]) {
+ fprintf(stderr, "Not enough memory to hold filter string\n");
+ exit(-1);
}
+ strncpy(filters[nr_counters], filter, filter_length);
+ filters[nr_counters][filter_length] = '\0';

+next:
evt_length = strlen(evt_name);
if (evt_length >= MAX_EVENT_LENGTH)
return 0;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 60704c1..0ae146e 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -17,6 +17,7 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern int nr_counters;

extern struct perf_counter_attr attrs[MAX_COUNTERS];
+extern char *filters[MAX_COUNTERS];

extern const char *event_name(int ctr);
extern const char *__event_name(int type, u64 config);
-- 1.6.3
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/