[PATCHv2 10/10] ftrace, graph: Add global_ops filter callback for graph tracing

From: Jiri Olsa
Date: Mon Dec 05 2011 - 12:23:35 EST


The function graph tracer should depend on the global_ops filter,
and process only functions that pass the global_ops filter.

Currently the function graph tracer gets all the functions
enabled for tracing no matter what ftrace_ops enabled them.

Adding a hook for the graph entry callback, which ensures the
function is compared against the global_ops filter and bail
out of if it does not match.

This hook is enabled only if there's at least one non global
ftrace_ops registered.

Signed-off-by: Jiri Olsa <jolsa@xxxxxxxxxx>
---
kernel/trace/ftrace.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 41 insertions(+), 0 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 2dae0c7..dc49ba6 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -95,10 +95,13 @@ ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;
ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
static struct ftrace_ops global_ops;
static struct ftrace_ops control_ops;
+static int non_global_ops_registered;

static void
ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip);

+static void ftrace_graph_update_filter(void);
+
/*
* Traverse the ftrace_global_list, invoking all entries. The reason that we
* can use rcu_dereference_raw() is that elements removed from this list
@@ -330,6 +333,9 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
if (!core_kernel_data((unsigned long)ops))
ops->flags |= FTRACE_OPS_FL_DYNAMIC;

+ if (!(ops->flags & FTRACE_OPS_FL_GLOBAL))
+ non_global_ops_registered++;
+
if (ops->flags & FTRACE_OPS_FL_GLOBAL) {
add_ftrace_ops(&ftrace_global_list, &global_ops, ops);
ops->flags |= FTRACE_OPS_FL_ENABLED;
@@ -359,6 +365,9 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
if (FTRACE_WARN_ON(ops == &global_ops))
return -EINVAL;

+ if (!(ops->flags & FTRACE_OPS_FL_GLOBAL))
+ non_global_ops_registered--;
+
if (ops->flags & FTRACE_OPS_FL_GLOBAL) {
ret = remove_ftrace_ops(&ftrace_global_list, &global_ops, ops);
if (!ret)
@@ -1695,6 +1704,8 @@ static int __ftrace_modify_code(void *data)
if (*command & FTRACE_UPDATE_TRACE_FUNC)
ftrace_update_ftrace_func(ftrace_trace_function);

+ ftrace_graph_update_filter();
+
if (*command & FTRACE_START_FUNC_RET)
ftrace_enable_ftrace_graph_caller();
else if (*command & FTRACE_STOP_FUNC_RET)
@@ -4339,4 +4350,34 @@ void ftrace_graph_stop(void)
{
ftrace_stop();
}
+
+static trace_func_graph_ent_t ftrace_graph_entry_saved;
+
+int ftrace_graph_entry_filter(struct ftrace_graph_ent *ent)
+{
+ if (ftrace_ops_test(&global_ops, ent->func))
+ return ftrace_graph_entry_saved(ent);
+
+ return 0;
+}
+
+static void ftrace_graph_update_filter(void)
+{
+ bool installed = (ftrace_graph_entry == ftrace_graph_entry_filter);
+
+ if (!ftrace_graph_active)
+ return;
+
+ if (!installed && non_global_ops_registered) {
+ ftrace_graph_entry_saved = ftrace_graph_entry;
+ ftrace_graph_entry = ftrace_graph_entry_filter;
+ return;
+ }
+
+ if (installed && !non_global_ops_registered)
+ ftrace_graph_entry = ftrace_graph_entry_saved;
+}
+
+#else
+static void ftrace_graph_update_filter(void) { }
#endif
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/