* [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* [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* 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: [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
* [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* [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* 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
* [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* [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* 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
* [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] 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