* [PATCH 2/4] tracing/filters: Use a different op for glob match
2009-10-13 2:17 [PATCH 0/4] perf trace: Add filter Suppport, V2 Li Zefan
@ 2009-10-13 2:18 ` Li Zefan
0 siblings, 0 replies; 14+ messages in thread
From: Li Zefan @ 2009-10-13 2:18 UTC (permalink / raw)
To: Ingo Molnar
Cc: Peter Zijlstra, Frederic Weisbecker, Steven Rostedt, Tom Zanussi,
LKML
"==" will always do a full match, and "~" will do a glob match.
In the future, we may add "=~" for regex match.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
kernel/trace/trace.h | 2 +-
kernel/trace/trace_events_filter.c | 59 +++++++++++++++++-------------------
2 files changed, 29 insertions(+), 32 deletions(-)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 300cdae..b5f30d5 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -724,7 +724,7 @@ typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
typedef int (*regex_match_func)(char *str, struct regex *r, int len);
enum regex_type {
- MATCH_FULL,
+ MATCH_FULL = 0,
MATCH_FRONT_ONLY,
MATCH_MIDDLE_ONLY,
MATCH_END_ONLY,
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 1d22749..c7e1a54 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -29,6 +29,7 @@ enum filter_op_ids
{
OP_OR,
OP_AND,
+ OP_GLOB,
OP_NE,
OP_EQ,
OP_LT,
@@ -46,16 +47,17 @@ struct filter_op {
};
static struct filter_op filter_ops[] = {
- { OP_OR, "||", 1 },
- { OP_AND, "&&", 2 },
- { OP_NE, "!=", 4 },
- { OP_EQ, "==", 4 },
- { OP_LT, "<", 5 },
- { OP_LE, "<=", 5 },
- { OP_GT, ">", 5 },
- { OP_GE, ">=", 5 },
- { OP_NONE, "OP_NONE", 0 },
- { OP_OPEN_PAREN, "(", 0 },
+ { OP_OR, "||", 1 },
+ { OP_AND, "&&", 2 },
+ { OP_GLOB, "~", 4 },
+ { OP_NE, "!=", 4 },
+ { OP_EQ, "==", 4 },
+ { OP_LT, "<", 5 },
+ { OP_LE, "<=", 5 },
+ { OP_GT, ">", 5 },
+ { OP_GE, ">=", 5 },
+ { OP_NONE, "OP_NONE", 0 },
+ { OP_OPEN_PAREN, "(", 0 },
};
enum {
@@ -329,22 +331,18 @@ enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not)
return type;
}
-static int filter_build_regex(struct filter_pred *pred)
+static void filter_build_regex(struct filter_pred *pred)
{
struct regex *r = &pred->regex;
- char *search, *dup;
- enum regex_type type;
- int not;
-
- type = filter_parse_regex(r->pattern, r->len, &search, ¬);
- dup = kstrdup(search, GFP_KERNEL);
- if (!dup)
- return -ENOMEM;
-
- strcpy(r->pattern, dup);
- kfree(dup);
-
- r->len = strlen(r->pattern);
+ char *search;
+ enum regex_type type = MATCH_FULL;
+ int not = 0;
+
+ if (pred->op == OP_GLOB) {
+ type = filter_parse_regex(r->pattern, r->len, &search, ¬);
+ r->len = strlen(search);
+ memmove(r->pattern, search, r->len+1);
+ }
switch (type) {
case MATCH_FULL:
@@ -362,8 +360,6 @@ static int filter_build_regex(struct filter_pred *pred)
}
pred->not ^= not;
-
- return 0;
}
/* return 1 if event matches, 0 otherwise (discard) */
@@ -676,7 +672,10 @@ static bool is_string_field(struct ftrace_event_field *field)
static int is_legal_op(struct ftrace_event_field *field, int op)
{
- if (is_string_field(field) && (op != OP_EQ && op != OP_NE))
+ if (is_string_field(field) &&
+ (op != OP_EQ && op != OP_NE && op != OP_GLOB))
+ return 0;
+ if (!is_string_field(field) && op == OP_GLOB)
return 0;
return 1;
@@ -761,15 +760,13 @@ static int filter_add_pred(struct filter_parse_state *ps,
}
if (is_string_field(field)) {
- ret = filter_build_regex(pred);
- if (ret)
- return ret;
+ filter_build_regex(pred);
if (field->filter_type == FILTER_STATIC_STRING) {
fn = filter_pred_string;
pred->regex.field_len = field->size;
} else if (field->filter_type == FILTER_DYN_STRING)
- fn = filter_pred_strloc;
+ fn = filter_pred_strloc;
else {
fn = filter_pred_pchar;
pred->regex.field_len = strlen(pred->regex.pattern);
--
1.6.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 0/4] perf trace: Add filter Suppport, V3
@ 2009-10-15 3:19 Li Zefan
2009-10-15 3:20 ` [PATCH 1/4] tracing/filters: Refactor subsystem filter code Li Zefan
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Li Zefan @ 2009-10-15 3:19 UTC (permalink / raw)
To: Ingo Molnar
Cc: Peter Zijlstra, Frederic Weisbecker, Steven Rostedt, Tom Zanussi,
LKML
This patchset adds filter support for perf event, so not all
profile events are recorded but only those match the filters
we set.
An example:
#./perf record -R -f -e irq:irq_handler_entry --filter irq==18
^C
# ./perf trace
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 syntax of filter expressions can be found in
Documentation/trace/events.txt.
Major changes since V2:
- Remove struct perf_event::filter_active.
Major changes since V1:
- Make filters per perf event, instead of per tracepoint.
- Use "--filter" to set a filter for a trace event, instead of
mixing it into "-e" option.
---
include/linux/ftrace_event.h | 11 ++-
include/linux/perf_counter.h | 1 +
include/linux/perf_event.h | 6 +
kernel/perf_event.c | 80 +++++++++-
kernel/trace/trace.h | 6 +-
kernel/trace/trace_events_filter.c | 302 +++++++++++++++++++++---------------
tools/perf/builtin-record.c | 15 ++-
tools/perf/util/parse-events.c | 26 +++-
tools/perf/util/parse-events.h | 2 +
9 files changed, 306 insertions(+), 143 deletions(-)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/4] tracing/filters: Refactor subsystem filter code
2009-10-15 3:19 [PATCH 0/4] perf trace: Add filter Suppport, V3 Li Zefan
@ 2009-10-15 3:20 ` Li Zefan
2009-10-15 9:39 ` [tip:perf/core] " tip-bot for Li Zefan
2009-10-15 3:21 ` [PATCH 2/4] tracing/filters: Use a different op for glob match Li Zefan
` (2 subsequent siblings)
3 siblings, 1 reply; 14+ messages in thread
From: Li Zefan @ 2009-10-15 3:20 UTC (permalink / raw)
To: Ingo Molnar
Cc: Peter Zijlstra, Frederic Weisbecker, Steven Rostedt, Tom Zanussi,
LKML
Change:
for_each_pred
for_each_subsystem
To:
for_each_subsystem
for_each_pred
This change also prepares for later patches.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
kernel/trace/trace.h | 1 -
kernel/trace/trace_events_filter.c | 124 +++++++++++++-----------------------
2 files changed, 45 insertions(+), 80 deletions(-)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index b17e0ea..300cdae 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -705,7 +705,6 @@ struct event_filter {
int n_preds;
struct filter_pred **preds;
char *filter_string;
- bool no_reset;
};
struct event_subsystem {
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 8c194de..1d22749 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -615,14 +615,7 @@ static int init_subsystem_preds(struct event_subsystem *system)
return 0;
}
-enum {
- FILTER_DISABLE_ALL,
- FILTER_INIT_NO_RESET,
- FILTER_SKIP_NO_RESET,
-};
-
-static void filter_free_subsystem_preds(struct event_subsystem *system,
- int flag)
+static void filter_free_subsystem_preds(struct event_subsystem *system)
{
struct ftrace_event_call *call;
@@ -633,14 +626,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
if (strcmp(call->system, system->name) != 0)
continue;
- if (flag == FILTER_INIT_NO_RESET) {
- call->filter->no_reset = false;
- continue;
- }
-
- if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset)
- continue;
-
filter_disable_preds(call);
remove_filter_string(call->filter);
}
@@ -817,44 +802,6 @@ add_pred_fn:
return 0;
}
-static int filter_add_subsystem_pred(struct filter_parse_state *ps,
- struct event_subsystem *system,
- struct filter_pred *pred,
- char *filter_string,
- bool dry_run)
-{
- struct ftrace_event_call *call;
- int err = 0;
- bool fail = true;
-
- list_for_each_entry(call, &ftrace_events, list) {
-
- if (!call->define_fields)
- continue;
-
- if (strcmp(call->system, system->name))
- continue;
-
- if (call->filter->no_reset)
- continue;
-
- err = filter_add_pred(ps, call, pred, dry_run);
- if (err)
- call->filter->no_reset = true;
- else
- fail = false;
-
- if (!dry_run)
- replace_filter_string(call->filter, filter_string);
- }
-
- if (fail) {
- parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
- return err;
- }
- return 0;
-}
-
static void parse_init(struct filter_parse_state *ps,
struct filter_op *ops,
char *infix_string)
@@ -1208,8 +1155,7 @@ static int check_preds(struct filter_parse_state *ps)
return 0;
}
-static int replace_preds(struct event_subsystem *system,
- struct ftrace_event_call *call,
+static int replace_preds(struct ftrace_event_call *call,
struct filter_parse_state *ps,
char *filter_string,
bool dry_run)
@@ -1256,11 +1202,7 @@ static int replace_preds(struct event_subsystem *system,
add_pred:
if (!pred)
return -ENOMEM;
- if (call)
- err = filter_add_pred(ps, call, pred, false);
- else
- err = filter_add_subsystem_pred(ps, system, pred,
- filter_string, dry_run);
+ err = filter_add_pred(ps, call, pred, dry_run);
filter_free_pred(pred);
if (err)
return err;
@@ -1271,6 +1213,44 @@ add_pred:
return 0;
}
+static int replace_system_preds(struct event_subsystem *system,
+ struct filter_parse_state *ps,
+ char *filter_string)
+{
+ struct ftrace_event_call *call;
+ int err;
+ bool fail = true;
+
+ list_for_each_entry(call, &ftrace_events, list) {
+
+ if (!call->define_fields)
+ continue;
+
+ if (strcmp(call->system, system->name) != 0)
+ continue;
+
+ /* try to see if the filter can be applied */
+ err = replace_preds(call, ps, filter_string, true);
+ if (err)
+ continue;
+
+ /* really apply the filter */
+ filter_disable_preds(call);
+ err = replace_preds(call, ps, filter_string, false);
+ if (err)
+ filter_disable_preds(call);
+ else
+ replace_filter_string(call->filter, filter_string);
+ fail = false;
+ }
+
+ if (fail) {
+ parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
+ return err;
+ }
+ return 0;
+}
+
int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
{
int err;
@@ -1305,7 +1285,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
goto out;
}
- err = replace_preds(NULL, call, ps, filter_string, false);
+ err = replace_preds(call, ps, filter_string, false);
if (err)
append_filter_err(ps, call->filter);
@@ -1333,7 +1313,7 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
goto out_unlock;
if (!strcmp(strstrip(filter_string), "0")) {
- filter_free_subsystem_preds(system, FILTER_DISABLE_ALL);
+ filter_free_subsystem_preds(system);
remove_filter_string(system->filter);
mutex_unlock(&event_mutex);
return 0;
@@ -1353,23 +1333,9 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
goto out;
}
- filter_free_subsystem_preds(system, FILTER_INIT_NO_RESET);
-
- /* try to see the filter can be applied to which events */
- err = replace_preds(system, NULL, ps, filter_string, true);
- if (err) {
- append_filter_err(ps, system->filter);
- goto out;
- }
-
- filter_free_subsystem_preds(system, FILTER_SKIP_NO_RESET);
-
- /* really apply the filter to the events */
- err = replace_preds(system, NULL, ps, filter_string, false);
- if (err) {
+ err = replace_system_preds(system, ps, filter_string);
+ if (err)
append_filter_err(ps, system->filter);
- filter_free_subsystem_preds(system, 2);
- }
out:
filter_opstack_clear(ps);
--
1.6.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/4] tracing/filters: Use a different op for glob match
2009-10-15 3:19 [PATCH 0/4] perf trace: Add filter Suppport, V3 Li Zefan
2009-10-15 3:20 ` [PATCH 1/4] tracing/filters: Refactor subsystem filter code Li Zefan
@ 2009-10-15 3:21 ` Li Zefan
2009-10-15 9:40 ` [tip:perf/core] " tip-bot for Li Zefan
2009-10-15 12:52 ` [PATCH 2/4] " Frederic Weisbecker
2009-10-15 3:21 ` [PATCH 3/4] tracing/profile: Add filter support Li Zefan
2009-10-15 3:22 ` [PATCH 4/4] perf trace: Add filter Suppport Li Zefan
3 siblings, 2 replies; 14+ messages in thread
From: Li Zefan @ 2009-10-15 3:21 UTC (permalink / raw)
To: Ingo Molnar
Cc: Peter Zijlstra, Frederic Weisbecker, Steven Rostedt, Tom Zanussi,
LKML
"==" will always do a full match, and "~" will do a glob match.
In the future, we may add "=~" for regex match.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
kernel/trace/trace.h | 2 +-
kernel/trace/trace_events_filter.c | 59 +++++++++++++++++-------------------
2 files changed, 29 insertions(+), 32 deletions(-)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 300cdae..b5f30d5 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -724,7 +724,7 @@ typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
typedef int (*regex_match_func)(char *str, struct regex *r, int len);
enum regex_type {
- MATCH_FULL,
+ MATCH_FULL = 0,
MATCH_FRONT_ONLY,
MATCH_MIDDLE_ONLY,
MATCH_END_ONLY,
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 1d22749..c7e1a54 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -29,6 +29,7 @@ enum filter_op_ids
{
OP_OR,
OP_AND,
+ OP_GLOB,
OP_NE,
OP_EQ,
OP_LT,
@@ -46,16 +47,17 @@ struct filter_op {
};
static struct filter_op filter_ops[] = {
- { OP_OR, "||", 1 },
- { OP_AND, "&&", 2 },
- { OP_NE, "!=", 4 },
- { OP_EQ, "==", 4 },
- { OP_LT, "<", 5 },
- { OP_LE, "<=", 5 },
- { OP_GT, ">", 5 },
- { OP_GE, ">=", 5 },
- { OP_NONE, "OP_NONE", 0 },
- { OP_OPEN_PAREN, "(", 0 },
+ { OP_OR, "||", 1 },
+ { OP_AND, "&&", 2 },
+ { OP_GLOB, "~", 4 },
+ { OP_NE, "!=", 4 },
+ { OP_EQ, "==", 4 },
+ { OP_LT, "<", 5 },
+ { OP_LE, "<=", 5 },
+ { OP_GT, ">", 5 },
+ { OP_GE, ">=", 5 },
+ { OP_NONE, "OP_NONE", 0 },
+ { OP_OPEN_PAREN, "(", 0 },
};
enum {
@@ -329,22 +331,18 @@ enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not)
return type;
}
-static int filter_build_regex(struct filter_pred *pred)
+static void filter_build_regex(struct filter_pred *pred)
{
struct regex *r = &pred->regex;
- char *search, *dup;
- enum regex_type type;
- int not;
-
- type = filter_parse_regex(r->pattern, r->len, &search, ¬);
- dup = kstrdup(search, GFP_KERNEL);
- if (!dup)
- return -ENOMEM;
-
- strcpy(r->pattern, dup);
- kfree(dup);
-
- r->len = strlen(r->pattern);
+ char *search;
+ enum regex_type type = MATCH_FULL;
+ int not = 0;
+
+ if (pred->op == OP_GLOB) {
+ type = filter_parse_regex(r->pattern, r->len, &search, ¬);
+ r->len = strlen(search);
+ memmove(r->pattern, search, r->len+1);
+ }
switch (type) {
case MATCH_FULL:
@@ -362,8 +360,6 @@ static int filter_build_regex(struct filter_pred *pred)
}
pred->not ^= not;
-
- return 0;
}
/* return 1 if event matches, 0 otherwise (discard) */
@@ -676,7 +672,10 @@ static bool is_string_field(struct ftrace_event_field *field)
static int is_legal_op(struct ftrace_event_field *field, int op)
{
- if (is_string_field(field) && (op != OP_EQ && op != OP_NE))
+ if (is_string_field(field) &&
+ (op != OP_EQ && op != OP_NE && op != OP_GLOB))
+ return 0;
+ if (!is_string_field(field) && op == OP_GLOB)
return 0;
return 1;
@@ -761,15 +760,13 @@ static int filter_add_pred(struct filter_parse_state *ps,
}
if (is_string_field(field)) {
- ret = filter_build_regex(pred);
- if (ret)
- return ret;
+ filter_build_regex(pred);
if (field->filter_type == FILTER_STATIC_STRING) {
fn = filter_pred_string;
pred->regex.field_len = field->size;
} else if (field->filter_type == FILTER_DYN_STRING)
- fn = filter_pred_strloc;
+ fn = filter_pred_strloc;
else {
fn = filter_pred_pchar;
pred->regex.field_len = strlen(pred->regex.pattern);
--
1.6.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/4] tracing/profile: Add filter support
2009-10-15 3:19 [PATCH 0/4] perf trace: Add filter Suppport, V3 Li Zefan
2009-10-15 3:20 ` [PATCH 1/4] tracing/filters: Refactor subsystem filter code Li Zefan
2009-10-15 3:21 ` [PATCH 2/4] tracing/filters: Use a different op for glob match Li Zefan
@ 2009-10-15 3:21 ` Li Zefan
2009-10-15 9:40 ` [tip:perf/core] " tip-bot for Li Zefan
2009-10-15 9:47 ` [PATCH 3/4] " Américo Wang
2009-10-15 3:22 ` [PATCH 4/4] perf trace: Add filter Suppport Li Zefan
3 siblings, 2 replies; 14+ messages in thread
From: Li Zefan @ 2009-10-15 3:21 UTC (permalink / raw)
To: Ingo Molnar
Cc: Peter Zijlstra, Frederic Weisbecker, Steven Rostedt, Tom Zanussi,
LKML
- Add an ioctl to allocate a filter for a perf event.
- Free the filter when the associated perf event is to be freed.
- Do the filtering in perf_swevent_match().
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
include/linux/ftrace_event.h | 11 +++-
include/linux/perf_counter.h | 1 +
include/linux/perf_event.h | 6 ++
kernel/perf_event.c | 80 ++++++++++++++++++++--
kernel/trace/trace.h | 3 +-
kernel/trace/trace_events_filter.c | 133 +++++++++++++++++++++++++++++-------
6 files changed, 199 insertions(+), 35 deletions(-)
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 4ec5e67..d117704 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -144,7 +144,7 @@ extern char *trace_profile_buf_nmi;
#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */
extern void destroy_preds(struct ftrace_event_call *call);
-extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
+extern int filter_match_preds(struct event_filter *filter, void *rec);
extern int filter_current_check_discard(struct ring_buffer *buffer,
struct ftrace_event_call *call,
void *rec,
@@ -186,4 +186,13 @@ do { \
__trace_printk(ip, fmt, ##args); \
} while (0)
+#ifdef CONFIG_EVENT_PROFILE
+struct perf_event;
+extern int ftrace_profile_enable(int event_id);
+extern void ftrace_profile_disable(int event_id);
+extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+ char *filter_str);
+extern void ftrace_profile_free_filter(struct perf_event *event);
+#endif
+
#endif /* _LINUX_FTRACE_EVENT_H */
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 7b7fbf4..91a2b43 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -225,6 +225,7 @@ struct perf_counter_attr {
#define PERF_COUNTER_IOC_RESET _IO ('$', 3)
#define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_COUNTER_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_counter_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 2e6d95f..df9d964 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -221,6 +221,7 @@ struct perf_event_attr {
#define PERF_EVENT_IOC_RESET _IO ('$', 3)
#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
@@ -633,7 +634,12 @@ struct perf_event {
struct pid_namespace *ns;
u64 id;
+
+#ifdef CONFIG_EVENT_PROFILE
+ struct event_filter *filter;
#endif
+
+#endif /* CONFIG_PERF_EVENTS */
};
/**
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 9d0b5c6..12b5ec3 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -28,6 +28,7 @@
#include <linux/anon_inodes.h>
#include <linux/kernel_stat.h>
#include <linux/perf_event.h>
+#include <linux/ftrace_event.h>
#include <asm/irq_regs.h>
@@ -1658,6 +1659,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
return ERR_PTR(err);
}
+static void perf_event_free_filter(struct perf_event *event);
+
static void free_event_rcu(struct rcu_head *head)
{
struct perf_event *event;
@@ -1665,6 +1668,7 @@ static void free_event_rcu(struct rcu_head *head)
event = container_of(head, struct perf_event, rcu_head);
if (event->ns)
put_pid_ns(event->ns);
+ perf_event_free_filter(event);
kfree(event);
}
@@ -1974,7 +1978,8 @@ unlock:
return ret;
}
-int perf_event_set_output(struct perf_event *event, int output_fd);
+static int perf_event_set_output(struct perf_event *event, int output_fd);
+static int perf_event_set_filter(struct perf_event *event, void __user *arg);
static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -2002,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PERF_EVENT_IOC_SET_OUTPUT:
return perf_event_set_output(event, arg);
+ case PERF_EVENT_IOC_SET_FILTER:
+ return perf_event_set_filter(event, (void __user *)arg);
+
default:
return -ENOTTY;
}
@@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event)
return 1;
}
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data);
+
static int perf_swevent_match(struct perf_event *event,
enum perf_type_id type,
- u32 event_id, struct pt_regs *regs)
+ u32 event_id,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
{
if (!perf_swevent_is_counting(event))
return 0;
@@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event,
return 0;
}
+ if (event->attr.type == PERF_TYPE_TRACEPOINT &&
+ !perf_tp_event_match(event, data))
+ return 0;
+
return 1;
}
@@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx,
rcu_read_lock();
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
- if (perf_swevent_match(event, type, event_id, regs))
+ if (perf_swevent_match(event, type, event_id, data, regs))
perf_swevent_add(event, nr, nmi, data, regs);
}
rcu_read_unlock();
@@ -4086,6 +4103,7 @@ static const struct pmu perf_ops_task_clock = {
};
#ifdef CONFIG_EVENT_PROFILE
+
void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size)
{
@@ -4109,8 +4127,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
}
EXPORT_SYMBOL_GPL(perf_tp_event);
-extern int ftrace_profile_enable(int);
-extern void ftrace_profile_disable(int);
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data)
+{
+ void *record = data->raw->data;
+
+ if (likely(!event->filter) || filter_match_preds(event->filter, record))
+ return 1;
+ return 0;
+}
static void tp_perf_event_destroy(struct perf_event *event)
{
@@ -4135,12 +4160,53 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
return &perf_ops_generic;
}
+
+static int perf_event_set_filter(struct perf_event *event, void __user *arg)
+{
+ char *filter_str;
+ int ret;
+
+ if (event->attr.type != PERF_TYPE_TRACEPOINT)
+ return -EINVAL;
+
+ filter_str = strndup_user(arg, PAGE_SIZE);
+ if (IS_ERR(filter_str))
+ return PTR_ERR(filter_str);
+
+ ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);
+
+ kfree(filter_str);
+ return ret;
+}
+
+static void perf_event_free_filter(struct perf_event *event)
+{
+ ftrace_profile_free_filter(event);
+}
+
#else
+
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data)
+{
+ return 1;
+}
+
static const struct pmu *tp_perf_event_init(struct perf_event *event)
{
return NULL;
}
-#endif
+
+static int perf_event_set_filter(struct perf_event *event, void __user *arg)
+{
+ return -ENOENT;
+}
+
+static void perf_event_free_filter(struct perf_event *event)
+{
+}
+
+#endif /* CONFIG_EVENT_PROFILE */
atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
@@ -4394,7 +4460,7 @@ err_size:
goto out;
}
-int perf_event_set_output(struct perf_event *event, int output_fd)
+static int perf_event_set_output(struct perf_event *event, int output_fd)
{
struct perf_event *output_event = NULL;
struct file *output_file = NULL;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index b5f30d5..671bedb 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -765,7 +765,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
struct ring_buffer *buffer,
struct ring_buffer_event *event)
{
- if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) {
+ if (unlikely(call->filter_active) &&
+ !filter_match_preds(call->filter, rec)) {
ring_buffer_discard_commit(buffer, event);
return 1;
}
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index c7e1a54..99cb3f0 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/mutex.h>
+#include <linux/perf_event.h>
#include "trace.h"
#include "trace_output.h"
@@ -363,9 +364,8 @@ static void filter_build_regex(struct filter_pred *pred)
}
/* return 1 if event matches, 0 otherwise (discard) */
-int filter_match_preds(struct ftrace_event_call *call, void *rec)
+int filter_match_preds(struct event_filter *filter, void *rec)
{
- struct event_filter *filter = call->filter;
int match, top = 0, val1 = 0, val2 = 0;
int stack[MAX_FILTER_PRED];
struct filter_pred *pred;
@@ -538,9 +538,8 @@ static void filter_disable_preds(struct ftrace_event_call *call)
filter->preds[i]->fn = filter_pred_none;
}
-void destroy_preds(struct ftrace_event_call *call)
+static void __free_preds(struct event_filter *filter)
{
- struct event_filter *filter = call->filter;
int i;
if (!filter)
@@ -553,21 +552,24 @@ void destroy_preds(struct ftrace_event_call *call)
kfree(filter->preds);
kfree(filter->filter_string);
kfree(filter);
+}
+
+void destroy_preds(struct ftrace_event_call *call)
+{
+ __free_preds(call->filter);
call->filter = NULL;
+ call->filter_active = 0;
}
-static int init_preds(struct ftrace_event_call *call)
+static struct event_filter *__alloc_preds(void)
{
struct event_filter *filter;
struct filter_pred *pred;
int i;
- if (call->filter)
- return 0;
-
- filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL);
- if (!call->filter)
- return -ENOMEM;
+ filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+ if (!filter)
+ return ERR_PTR(-ENOMEM);
filter->n_preds = 0;
@@ -583,12 +585,24 @@ static int init_preds(struct ftrace_event_call *call)
filter->preds[i] = pred;
}
- return 0;
+ return filter;
oom:
- destroy_preds(call);
+ __free_preds(filter);
+ return ERR_PTR(-ENOMEM);
+}
+
+static int init_preds(struct ftrace_event_call *call)
+{
+ if (call->filter)
+ return 0;
+
+ call->filter_active = 0;
+ call->filter = __alloc_preds();
+ if (IS_ERR(call->filter))
+ return PTR_ERR(call->filter);
- return -ENOMEM;
+ return 0;
}
static int init_subsystem_preds(struct event_subsystem *system)
@@ -629,10 +643,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system)
static int filter_add_pred_fn(struct filter_parse_state *ps,
struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_pred *pred,
filter_pred_fn_t fn)
{
- struct event_filter *filter = call->filter;
int idx, err;
if (filter->n_preds == MAX_FILTER_PRED) {
@@ -647,7 +661,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
return err;
filter->n_preds++;
- call->filter_active = 1;
return 0;
}
@@ -726,6 +739,7 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size,
static int filter_add_pred(struct filter_parse_state *ps,
struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_pred *pred,
bool dry_run)
{
@@ -795,7 +809,7 @@ static int filter_add_pred(struct filter_parse_state *ps,
add_pred_fn:
if (!dry_run)
- return filter_add_pred_fn(ps, call, pred, fn);
+ return filter_add_pred_fn(ps, call, filter, pred, fn);
return 0;
}
@@ -1153,6 +1167,7 @@ static int check_preds(struct filter_parse_state *ps)
}
static int replace_preds(struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_parse_state *ps,
char *filter_string,
bool dry_run)
@@ -1199,7 +1214,7 @@ static int replace_preds(struct ftrace_event_call *call,
add_pred:
if (!pred)
return -ENOMEM;
- err = filter_add_pred(ps, call, pred, dry_run);
+ err = filter_add_pred(ps, call, filter, pred, dry_run);
filter_free_pred(pred);
if (err)
return err;
@@ -1215,6 +1230,7 @@ static int replace_system_preds(struct event_subsystem *system,
char *filter_string)
{
struct ftrace_event_call *call;
+ struct event_filter *filter;
int err;
bool fail = true;
@@ -1227,17 +1243,19 @@ static int replace_system_preds(struct event_subsystem *system,
continue;
/* try to see if the filter can be applied */
- err = replace_preds(call, ps, filter_string, true);
+ err = replace_preds(call, filter, ps, filter_string, true);
if (err)
continue;
/* really apply the filter */
filter_disable_preds(call);
- err = replace_preds(call, ps, filter_string, false);
+ err = replace_preds(call, filter, ps, filter_string, false);
if (err)
filter_disable_preds(call);
- else
- replace_filter_string(call->filter, filter_string);
+ else {
+ call->filter_active = 1;
+ replace_filter_string(filter, filter_string);
+ }
fail = false;
}
@@ -1251,7 +1269,6 @@ static int replace_system_preds(struct event_subsystem *system,
int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
{
int err;
-
struct filter_parse_state *ps;
mutex_lock(&event_mutex);
@@ -1282,10 +1299,11 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
goto out;
}
- err = replace_preds(call, ps, filter_string, false);
+ err = replace_preds(call, call->filter, ps, filter_string, false);
if (err)
append_filter_err(ps, call->filter);
-
+ else
+ call->filter_active = 1;
out:
filter_opstack_clear(ps);
postfix_clear(ps);
@@ -1300,7 +1318,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
char *filter_string)
{
int err;
-
struct filter_parse_state *ps;
mutex_lock(&event_mutex);
@@ -1344,3 +1361,67 @@ out_unlock:
return err;
}
+#ifdef CONFIG_EVENT_PROFILE
+
+void ftrace_profile_free_filter(struct perf_event *event)
+{
+ struct event_filter *filter = event->filter;
+
+ event->filter = NULL;
+ __free_preds(filter);
+}
+
+int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+ char *filter_str)
+{
+ int err;
+ struct event_filter *filter;
+ struct filter_parse_state *ps;
+ struct ftrace_event_call *call = NULL;
+
+ mutex_lock(&event_mutex);
+
+ list_for_each_entry(call, &ftrace_events, list) {
+ if (call->id == event_id)
+ break;
+ }
+ if (!call)
+ return -EINVAL;
+
+ if (event->filter)
+ return -EEXIST;
+
+ filter = __alloc_preds();
+ if (IS_ERR(filter))
+ return PTR_ERR(filter);
+
+ err = -ENOMEM;
+ ps = kzalloc(sizeof(*ps), GFP_KERNEL);
+ if (!ps)
+ goto free_preds;
+
+ parse_init(ps, filter_ops, filter_str);
+ err = filter_parse(ps);
+ if (err)
+ goto free_ps;
+
+ err = replace_preds(call, filter, ps, filter_str, false);
+ if (!err)
+ event->filter = filter;
+
+free_ps:
+ filter_opstack_clear(ps);
+ postfix_clear(ps);
+ kfree(ps);
+
+free_preds:
+ if (err)
+ __free_preds(filter);
+
+ mutex_unlock(&event_mutex);
+
+ return err;
+}
+
+#endif /* CONFIG_EVENT_PROFILE */
+
--
1.6.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/4] perf trace: Add filter Suppport
2009-10-15 3:19 [PATCH 0/4] perf trace: Add filter Suppport, V3 Li Zefan
` (2 preceding siblings ...)
2009-10-15 3:21 ` [PATCH 3/4] tracing/profile: Add filter support Li Zefan
@ 2009-10-15 3:22 ` Li Zefan
2009-10-15 9:40 ` [tip:perf/core] " tip-bot for Li Zefan
3 siblings, 1 reply; 14+ messages in thread
From: Li Zefan @ 2009-10-15 3:22 UTC (permalink / raw)
To: Ingo Molnar
Cc: Peter Zijlstra, Frederic Weisbecker, Steven Rostedt, Tom Zanussi,
LKML
Add a new option "--filter <filter_str>" to perf record, and
it should be right after "-e trace_point":
#./perf record -R -f -e irq:irq_handler_entry --filter irq==18
^C
# ./perf trace
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
See Documentation/trace/events.txt for the syntax of filter
expressions.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
tools/perf/builtin-record.c | 15 ++++++++++++++-
tools/perf/util/parse-events.c | 26 ++++++++++++++++++++++++--
tools/perf/util/parse-events.h | 2 ++
3 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4e3a374..8b2c860 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -374,9 +374,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
static void create_counter(int counter, int cpu, pid_t pid)
{
+ char *filter = filters[counter];
struct perf_event_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;
@@ -479,7 +481,6 @@ try_again:
multiplex_fd = fd[nr_cpu][counter];
if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
- int ret;
ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
assert(ret != -1);
@@ -499,6 +500,16 @@ try_again:
}
}
+ if (filter != NULL) {
+ ret = ioctl(fd[nr_cpu][counter],
+ PERF_EVENT_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_EVENT_IOC_ENABLE);
}
@@ -676,6 +687,8 @@ static const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event",
"event selector. use 'perf list' to list available events",
parse_events),
+ OPT_CALLBACK(0, "filter", NULL, "filter",
+ "event filter", parse_filter),
OPT_INTEGER('p', "pid", &target_pid,
"record events on existing pid"),
OPT_INTEGER('r', "realtime", &realtime_prio,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8cfb48c..b097570 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -8,9 +8,10 @@
#include "cache.h"
#include "header.h"
-int nr_counters;
+int nr_counters;
struct perf_event_attr attrs[MAX_COUNTERS];
+char *filters[MAX_COUNTERS];
struct event_symbol {
u8 type;
@@ -708,7 +709,6 @@ static void store_event_type(const char *orgname)
perf_header__push_event(id, orgname);
}
-
int parse_events(const struct option *opt __used, const char *str, int unset __used)
{
struct perf_event_attr attr;
@@ -745,6 +745,28 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
return 0;
}
+int parse_filter(const struct option *opt __used, const char *str,
+ int unset __used)
+{
+ int i = nr_counters - 1;
+ int len = strlen(str);
+
+ if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
+ fprintf(stderr,
+ "-F option should follow a -e tracepoint option\n");
+ return -1;
+ }
+
+ filters[i] = malloc(len + 1);
+ if (!filters[i]) {
+ fprintf(stderr, "not enough memory to hold filter string\n");
+ return -1;
+ }
+ strcpy(filters[i], str);
+
+ return 0;
+}
+
static const char * const event_type_descriptors[] = {
"",
"Hardware event",
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8626a43..b8c1f64 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern int nr_counters;
extern struct perf_event_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);
extern int parse_events(const struct option *opt, const char *str, int unset);
+extern int parse_filter(const struct option *opt, const char *str, int unset);
#define EVENTS_HELP_MAX (128*1024)
--
1.6.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [tip:perf/core] tracing/filters: Refactor subsystem filter code
2009-10-15 3:20 ` [PATCH 1/4] tracing/filters: Refactor subsystem filter code Li Zefan
@ 2009-10-15 9:39 ` tip-bot for Li Zefan
2009-10-15 10:36 ` Ingo Molnar
0 siblings, 1 reply; 14+ messages in thread
From: tip-bot for Li Zefan @ 2009-10-15 9:39 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, hpa, mingo, tzanussi, lizf, peterz, fweisbec,
rostedt, tglx, mingo
Commit-ID: fce29d15b59245597f7f320db4a9f2be0f5fb512
Gitweb: http://git.kernel.org/tip/fce29d15b59245597f7f320db4a9f2be0f5fb512
Author: Li Zefan <lizf@cn.fujitsu.com>
AuthorDate: Thu, 15 Oct 2009 11:20:34 +0800
Committer: Ingo Molnar <mingo@elte.hu>
CommitDate: Thu, 15 Oct 2009 11:35:22 +0200
tracing/filters: Refactor subsystem filter code
Change:
for_each_pred
for_each_subsystem
To:
for_each_subsystem
for_each_pred
This change also prepares for later patches.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <4AD69502.8060903@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
kernel/trace/trace.h | 1 -
kernel/trace/trace_events_filter.c | 124 +++++++++++++-----------------------
2 files changed, 45 insertions(+), 80 deletions(-)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index acef8b4..6286145 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -683,7 +683,6 @@ struct event_filter {
int n_preds;
struct filter_pred **preds;
char *filter_string;
- bool no_reset;
};
struct event_subsystem {
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 9267201..9c4f9a0 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -615,14 +615,7 @@ static int init_subsystem_preds(struct event_subsystem *system)
return 0;
}
-enum {
- FILTER_DISABLE_ALL,
- FILTER_INIT_NO_RESET,
- FILTER_SKIP_NO_RESET,
-};
-
-static void filter_free_subsystem_preds(struct event_subsystem *system,
- int flag)
+static void filter_free_subsystem_preds(struct event_subsystem *system)
{
struct ftrace_event_call *call;
@@ -633,14 +626,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
if (strcmp(call->system, system->name) != 0)
continue;
- if (flag == FILTER_INIT_NO_RESET) {
- call->filter->no_reset = false;
- continue;
- }
-
- if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset)
- continue;
-
filter_disable_preds(call);
remove_filter_string(call->filter);
}
@@ -817,44 +802,6 @@ add_pred_fn:
return 0;
}
-static int filter_add_subsystem_pred(struct filter_parse_state *ps,
- struct event_subsystem *system,
- struct filter_pred *pred,
- char *filter_string,
- bool dry_run)
-{
- struct ftrace_event_call *call;
- int err = 0;
- bool fail = true;
-
- list_for_each_entry(call, &ftrace_events, list) {
-
- if (!call->define_fields)
- continue;
-
- if (strcmp(call->system, system->name))
- continue;
-
- if (call->filter->no_reset)
- continue;
-
- err = filter_add_pred(ps, call, pred, dry_run);
- if (err)
- call->filter->no_reset = true;
- else
- fail = false;
-
- if (!dry_run)
- replace_filter_string(call->filter, filter_string);
- }
-
- if (fail) {
- parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
- return err;
- }
- return 0;
-}
-
static void parse_init(struct filter_parse_state *ps,
struct filter_op *ops,
char *infix_string)
@@ -1209,8 +1156,7 @@ static int check_preds(struct filter_parse_state *ps)
return 0;
}
-static int replace_preds(struct event_subsystem *system,
- struct ftrace_event_call *call,
+static int replace_preds(struct ftrace_event_call *call,
struct filter_parse_state *ps,
char *filter_string,
bool dry_run)
@@ -1257,11 +1203,7 @@ static int replace_preds(struct event_subsystem *system,
add_pred:
if (!pred)
return -ENOMEM;
- if (call)
- err = filter_add_pred(ps, call, pred, false);
- else
- err = filter_add_subsystem_pred(ps, system, pred,
- filter_string, dry_run);
+ err = filter_add_pred(ps, call, pred, dry_run);
filter_free_pred(pred);
if (err)
return err;
@@ -1272,6 +1214,44 @@ add_pred:
return 0;
}
+static int replace_system_preds(struct event_subsystem *system,
+ struct filter_parse_state *ps,
+ char *filter_string)
+{
+ struct ftrace_event_call *call;
+ int err;
+ bool fail = true;
+
+ list_for_each_entry(call, &ftrace_events, list) {
+
+ if (!call->define_fields)
+ continue;
+
+ if (strcmp(call->system, system->name) != 0)
+ continue;
+
+ /* try to see if the filter can be applied */
+ err = replace_preds(call, ps, filter_string, true);
+ if (err)
+ continue;
+
+ /* really apply the filter */
+ filter_disable_preds(call);
+ err = replace_preds(call, ps, filter_string, false);
+ if (err)
+ filter_disable_preds(call);
+ else
+ replace_filter_string(call->filter, filter_string);
+ fail = false;
+ }
+
+ if (fail) {
+ parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
+ return err;
+ }
+ return 0;
+}
+
int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
{
int err;
@@ -1306,7 +1286,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
goto out;
}
- err = replace_preds(NULL, call, ps, filter_string, false);
+ err = replace_preds(call, ps, filter_string, false);
if (err)
append_filter_err(ps, call->filter);
@@ -1334,7 +1314,7 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
goto out_unlock;
if (!strcmp(strstrip(filter_string), "0")) {
- filter_free_subsystem_preds(system, FILTER_DISABLE_ALL);
+ filter_free_subsystem_preds(system);
remove_filter_string(system->filter);
mutex_unlock(&event_mutex);
return 0;
@@ -1354,23 +1334,9 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
goto out;
}
- filter_free_subsystem_preds(system, FILTER_INIT_NO_RESET);
-
- /* try to see the filter can be applied to which events */
- err = replace_preds(system, NULL, ps, filter_string, true);
- if (err) {
- append_filter_err(ps, system->filter);
- goto out;
- }
-
- filter_free_subsystem_preds(system, FILTER_SKIP_NO_RESET);
-
- /* really apply the filter to the events */
- err = replace_preds(system, NULL, ps, filter_string, false);
- if (err) {
+ err = replace_system_preds(system, ps, filter_string);
+ if (err)
append_filter_err(ps, system->filter);
- filter_free_subsystem_preds(system, 2);
- }
out:
filter_opstack_clear(ps);
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [tip:perf/core] tracing/filters: Use a different op for glob match
2009-10-15 3:21 ` [PATCH 2/4] tracing/filters: Use a different op for glob match Li Zefan
@ 2009-10-15 9:40 ` tip-bot for Li Zefan
2009-10-15 12:52 ` [PATCH 2/4] " Frederic Weisbecker
1 sibling, 0 replies; 14+ messages in thread
From: tip-bot for Li Zefan @ 2009-10-15 9:40 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, hpa, mingo, tzanussi, lizf, peterz, fweisbec,
rostedt, tglx, mingo
Commit-ID: b0f1a59a98d7ac2102e7e4f22904c26d564a5628
Gitweb: http://git.kernel.org/tip/b0f1a59a98d7ac2102e7e4f22904c26d564a5628
Author: Li Zefan <lizf@cn.fujitsu.com>
AuthorDate: Thu, 15 Oct 2009 11:21:12 +0800
Committer: Ingo Molnar <mingo@elte.hu>
CommitDate: Thu, 15 Oct 2009 11:35:22 +0200
tracing/filters: Use a different op for glob match
"==" will always do a full match, and "~" will do a glob match.
In the future, we may add "=~" for regex match.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <4AD69528.3050309@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
kernel/trace/trace.h | 2 +-
kernel/trace/trace_events_filter.c | 59 +++++++++++++++++-------------------
2 files changed, 29 insertions(+), 32 deletions(-)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 6286145..ffe53dd 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -702,7 +702,7 @@ typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
typedef int (*regex_match_func)(char *str, struct regex *r, int len);
enum regex_type {
- MATCH_FULL,
+ MATCH_FULL = 0,
MATCH_FRONT_ONLY,
MATCH_MIDDLE_ONLY,
MATCH_END_ONLY,
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 9c4f9a0..273845f 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -29,6 +29,7 @@ enum filter_op_ids
{
OP_OR,
OP_AND,
+ OP_GLOB,
OP_NE,
OP_EQ,
OP_LT,
@@ -46,16 +47,17 @@ struct filter_op {
};
static struct filter_op filter_ops[] = {
- { OP_OR, "||", 1 },
- { OP_AND, "&&", 2 },
- { OP_NE, "!=", 4 },
- { OP_EQ, "==", 4 },
- { OP_LT, "<", 5 },
- { OP_LE, "<=", 5 },
- { OP_GT, ">", 5 },
- { OP_GE, ">=", 5 },
- { OP_NONE, "OP_NONE", 0 },
- { OP_OPEN_PAREN, "(", 0 },
+ { OP_OR, "||", 1 },
+ { OP_AND, "&&", 2 },
+ { OP_GLOB, "~", 4 },
+ { OP_NE, "!=", 4 },
+ { OP_EQ, "==", 4 },
+ { OP_LT, "<", 5 },
+ { OP_LE, "<=", 5 },
+ { OP_GT, ">", 5 },
+ { OP_GE, ">=", 5 },
+ { OP_NONE, "OP_NONE", 0 },
+ { OP_OPEN_PAREN, "(", 0 },
};
enum {
@@ -329,22 +331,18 @@ enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not)
return type;
}
-static int filter_build_regex(struct filter_pred *pred)
+static void filter_build_regex(struct filter_pred *pred)
{
struct regex *r = &pred->regex;
- char *search, *dup;
- enum regex_type type;
- int not;
-
- type = filter_parse_regex(r->pattern, r->len, &search, ¬);
- dup = kstrdup(search, GFP_KERNEL);
- if (!dup)
- return -ENOMEM;
-
- strcpy(r->pattern, dup);
- kfree(dup);
-
- r->len = strlen(r->pattern);
+ char *search;
+ enum regex_type type = MATCH_FULL;
+ int not = 0;
+
+ if (pred->op == OP_GLOB) {
+ type = filter_parse_regex(r->pattern, r->len, &search, ¬);
+ r->len = strlen(search);
+ memmove(r->pattern, search, r->len+1);
+ }
switch (type) {
case MATCH_FULL:
@@ -362,8 +360,6 @@ static int filter_build_regex(struct filter_pred *pred)
}
pred->not ^= not;
-
- return 0;
}
/* return 1 if event matches, 0 otherwise (discard) */
@@ -676,7 +672,10 @@ static bool is_string_field(struct ftrace_event_field *field)
static int is_legal_op(struct ftrace_event_field *field, int op)
{
- if (is_string_field(field) && (op != OP_EQ && op != OP_NE))
+ if (is_string_field(field) &&
+ (op != OP_EQ && op != OP_NE && op != OP_GLOB))
+ return 0;
+ if (!is_string_field(field) && op == OP_GLOB)
return 0;
return 1;
@@ -761,15 +760,13 @@ static int filter_add_pred(struct filter_parse_state *ps,
}
if (is_string_field(field)) {
- ret = filter_build_regex(pred);
- if (ret)
- return ret;
+ filter_build_regex(pred);
if (field->filter_type == FILTER_STATIC_STRING) {
fn = filter_pred_string;
pred->regex.field_len = field->size;
} else if (field->filter_type == FILTER_DYN_STRING)
- fn = filter_pred_strloc;
+ fn = filter_pred_strloc;
else {
fn = filter_pred_pchar;
pred->regex.field_len = strlen(pred->regex.pattern);
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [tip:perf/core] tracing/profile: Add filter support
2009-10-15 3:21 ` [PATCH 3/4] tracing/profile: Add filter support Li Zefan
@ 2009-10-15 9:40 ` tip-bot for Li Zefan
2009-10-15 9:47 ` [PATCH 3/4] " Américo Wang
1 sibling, 0 replies; 14+ messages in thread
From: tip-bot for Li Zefan @ 2009-10-15 9:40 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, hpa, mingo, tzanussi, lizf, peterz, fweisbec,
rostedt, tglx, mingo
Commit-ID: 6fb2915df7f0747d9044da9dbff5b46dc2e20830
Gitweb: http://git.kernel.org/tip/6fb2915df7f0747d9044da9dbff5b46dc2e20830
Author: Li Zefan <lizf@cn.fujitsu.com>
AuthorDate: Thu, 15 Oct 2009 11:21:42 +0800
Committer: Ingo Molnar <mingo@elte.hu>
CommitDate: Thu, 15 Oct 2009 11:35:23 +0200
tracing/profile: Add filter support
- Add an ioctl to allocate a filter for a perf event.
- Free the filter when the associated perf event is to be freed.
- Do the filtering in perf_swevent_match().
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <4AD69546.8050401@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
include/linux/ftrace_event.h | 11 +++-
include/linux/perf_counter.h | 1 +
include/linux/perf_event.h | 6 ++
kernel/perf_event.c | 80 ++++++++++++++++++++--
kernel/trace/trace.h | 3 +-
kernel/trace/trace_events_filter.c | 133 +++++++++++++++++++++++++++++-------
6 files changed, 199 insertions(+), 35 deletions(-)
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 4ec5e67..d117704 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -144,7 +144,7 @@ extern char *trace_profile_buf_nmi;
#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */
extern void destroy_preds(struct ftrace_event_call *call);
-extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
+extern int filter_match_preds(struct event_filter *filter, void *rec);
extern int filter_current_check_discard(struct ring_buffer *buffer,
struct ftrace_event_call *call,
void *rec,
@@ -186,4 +186,13 @@ do { \
__trace_printk(ip, fmt, ##args); \
} while (0)
+#ifdef CONFIG_EVENT_PROFILE
+struct perf_event;
+extern int ftrace_profile_enable(int event_id);
+extern void ftrace_profile_disable(int event_id);
+extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+ char *filter_str);
+extern void ftrace_profile_free_filter(struct perf_event *event);
+#endif
+
#endif /* _LINUX_FTRACE_EVENT_H */
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 7b7fbf4..91a2b43 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -225,6 +225,7 @@ struct perf_counter_attr {
#define PERF_COUNTER_IOC_RESET _IO ('$', 3)
#define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_COUNTER_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_counter_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 2e6d95f..df9d964 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -221,6 +221,7 @@ struct perf_event_attr {
#define PERF_EVENT_IOC_RESET _IO ('$', 3)
#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
@@ -633,7 +634,12 @@ struct perf_event {
struct pid_namespace *ns;
u64 id;
+
+#ifdef CONFIG_EVENT_PROFILE
+ struct event_filter *filter;
#endif
+
+#endif /* CONFIG_PERF_EVENTS */
};
/**
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 9d0b5c6..12b5ec3 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -28,6 +28,7 @@
#include <linux/anon_inodes.h>
#include <linux/kernel_stat.h>
#include <linux/perf_event.h>
+#include <linux/ftrace_event.h>
#include <asm/irq_regs.h>
@@ -1658,6 +1659,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
return ERR_PTR(err);
}
+static void perf_event_free_filter(struct perf_event *event);
+
static void free_event_rcu(struct rcu_head *head)
{
struct perf_event *event;
@@ -1665,6 +1668,7 @@ static void free_event_rcu(struct rcu_head *head)
event = container_of(head, struct perf_event, rcu_head);
if (event->ns)
put_pid_ns(event->ns);
+ perf_event_free_filter(event);
kfree(event);
}
@@ -1974,7 +1978,8 @@ unlock:
return ret;
}
-int perf_event_set_output(struct perf_event *event, int output_fd);
+static int perf_event_set_output(struct perf_event *event, int output_fd);
+static int perf_event_set_filter(struct perf_event *event, void __user *arg);
static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -2002,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PERF_EVENT_IOC_SET_OUTPUT:
return perf_event_set_output(event, arg);
+ case PERF_EVENT_IOC_SET_FILTER:
+ return perf_event_set_filter(event, (void __user *)arg);
+
default:
return -ENOTTY;
}
@@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event)
return 1;
}
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data);
+
static int perf_swevent_match(struct perf_event *event,
enum perf_type_id type,
- u32 event_id, struct pt_regs *regs)
+ u32 event_id,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
{
if (!perf_swevent_is_counting(event))
return 0;
@@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event,
return 0;
}
+ if (event->attr.type == PERF_TYPE_TRACEPOINT &&
+ !perf_tp_event_match(event, data))
+ return 0;
+
return 1;
}
@@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx,
rcu_read_lock();
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
- if (perf_swevent_match(event, type, event_id, regs))
+ if (perf_swevent_match(event, type, event_id, data, regs))
perf_swevent_add(event, nr, nmi, data, regs);
}
rcu_read_unlock();
@@ -4086,6 +4103,7 @@ static const struct pmu perf_ops_task_clock = {
};
#ifdef CONFIG_EVENT_PROFILE
+
void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size)
{
@@ -4109,8 +4127,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
}
EXPORT_SYMBOL_GPL(perf_tp_event);
-extern int ftrace_profile_enable(int);
-extern void ftrace_profile_disable(int);
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data)
+{
+ void *record = data->raw->data;
+
+ if (likely(!event->filter) || filter_match_preds(event->filter, record))
+ return 1;
+ return 0;
+}
static void tp_perf_event_destroy(struct perf_event *event)
{
@@ -4135,12 +4160,53 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
return &perf_ops_generic;
}
+
+static int perf_event_set_filter(struct perf_event *event, void __user *arg)
+{
+ char *filter_str;
+ int ret;
+
+ if (event->attr.type != PERF_TYPE_TRACEPOINT)
+ return -EINVAL;
+
+ filter_str = strndup_user(arg, PAGE_SIZE);
+ if (IS_ERR(filter_str))
+ return PTR_ERR(filter_str);
+
+ ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);
+
+ kfree(filter_str);
+ return ret;
+}
+
+static void perf_event_free_filter(struct perf_event *event)
+{
+ ftrace_profile_free_filter(event);
+}
+
#else
+
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data)
+{
+ return 1;
+}
+
static const struct pmu *tp_perf_event_init(struct perf_event *event)
{
return NULL;
}
-#endif
+
+static int perf_event_set_filter(struct perf_event *event, void __user *arg)
+{
+ return -ENOENT;
+}
+
+static void perf_event_free_filter(struct perf_event *event)
+{
+}
+
+#endif /* CONFIG_EVENT_PROFILE */
atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
@@ -4394,7 +4460,7 @@ err_size:
goto out;
}
-int perf_event_set_output(struct perf_event *event, int output_fd)
+static int perf_event_set_output(struct perf_event *event, int output_fd)
{
struct perf_event *output_event = NULL;
struct file *output_file = NULL;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index ffe53dd..4959ada 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -743,7 +743,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
struct ring_buffer *buffer,
struct ring_buffer_event *event)
{
- if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) {
+ if (unlikely(call->filter_active) &&
+ !filter_match_preds(call->filter, rec)) {
ring_buffer_discard_commit(buffer, event);
return 1;
}
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 273845f..e27bb6a 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/mutex.h>
+#include <linux/perf_event.h>
#include "trace.h"
#include "trace_output.h"
@@ -363,9 +364,8 @@ static void filter_build_regex(struct filter_pred *pred)
}
/* return 1 if event matches, 0 otherwise (discard) */
-int filter_match_preds(struct ftrace_event_call *call, void *rec)
+int filter_match_preds(struct event_filter *filter, void *rec)
{
- struct event_filter *filter = call->filter;
int match, top = 0, val1 = 0, val2 = 0;
int stack[MAX_FILTER_PRED];
struct filter_pred *pred;
@@ -538,9 +538,8 @@ static void filter_disable_preds(struct ftrace_event_call *call)
filter->preds[i]->fn = filter_pred_none;
}
-void destroy_preds(struct ftrace_event_call *call)
+static void __free_preds(struct event_filter *filter)
{
- struct event_filter *filter = call->filter;
int i;
if (!filter)
@@ -553,21 +552,24 @@ void destroy_preds(struct ftrace_event_call *call)
kfree(filter->preds);
kfree(filter->filter_string);
kfree(filter);
+}
+
+void destroy_preds(struct ftrace_event_call *call)
+{
+ __free_preds(call->filter);
call->filter = NULL;
+ call->filter_active = 0;
}
-static int init_preds(struct ftrace_event_call *call)
+static struct event_filter *__alloc_preds(void)
{
struct event_filter *filter;
struct filter_pred *pred;
int i;
- if (call->filter)
- return 0;
-
- filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL);
- if (!call->filter)
- return -ENOMEM;
+ filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+ if (!filter)
+ return ERR_PTR(-ENOMEM);
filter->n_preds = 0;
@@ -583,12 +585,24 @@ static int init_preds(struct ftrace_event_call *call)
filter->preds[i] = pred;
}
- return 0;
+ return filter;
oom:
- destroy_preds(call);
+ __free_preds(filter);
+ return ERR_PTR(-ENOMEM);
+}
+
+static int init_preds(struct ftrace_event_call *call)
+{
+ if (call->filter)
+ return 0;
+
+ call->filter_active = 0;
+ call->filter = __alloc_preds();
+ if (IS_ERR(call->filter))
+ return PTR_ERR(call->filter);
- return -ENOMEM;
+ return 0;
}
static int init_subsystem_preds(struct event_subsystem *system)
@@ -629,10 +643,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system)
static int filter_add_pred_fn(struct filter_parse_state *ps,
struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_pred *pred,
filter_pred_fn_t fn)
{
- struct event_filter *filter = call->filter;
int idx, err;
if (filter->n_preds == MAX_FILTER_PRED) {
@@ -647,7 +661,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
return err;
filter->n_preds++;
- call->filter_active = 1;
return 0;
}
@@ -726,6 +739,7 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size,
static int filter_add_pred(struct filter_parse_state *ps,
struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_pred *pred,
bool dry_run)
{
@@ -795,7 +809,7 @@ static int filter_add_pred(struct filter_parse_state *ps,
add_pred_fn:
if (!dry_run)
- return filter_add_pred_fn(ps, call, pred, fn);
+ return filter_add_pred_fn(ps, call, filter, pred, fn);
return 0;
}
@@ -1154,6 +1168,7 @@ static int check_preds(struct filter_parse_state *ps)
}
static int replace_preds(struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_parse_state *ps,
char *filter_string,
bool dry_run)
@@ -1200,7 +1215,7 @@ static int replace_preds(struct ftrace_event_call *call,
add_pred:
if (!pred)
return -ENOMEM;
- err = filter_add_pred(ps, call, pred, dry_run);
+ err = filter_add_pred(ps, call, filter, pred, dry_run);
filter_free_pred(pred);
if (err)
return err;
@@ -1216,6 +1231,7 @@ static int replace_system_preds(struct event_subsystem *system,
char *filter_string)
{
struct ftrace_event_call *call;
+ struct event_filter *filter;
int err;
bool fail = true;
@@ -1228,17 +1244,19 @@ static int replace_system_preds(struct event_subsystem *system,
continue;
/* try to see if the filter can be applied */
- err = replace_preds(call, ps, filter_string, true);
+ err = replace_preds(call, filter, ps, filter_string, true);
if (err)
continue;
/* really apply the filter */
filter_disable_preds(call);
- err = replace_preds(call, ps, filter_string, false);
+ err = replace_preds(call, filter, ps, filter_string, false);
if (err)
filter_disable_preds(call);
- else
- replace_filter_string(call->filter, filter_string);
+ else {
+ call->filter_active = 1;
+ replace_filter_string(filter, filter_string);
+ }
fail = false;
}
@@ -1252,7 +1270,6 @@ static int replace_system_preds(struct event_subsystem *system,
int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
{
int err;
-
struct filter_parse_state *ps;
mutex_lock(&event_mutex);
@@ -1283,10 +1300,11 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
goto out;
}
- err = replace_preds(call, ps, filter_string, false);
+ err = replace_preds(call, call->filter, ps, filter_string, false);
if (err)
append_filter_err(ps, call->filter);
-
+ else
+ call->filter_active = 1;
out:
filter_opstack_clear(ps);
postfix_clear(ps);
@@ -1301,7 +1319,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
char *filter_string)
{
int err;
-
struct filter_parse_state *ps;
mutex_lock(&event_mutex);
@@ -1345,3 +1362,67 @@ out_unlock:
return err;
}
+#ifdef CONFIG_EVENT_PROFILE
+
+void ftrace_profile_free_filter(struct perf_event *event)
+{
+ struct event_filter *filter = event->filter;
+
+ event->filter = NULL;
+ __free_preds(filter);
+}
+
+int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+ char *filter_str)
+{
+ int err;
+ struct event_filter *filter;
+ struct filter_parse_state *ps;
+ struct ftrace_event_call *call = NULL;
+
+ mutex_lock(&event_mutex);
+
+ list_for_each_entry(call, &ftrace_events, list) {
+ if (call->id == event_id)
+ break;
+ }
+ if (!call)
+ return -EINVAL;
+
+ if (event->filter)
+ return -EEXIST;
+
+ filter = __alloc_preds();
+ if (IS_ERR(filter))
+ return PTR_ERR(filter);
+
+ err = -ENOMEM;
+ ps = kzalloc(sizeof(*ps), GFP_KERNEL);
+ if (!ps)
+ goto free_preds;
+
+ parse_init(ps, filter_ops, filter_str);
+ err = filter_parse(ps);
+ if (err)
+ goto free_ps;
+
+ err = replace_preds(call, filter, ps, filter_str, false);
+ if (!err)
+ event->filter = filter;
+
+free_ps:
+ filter_opstack_clear(ps);
+ postfix_clear(ps);
+ kfree(ps);
+
+free_preds:
+ if (err)
+ __free_preds(filter);
+
+ mutex_unlock(&event_mutex);
+
+ return err;
+}
+
+#endif /* CONFIG_EVENT_PROFILE */
+
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [tip:perf/core] perf trace: Add filter Suppport
2009-10-15 3:22 ` [PATCH 4/4] perf trace: Add filter Suppport Li Zefan
@ 2009-10-15 9:40 ` tip-bot for Li Zefan
0 siblings, 0 replies; 14+ messages in thread
From: tip-bot for Li Zefan @ 2009-10-15 9:40 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, hpa, mingo, tzanussi, lizf, peterz, fweisbec,
rostedt, tglx, mingo
Commit-ID: c171b552a7d316c7e1c3ad6f70a30178dd53e14c
Gitweb: http://git.kernel.org/tip/c171b552a7d316c7e1c3ad6f70a30178dd53e14c
Author: Li Zefan <lizf@cn.fujitsu.com>
AuthorDate: Thu, 15 Oct 2009 11:22:07 +0800
Committer: Ingo Molnar <mingo@elte.hu>
CommitDate: Thu, 15 Oct 2009 11:35:23 +0200
perf trace: Add filter Suppport
Add a new option "--filter <filter_str>" to perf record, and
it should be right after "-e trace_point":
#./perf record -R -f -e irq:irq_handler_entry --filter irq==18
^C
# ./perf trace
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
See Documentation/trace/events.txt for the syntax of filter
expressions.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <4AD6955F.90602@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
tools/perf/builtin-record.c | 15 ++++++++++++++-
tools/perf/util/parse-events.c | 26 ++++++++++++++++++++++++--
tools/perf/util/parse-events.h | 2 ++
3 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4e3a374..8b2c860 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -374,9 +374,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
static void create_counter(int counter, int cpu, pid_t pid)
{
+ char *filter = filters[counter];
struct perf_event_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;
@@ -479,7 +481,6 @@ try_again:
multiplex_fd = fd[nr_cpu][counter];
if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
- int ret;
ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
assert(ret != -1);
@@ -499,6 +500,16 @@ try_again:
}
}
+ if (filter != NULL) {
+ ret = ioctl(fd[nr_cpu][counter],
+ PERF_EVENT_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_EVENT_IOC_ENABLE);
}
@@ -676,6 +687,8 @@ static const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event",
"event selector. use 'perf list' to list available events",
parse_events),
+ OPT_CALLBACK(0, "filter", NULL, "filter",
+ "event filter", parse_filter),
OPT_INTEGER('p', "pid", &target_pid,
"record events on existing pid"),
OPT_INTEGER('r', "realtime", &realtime_prio,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8cfb48c..b097570 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -8,9 +8,10 @@
#include "cache.h"
#include "header.h"
-int nr_counters;
+int nr_counters;
struct perf_event_attr attrs[MAX_COUNTERS];
+char *filters[MAX_COUNTERS];
struct event_symbol {
u8 type;
@@ -708,7 +709,6 @@ static void store_event_type(const char *orgname)
perf_header__push_event(id, orgname);
}
-
int parse_events(const struct option *opt __used, const char *str, int unset __used)
{
struct perf_event_attr attr;
@@ -745,6 +745,28 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
return 0;
}
+int parse_filter(const struct option *opt __used, const char *str,
+ int unset __used)
+{
+ int i = nr_counters - 1;
+ int len = strlen(str);
+
+ if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
+ fprintf(stderr,
+ "-F option should follow a -e tracepoint option\n");
+ return -1;
+ }
+
+ filters[i] = malloc(len + 1);
+ if (!filters[i]) {
+ fprintf(stderr, "not enough memory to hold filter string\n");
+ return -1;
+ }
+ strcpy(filters[i], str);
+
+ return 0;
+}
+
static const char * const event_type_descriptors[] = {
"",
"Hardware event",
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8626a43..b8c1f64 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern int nr_counters;
extern struct perf_event_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);
extern int parse_events(const struct option *opt, const char *str, int unset);
+extern int parse_filter(const struct option *opt, const char *str, int unset);
#define EVENTS_HELP_MAX (128*1024)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] tracing/profile: Add filter support
2009-10-15 3:21 ` [PATCH 3/4] tracing/profile: Add filter support Li Zefan
2009-10-15 9:40 ` [tip:perf/core] " tip-bot for Li Zefan
@ 2009-10-15 9:47 ` Américo Wang
1 sibling, 0 replies; 14+ messages in thread
From: Américo Wang @ 2009-10-15 9:47 UTC (permalink / raw)
To: Li Zefan
Cc: Ingo Molnar, Peter Zijlstra, Frederic Weisbecker, Steven Rostedt,
Tom Zanussi, LKML
On Thu, Oct 15, 2009 at 11:21 AM, Li Zefan <lizf@cn.fujitsu.com> wrote:
> - Add an ioctl to allocate a filter for a perf event.
>
> - Free the filter when the associated perf event is to be freed.
>
> - Do the filtering in perf_swevent_match().
>
> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
{snip}
> +int ftrace_profile_set_filter(struct perf_event *event, int event_id,
> + char *filter_str)
> +{
> + int err;
> + struct event_filter *filter;
> + struct filter_parse_state *ps;
> + struct ftrace_event_call *call = NULL;
> +
> + mutex_lock(&event_mutex);
> +
> + list_for_each_entry(call, &ftrace_events, list) {
> + if (call->id == event_id)
> + break;
> + }
> + if (!call)
> + return -EINVAL;
> +
> + if (event->filter)
> + return -EEXIST;
> +
> + filter = __alloc_preds();
> + if (IS_ERR(filter))
> + return PTR_ERR(filter);
Just return will leave &event_mutex locked...
Am I missing something here?
> +
> + err = -ENOMEM;
> + ps = kzalloc(sizeof(*ps), GFP_KERNEL);
> + if (!ps)
> + goto free_preds;
> +
> + parse_init(ps, filter_ops, filter_str);
> + err = filter_parse(ps);
> + if (err)
> + goto free_ps;
> +
> + err = replace_preds(call, filter, ps, filter_str, false);
> + if (!err)
> + event->filter = filter;
> +
> +free_ps:
> + filter_opstack_clear(ps);
> + postfix_clear(ps);
> + kfree(ps);
> +
> +free_preds:
> + if (err)
> + __free_preds(filter);
> +
> + mutex_unlock(&event_mutex);
> +
> + return err;
> +}
> +
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [tip:perf/core] tracing/filters: Refactor subsystem filter code
2009-10-15 9:39 ` [tip:perf/core] " tip-bot for Li Zefan
@ 2009-10-15 10:36 ` Ingo Molnar
2009-10-28 9:06 ` Li Zefan
0 siblings, 1 reply; 14+ messages in thread
From: Ingo Molnar @ 2009-10-15 10:36 UTC (permalink / raw)
To: tip-bot for Li Zefan
Cc: linux-tip-commits, linux-kernel, hpa, mingo, tzanussi, peterz,
fweisbec, rostedt, tglx
* tip-bot for Li Zefan <lizf@cn.fujitsu.com> wrote:
> Commit-ID: fce29d15b59245597f7f320db4a9f2be0f5fb512
> Gitweb: http://git.kernel.org/tip/fce29d15b59245597f7f320db4a9f2be0f5fb512
> Author: Li Zefan <lizf@cn.fujitsu.com>
> AuthorDate: Thu, 15 Oct 2009 11:20:34 +0800
> Committer: Ingo Molnar <mingo@elte.hu>
> CommitDate: Thu, 15 Oct 2009 11:35:22 +0200
the filter variable was not initialized here - i have applied the fix
below.
Ingo
Index: linux/kernel/trace/trace_events_filter.c
===================================================================
--- linux.orig/kernel/trace/trace_events_filter.c
+++ linux/kernel/trace/trace_events_filter.c
@@ -1230,8 +1230,8 @@ static int replace_system_preds(struct e
struct filter_parse_state *ps,
char *filter_string)
{
+ struct event_filter *filter = system->filter;
struct ftrace_event_call *call;
- struct event_filter *filter;
int err;
bool fail = true;
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2/4] tracing/filters: Use a different op for glob match
2009-10-15 3:21 ` [PATCH 2/4] tracing/filters: Use a different op for glob match Li Zefan
2009-10-15 9:40 ` [tip:perf/core] " tip-bot for Li Zefan
@ 2009-10-15 12:52 ` Frederic Weisbecker
1 sibling, 0 replies; 14+ messages in thread
From: Frederic Weisbecker @ 2009-10-15 12:52 UTC (permalink / raw)
To: Li Zefan; +Cc: Ingo Molnar, Peter Zijlstra, Steven Rostedt, Tom Zanussi, LKML
On Thu, Oct 15, 2009 at 11:21:12AM +0800, Li Zefan wrote:
> "==" will always do a full match, and "~" will do a glob match.
>
> In the future, we may add "=~" for regex match.
>
> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Thanks a lot for doing this. I can then remove it from my
TODO list :)
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [tip:perf/core] tracing/filters: Refactor subsystem filter code
2009-10-15 10:36 ` Ingo Molnar
@ 2009-10-28 9:06 ` Li Zefan
0 siblings, 0 replies; 14+ messages in thread
From: Li Zefan @ 2009-10-28 9:06 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-tip-commits, linux-kernel, hpa, mingo, tzanussi, peterz,
fweisbec, rostedt, tglx
Ingo Molnar wrote:
> * tip-bot for Li Zefan <lizf@cn.fujitsu.com> wrote:
>
>> Commit-ID: fce29d15b59245597f7f320db4a9f2be0f5fb512
>> Gitweb: http://git.kernel.org/tip/fce29d15b59245597f7f320db4a9f2be0f5fb512
>> Author: Li Zefan <lizf@cn.fujitsu.com>
>> AuthorDate: Thu, 15 Oct 2009 11:20:34 +0800
>> Committer: Ingo Molnar <mingo@elte.hu>
>> CommitDate: Thu, 15 Oct 2009 11:35:22 +0200
>
> the filter variable was not initialized here - i have applied the fix
> below.
>
I sent out the patchset and then went for a travel, and came back
to found this fixup is wrong..
I'll send out the correct fix soon.
> Ingo
>
> Index: linux/kernel/trace/trace_events_filter.c
> ===================================================================
> --- linux.orig/kernel/trace/trace_events_filter.c
> +++ linux/kernel/trace/trace_events_filter.c
> @@ -1230,8 +1230,8 @@ static int replace_system_preds(struct e
> struct filter_parse_state *ps,
> char *filter_string)
> {
> + struct event_filter *filter = system->filter;
> struct ftrace_event_call *call;
> - struct event_filter *filter;
> int err;
> bool fail = true;
>
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2009-10-28 9:07 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-15 3:19 [PATCH 0/4] perf trace: Add filter Suppport, V3 Li Zefan
2009-10-15 3:20 ` [PATCH 1/4] tracing/filters: Refactor subsystem filter code Li Zefan
2009-10-15 9:39 ` [tip:perf/core] " tip-bot for Li Zefan
2009-10-15 10:36 ` Ingo Molnar
2009-10-28 9:06 ` Li Zefan
2009-10-15 3:21 ` [PATCH 2/4] tracing/filters: Use a different op for glob match Li Zefan
2009-10-15 9:40 ` [tip:perf/core] " tip-bot for Li Zefan
2009-10-15 12:52 ` [PATCH 2/4] " Frederic Weisbecker
2009-10-15 3:21 ` [PATCH 3/4] tracing/profile: Add filter support Li Zefan
2009-10-15 9:40 ` [tip:perf/core] " tip-bot for Li Zefan
2009-10-15 9:47 ` [PATCH 3/4] " Américo Wang
2009-10-15 3:22 ` [PATCH 4/4] perf trace: Add filter Suppport Li Zefan
2009-10-15 9:40 ` [tip:perf/core] " tip-bot for Li Zefan
-- strict thread matches above, loose matches on Subject: below --
2009-10-13 2:17 [PATCH 0/4] perf trace: Add filter Suppport, V2 Li Zefan
2009-10-13 2:18 ` [PATCH 2/4] tracing/filters: Use a different op for glob match Li Zefan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).