tracing/filters: Defer pred allocation
Li Zefan [Mon, 31 Aug 2009 08:49:41 +0000 (16:49 +0800)]
init_preds() allocates about 5392 bytes of memory (on x86_32) for
a TRACE_EVENT. With my config, at system boot total memory occupied
is:

5392 * (642 + 15) == 3459KB

642 == cat available_events | wc -l
15 == number of dirs in events/ftrace

That's quite a lot, so we'd better defer memory allocation util
it's needed, that's when filter is used.

Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: Masami Hiramatsu <mhiramat@redhat.com>
LKML-Reference: <4A9B8EA5.6020700@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

include/linux/ftrace_event.h
include/linux/syscalls.h
include/trace/ftrace.h
kernel/trace/trace_events_filter.c
kernel/trace/trace_export.c

index ace2da9..7554804 100644 (file)
@@ -133,7 +133,6 @@ struct ftrace_event_call {
 #define MAX_FILTER_PRED                32
 #define MAX_FILTER_STR_VAL     128
 
-extern int init_preds(struct ftrace_event_call *call);
 extern void destroy_preds(struct ftrace_event_call *call);
 extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
 extern int filter_current_check_discard(struct ftrace_event_call *call,
index f124c89..a8e3782 100644 (file)
@@ -177,7 +177,6 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \
                event_enter_##sname.id = id;                            \
                set_syscall_enter_id(num, id);                          \
                INIT_LIST_HEAD(&event_enter_##sname.fields);            \
-               init_preds(&event_enter_##sname);                       \
                return 0;                                               \
        }                                                               \
        TRACE_SYS_ENTER_PROFILE(sname);                                 \
@@ -214,7 +213,6 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \
                event_exit_##sname.id = id;                             \
                set_syscall_exit_id(num, id);                           \
                INIT_LIST_HEAD(&event_exit_##sname.fields);             \
-               init_preds(&event_exit_##sname);                        \
                return 0;                                               \
        }                                                               \
        TRACE_SYS_EXIT_PROFILE(sname);                                  \
index 57c56a9..bfbc842 100644 (file)
@@ -622,7 +622,6 @@ static int ftrace_raw_init_event_##call(void)                               \
                return -ENODEV;                                         \
        event_##call.id = id;                                           \
        INIT_LIST_HEAD(&event_##call.fields);                           \
-       init_preds(&event_##call);                                      \
        return 0;                                                       \
 }                                                                      \
                                                                        \
index 9f03082..c6b2edf 100644 (file)
@@ -309,7 +309,7 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
        struct event_filter *filter = call->filter;
 
        mutex_lock(&event_mutex);
-       if (filter->filter_string)
+       if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
                trace_seq_printf(s, "none\n");
@@ -322,7 +322,7 @@ void print_subsystem_event_filter(struct event_subsystem *system,
        struct event_filter *filter = system->filter;
 
        mutex_lock(&event_mutex);
-       if (filter->filter_string)
+       if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
                trace_seq_printf(s, "none\n");
@@ -390,6 +390,9 @@ void destroy_preds(struct ftrace_event_call *call)
        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,7 +403,7 @@ void destroy_preds(struct ftrace_event_call *call)
        call->filter = NULL;
 }
 
-int init_preds(struct ftrace_event_call *call)
+static int init_preds(struct ftrace_event_call *call)
 {
        struct event_filter *filter;
        struct filter_pred *pred;
@@ -410,7 +413,6 @@ int init_preds(struct ftrace_event_call *call)
        if (!call->filter)
                return -ENOMEM;
 
-       call->filter_active = 0;
        filter->n_preds = 0;
 
        filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
@@ -432,7 +434,28 @@ oom:
 
        return -ENOMEM;
 }
-EXPORT_SYMBOL_GPL(init_preds);
+
+static int init_subsystem_preds(struct event_subsystem *system)
+{
+       struct ftrace_event_call *call;
+       int err;
+
+       list_for_each_entry(call, &ftrace_events, list) {
+               if (!call->define_fields)
+                       continue;
+
+               if (strcmp(call->system, system->name) != 0)
+                       continue;
+
+               if (!call->filter) {
+                       err = init_preds(call);
+                       if (err)
+                               return err;
+               }
+       }
+
+       return 0;
+}
 
 enum {
        FILTER_DISABLE_ALL,
@@ -449,6 +472,9 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
                if (!call->define_fields)
                        continue;
 
+               if (strcmp(call->system, system->name) != 0)
+                       continue;
+
                if (flag == FILTER_INIT_NO_RESET) {
                        call->filter->no_reset = false;
                        continue;
@@ -457,10 +483,8 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
                if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset)
                        continue;
 
-               if (!strcmp(call->system, system->name)) {
-                       filter_disable_preds(call);
-                       remove_filter_string(call->filter);
-               }
+               filter_disable_preds(call);
+               remove_filter_string(call->filter);
        }
 }
 
@@ -1094,6 +1118,10 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
 
        mutex_lock(&event_mutex);
 
+       err = init_preds(call);
+       if (err)
+               goto out_unlock;
+
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_disable_preds(call);
                remove_filter_string(call->filter);
@@ -1139,6 +1167,10 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
 
        mutex_lock(&event_mutex);
 
+       err = init_subsystem_preds(system);
+       if (err)
+               goto out_unlock;
+
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_free_subsystem_preds(system, FILTER_DISABLE_ALL);
                remove_filter_string(system->filter);
index 029a91f..df1bf6e 100644 (file)
@@ -135,7 +135,6 @@ __attribute__((section("_ftrace_events"))) event_##call = {         \
 static int ftrace_raw_init_event_##call(void)                          \
 {                                                                      \
        INIT_LIST_HEAD(&event_##call.fields);                           \
-       init_preds(&event_##call);                                      \
        return 0;                                                       \
 }                                                                      \