From: Li Zefan <lizf@cn.fujitsu.com>
To: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>,
Steven Rostedt <rostedt@goodmis.org>,
Frederic Weisbecker <fweisbec@gmail.com>,
Tom Zanussi <tzanussi@gmail.com>, Jason Baron <jbaron@redhat.com>,
LKML <linux-kernel@vger.kernel.org>
Subject: [PATCH 2/6] tracing/profile: Add filter support
Date: Mon, 07 Sep 2009 16:12:53 +0800 [thread overview]
Message-ID: <4AA4C085.5050006@cn.fujitsu.com> (raw)
In-Reply-To: <4AA4C04D.1050201@cn.fujitsu.com>
- add ftrace_profile_set_filter(), to set filter for a profile event
- filter is enabled when profile probe is registered
- filter is disabled when profile probe is unregistered
- in ftrace_profile_##call(), record events only when
filter_match_preds() returns 1
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
include/linux/ftrace_event.h | 19 +++++-
include/trace/ftrace.h | 10 ++-
kernel/trace/trace.h | 8 ++-
kernel/trace/trace_event_profile.c | 18 +++++
kernel/trace/trace_events_filter.c | 135 ++++++++++++++++++++++++++++--------
5 files changed, 156 insertions(+), 34 deletions(-)
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 23f7179..44a7183 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -129,6 +129,10 @@ struct ftrace_event_call {
void *mod;
void *data;
+#ifdef CONFIG_EVENT_PROFILE
+ int profile_filter_active;
+ struct event_filter *profile_filter;
+#endif
atomic_t profile_count;
int (*profile_enable)(struct ftrace_event_call *);
void (*profile_disable)(struct ftrace_event_call *);
@@ -138,12 +142,25 @@ struct ftrace_event_call {
#define MAX_FILTER_STR_VAL 128
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,
struct ring_buffer_event *event);
+#ifdef CONFIG_EVENT_PROFILE
+extern void destroy_profile_preds(struct ftrace_event_call *call);
+
+static inline int
+profile_filter_check(struct ftrace_event_call *call, void *rec)
+{
+ if (likely(!call->profile_filter_active) ||
+ filter_match_preds(call->profile_filter, rec))
+ return 1;
+ return 0;
+}
+#endif
+
enum {
FILTER_OTHER = 0,
FILTER_STATIC_STRING,
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 308bafd..da95201 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -417,8 +417,11 @@ static int ftrace_profile_enable_##call(struct ftrace_event_call *event_call) \
\
static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
{ \
- if (atomic_add_negative(-1, &event_call->profile_count)) \
+ if (atomic_add_negative(-1, &event_call->profile_count)) { \
unregister_trace_##call(ftrace_profile_##call); \
+ tracepoint_synchronize_unregister(); \
+ destroy_profile_preds(event_call); \
+ } \
}
#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
@@ -742,8 +745,9 @@ static void ftrace_profile_##call(proto) \
\
{ assign; } \
\
- perf_tpcounter_event(event_call->id, __addr, __count, entry,\
- __entry_size); \
+ if (profile_filter_check(event_call, entry)) \
+ perf_tpcounter_event(event_call->id, __addr, __count, \
+ entry, __entry_size); \
} while (0); \
\
}
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 2b47eba..751f996 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -817,6 +817,11 @@ struct filter_pred {
int pop_n;
};
+#ifdef CONFIG_EVENT_PROFILE
+extern int apply_profile_filter(struct ftrace_event_call *call,
+ char *filter_string);
+#endif
+
extern void print_event_filter(struct ftrace_event_call *call,
struct trace_seq *s);
extern int apply_event_filter(struct ftrace_event_call *call,
@@ -832,7 +837,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_event_profile.c b/kernel/trace/trace_event_profile.c
index 11ba5bb..ec6d4b0 100644
--- a/kernel/trace/trace_event_profile.c
+++ b/kernel/trace/trace_event_profile.c
@@ -37,3 +37,21 @@ void ftrace_profile_disable(int event_id)
}
mutex_unlock(&event_mutex);
}
+
+int ftrace_profile_set_filter(int event_id, char *filter)
+{
+ struct ftrace_event_call *event;
+ int ret = -EINVAL;
+
+ mutex_lock(&event_mutex);
+ list_for_each_entry(event, &ftrace_events, list) {
+ if (event->id == event_id) {
+ ret = apply_profile_filter(event, filter);
+ break;
+ }
+ }
+ mutex_unlock(&event_mutex);
+
+ return ret;
+}
+
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index f9afbdf..1ab36b7 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -210,9 +210,8 @@ static int filter_pred_none(struct filter_pred *pred, void *event,
}
/* 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;
@@ -385,14 +384,10 @@ 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)
- return;
-
for (i = 0; i < MAX_FILTER_PRED; i++) {
if (filter->preds[i])
filter_free_pred(filter->preds[i]);
@@ -400,21 +395,27 @@ 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)
+{
+ if (!call->filter)
+ return;
+
+ __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;
@@ -430,12 +431,23 @@ 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;
- return -ENOMEM;
+ call->filter_active = 0;
+ call->filter = __alloc_preds();
+ if (IS_ERR(call->filter))
+ return PTR_ERR(call->filter);
+ return 0;
}
static int init_subsystem_preds(struct event_subsystem *system)
@@ -476,10 +488,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) {
@@ -494,7 +506,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
return err;
filter->n_preds++;
- call->filter_active = 1;
return 0;
}
@@ -570,6 +581,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)
{
@@ -638,7 +650,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;
}
@@ -996,6 +1008,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)
@@ -1042,7 +1055,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;
@@ -1058,10 +1071,12 @@ 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;
list_for_each_entry(call, &ftrace_events, list) {
+ filter = call->filter;
if (!call->define_fields)
continue;
@@ -1070,17 +1085,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;
}
@@ -1094,7 +1111,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);
@@ -1125,10 +1141,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);
@@ -1143,7 +1160,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
char *filter_string)
{
int err;
-
struct filter_parse_state *ps;
mutex_lock(&event_mutex);
@@ -1187,3 +1203,64 @@ out_unlock:
return err;
}
+#ifdef CONFIG_EVENT_PROFILE
+
+void destroy_profile_preds(struct ftrace_event_call *call)
+{
+ if (!call->profile_filter)
+ return;
+
+ __free_preds(call->profile_filter);
+ call->profile_filter = NULL;
+ call->profile_filter_active = 0;
+}
+EXPORT_SYMBOL_GPL(destroy_profile_preds);
+
+static int init_profile_preds(struct ftrace_event_call *call)
+{
+ if (call->profile_filter)
+ return 0;
+
+ call->profile_filter_active = 0;
+
+ call->profile_filter = __alloc_preds();
+ if (IS_ERR(call->profile_filter))
+ return PTR_ERR(call->profile_filter);
+ return 0;
+}
+
+/* Should be called with event_mutex held */
+int apply_profile_filter(struct ftrace_event_call *call, char *filter_string)
+{
+ int err;
+ struct filter_parse_state *ps;
+
+ err = init_profile_preds(call);
+ if (err)
+ return err;
+
+ err = -ENOMEM;
+ ps = kzalloc(sizeof(*ps), GFP_KERNEL);
+ if (!ps)
+ return err;
+
+ parse_init(ps, filter_ops, filter_string);
+ err = filter_parse(ps);
+ if (err)
+ goto out;
+
+ err = replace_preds(call, call->profile_filter, ps,
+ filter_string, false);
+ if (!err)
+ call->profile_filter_active = 1;
+
+out:
+ filter_opstack_clear(ps);
+ postfix_clear(ps);
+ kfree(ps);
+
+ return err;
+}
+
+#endif /* CONFIG_EVENT_PROFILE */
+
--
1.6.3
next prev parent reply other threads:[~2009-09-07 8:14 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-07 8:11 [PATCH 0/6] perf trace: Add filter support Li Zefan
2009-09-07 8:12 ` [PATCH 1/6] tracing/filters: refactor subsystem filter code Li Zefan
2009-09-07 8:12 ` Li Zefan [this message]
2009-09-08 2:01 ` [PATCH 2/6] tracing/profile: Add filter support Frederic Weisbecker
2009-09-08 2:24 ` Frederic Weisbecker
2009-09-08 8:35 ` Peter Zijlstra
2009-09-08 12:33 ` Frederic Weisbecker
2009-09-07 8:13 ` [PATCH 3/6] tracing/syscalls: Add profile " Li Zefan
2009-09-07 8:13 ` [PATCH 4/6] perf_counter: Add PERF_COUNTER_IOC_SET_FILTER ioctl Li Zefan
2009-09-07 16:44 ` Peter Zijlstra
2009-09-07 16:48 ` Ingo Molnar
2009-09-07 16:55 ` Peter Zijlstra
2009-09-08 0:49 ` Li Zefan
2009-09-08 6:52 ` Ingo Molnar
2009-09-08 8:37 ` Peter Zijlstra
2009-09-08 7:01 ` Tom Zanussi
2009-09-09 2:18 ` Li Zefan
2009-09-10 4:45 ` Tom Zanussi
2009-09-10 23:01 ` Randy Dunlap
2009-09-11 4:08 ` Tom Zanussi
2009-09-07 8:13 ` [PATCH 5/6] perf trace: increase MAX_EVENT_LENGTH Li Zefan
2009-09-07 8:14 ` [PATCH 6/6] perf trace: Add filter support Li Zefan
2009-09-08 0:02 ` [PATCH 0/6] " Frederic Weisbecker
2009-09-08 1:06 ` Li Zefan
2009-09-08 2:12 ` Frederic Weisbecker
2009-09-08 6:53 ` Ingo Molnar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4AA4C085.5050006@cn.fujitsu.com \
--to=lizf@cn.fujitsu.com \
--cc=fweisbec@gmail.com \
--cc=jbaron@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=tzanussi@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.