Skip to content

Commit

Permalink
tracing: Add function-trace option to disable function tracing of lat…
Browse files Browse the repository at this point in the history
…ency tracers

Currently, the only way to stop the latency tracers from doing function
tracing is to fully disable the function tracer from the proc file
system:

  echo 0 > /proc/sys/kernel/ftrace_enabled

This is a big hammer approach as it disables function tracing for
all users. This includes kprobes, perf, stack tracer, etc.

Instead, create a function-trace option that the latency tracers can
check to determine if it should enable function tracing or not.
This option can be set or cleared even while the tracer is active
and the tracers will disable or enable function tracing depending
on how the option was set.

Instead of using the proc file, disable latency function tracing with

  echo 0 > /debug/tracing/options/function-trace

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Clark Williams <williams@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt (Red Hat) committed Mar 15, 2013
1 parent 4df2971 commit 328df47
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 23 deletions.
3 changes: 2 additions & 1 deletion kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ static inline void trace_access_lock_init(void)
unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS;
TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION;

/**
* tracing_on - enable tracing buffers
Expand Down Expand Up @@ -635,6 +635,7 @@ static const char *trace_options[] = {
"disable_on_free",
"irq-info",
"markers",
"function-trace",
NULL
};

Expand Down
1 change: 1 addition & 0 deletions kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ enum trace_iterator_flags {
TRACE_ITER_STOP_ON_FREE = 0x400000,
TRACE_ITER_IRQ_INFO = 0x800000,
TRACE_ITER_MARKERS = 0x1000000,
TRACE_ITER_FUNCTION = 0x2000000,
};

/*
Expand Down
67 changes: 55 additions & 12 deletions kernel/trace/trace_irqsoff.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum {
static int trace_type __read_mostly;

static int save_flags;
static bool function_enabled;

static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
static int start_irqsoff_tracer(struct trace_array *tr, int graph);
Expand Down Expand Up @@ -528,15 +529,60 @@ void trace_preempt_off(unsigned long a0, unsigned long a1)
}
#endif /* CONFIG_PREEMPT_TRACER */

static int start_irqsoff_tracer(struct trace_array *tr, int graph)
static int register_irqsoff_function(int graph, int set)
{
int ret = 0;
int ret;

if (!graph)
ret = register_ftrace_function(&trace_ops);
else
/* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
return 0;

if (graph)
ret = register_ftrace_graph(&irqsoff_graph_return,
&irqsoff_graph_entry);
else
ret = register_ftrace_function(&trace_ops);

if (!ret)
function_enabled = true;

return ret;
}

static void unregister_irqsoff_function(int graph)
{
if (!function_enabled)
return;

if (graph)
unregister_ftrace_graph();
else
unregister_ftrace_function(&trace_ops);

function_enabled = false;
}

static void irqsoff_function_set(int set)
{
if (set)
register_irqsoff_function(is_graph(), 1);
else
unregister_irqsoff_function(is_graph());
}

static int irqsoff_flag_changed(struct tracer *tracer, u32 mask, int set)
{
if (mask & TRACE_ITER_FUNCTION)
irqsoff_function_set(set);

return trace_keep_overwrite(tracer, mask, set);
}

static int start_irqsoff_tracer(struct trace_array *tr, int graph)
{
int ret;

ret = register_irqsoff_function(graph, 0);

if (!ret && tracing_is_enabled())
tracer_enabled = 1;
Expand All @@ -550,10 +596,7 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
{
tracer_enabled = 0;

if (!graph)
unregister_ftrace_function(&trace_ops);
else
unregister_ftrace_graph();
unregister_irqsoff_function(graph);
}

static void __irqsoff_tracer_init(struct trace_array *tr)
Expand Down Expand Up @@ -615,7 +658,7 @@ static struct tracer irqsoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite,
.flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_irqsoff,
#endif
Expand Down Expand Up @@ -649,7 +692,7 @@ static struct tracer preemptoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite,
.flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_preemptoff,
#endif
Expand Down Expand Up @@ -685,7 +728,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite,
.flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_preemptirqsoff,
#endif
Expand Down
63 changes: 53 additions & 10 deletions kernel/trace/trace_sched_wakeup.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
static void wakeup_graph_return(struct ftrace_graph_ret *trace);

static int save_flags;
static bool function_enabled;

#define TRACE_DISPLAY_GRAPH 1

Expand Down Expand Up @@ -134,15 +135,60 @@ static struct ftrace_ops trace_ops __read_mostly =
};
#endif /* CONFIG_FUNCTION_TRACER */

static int start_func_tracer(int graph)
static int register_wakeup_function(int graph, int set)
{
int ret;

if (!graph)
ret = register_ftrace_function(&trace_ops);
else
/* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
return 0;

if (graph)
ret = register_ftrace_graph(&wakeup_graph_return,
&wakeup_graph_entry);
else
ret = register_ftrace_function(&trace_ops);

if (!ret)
function_enabled = true;

return ret;
}

static void unregister_wakeup_function(int graph)
{
if (!function_enabled)
return;

if (graph)
unregister_ftrace_graph();
else
unregister_ftrace_function(&trace_ops);

function_enabled = false;
}

static void wakeup_function_set(int set)
{
if (set)
register_wakeup_function(is_graph(), 1);
else
unregister_wakeup_function(is_graph());
}

static int wakeup_flag_changed(struct tracer *tracer, u32 mask, int set)
{
if (mask & TRACE_ITER_FUNCTION)
wakeup_function_set(set);

return trace_keep_overwrite(tracer, mask, set);
}

static int start_func_tracer(int graph)
{
int ret;

ret = register_wakeup_function(graph, 0);

if (!ret && tracing_is_enabled())
tracer_enabled = 1;
Expand All @@ -156,10 +202,7 @@ static void stop_func_tracer(int graph)
{
tracer_enabled = 0;

if (!graph)
unregister_ftrace_function(&trace_ops);
else
unregister_ftrace_graph();
unregister_wakeup_function(graph);
}

#ifdef CONFIG_FUNCTION_GRAPH_TRACER
Expand Down Expand Up @@ -600,7 +643,7 @@ static struct tracer wakeup_tracer __read_mostly =
.print_line = wakeup_print_line,
.flags = &tracer_flags,
.set_flag = wakeup_set_flag,
.flag_changed = trace_keep_overwrite,
.flag_changed = wakeup_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup,
#endif
Expand All @@ -622,7 +665,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
.print_line = wakeup_print_line,
.flags = &tracer_flags,
.set_flag = wakeup_set_flag,
.flag_changed = trace_keep_overwrite,
.flag_changed = wakeup_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup,
#endif
Expand Down

0 comments on commit 328df47

Please sign in to comment.