2008-05-13 03:20:42 +08:00
|
|
|
/*
|
|
|
|
* trace context switch
|
|
|
|
*
|
|
|
|
* Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/debugfs.h>
|
|
|
|
#include <linux/kallsyms.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <linux/ftrace.h>
|
2008-07-19 00:16:17 +08:00
|
|
|
#include <trace/sched.h>
|
2008-05-13 03:20:42 +08:00
|
|
|
|
|
|
|
#include "trace.h"
|
|
|
|
|
|
|
|
static struct trace_array *ctx_trace;
|
|
|
|
static int __read_mostly tracer_enabled;
|
2008-10-31 20:28:58 +08:00
|
|
|
static int sched_ref;
|
|
|
|
static DEFINE_MUTEX(sched_register_mutex);
|
2008-05-13 03:20:42 +08:00
|
|
|
|
2008-05-13 03:20:51 +08:00
|
|
|
static void
|
2008-07-19 00:16:17 +08:00
|
|
|
probe_sched_switch(struct rq *__rq, struct task_struct *prev,
|
2008-05-13 03:21:10 +08:00
|
|
|
struct task_struct *next)
|
2008-05-13 03:20:42 +08:00
|
|
|
{
|
|
|
|
struct trace_array_cpu *data;
|
|
|
|
unsigned long flags;
|
|
|
|
int cpu;
|
2008-10-02 01:14:09 +08:00
|
|
|
int pc;
|
2008-05-13 03:20:42 +08:00
|
|
|
|
2008-10-31 20:28:58 +08:00
|
|
|
if (!sched_ref)
|
2008-07-19 00:16:17 +08:00
|
|
|
return;
|
|
|
|
|
2008-05-22 23:49:22 +08:00
|
|
|
tracing_record_cmdline(prev);
|
|
|
|
tracing_record_cmdline(next);
|
|
|
|
|
2008-05-13 03:20:42 +08:00
|
|
|
if (!tracer_enabled)
|
|
|
|
return;
|
|
|
|
|
2008-10-02 01:14:09 +08:00
|
|
|
pc = preempt_count();
|
2008-05-13 03:20:44 +08:00
|
|
|
local_irq_save(flags);
|
2008-05-13 03:20:42 +08:00
|
|
|
cpu = raw_smp_processor_id();
|
2008-07-19 00:16:17 +08:00
|
|
|
data = ctx_trace->data[cpu];
|
2008-05-13 03:20:42 +08:00
|
|
|
|
2008-10-04 14:01:00 +08:00
|
|
|
if (likely(!atomic_read(&data->disabled)))
|
2008-10-02 01:14:09 +08:00
|
|
|
tracing_sched_switch_trace(ctx_trace, data, prev, next, flags, pc);
|
2008-05-13 03:20:42 +08:00
|
|
|
|
2008-05-13 03:20:44 +08:00
|
|
|
local_irq_restore(flags);
|
2008-05-13 03:20:42 +08:00
|
|
|
}
|
|
|
|
|
2008-05-13 03:20:52 +08:00
|
|
|
static void
|
2008-07-19 00:16:17 +08:00
|
|
|
probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee)
|
2008-05-13 03:20:51 +08:00
|
|
|
{
|
|
|
|
struct trace_array_cpu *data;
|
|
|
|
unsigned long flags;
|
2008-10-02 01:14:09 +08:00
|
|
|
int cpu, pc;
|
2008-05-13 03:20:51 +08:00
|
|
|
|
2008-07-19 00:16:17 +08:00
|
|
|
if (!likely(tracer_enabled))
|
2008-05-13 03:20:51 +08:00
|
|
|
return;
|
|
|
|
|
2008-10-02 01:14:09 +08:00
|
|
|
pc = preempt_count();
|
2008-07-19 00:16:17 +08:00
|
|
|
tracing_record_cmdline(current);
|
2008-05-13 03:20:53 +08:00
|
|
|
|
2008-05-13 03:20:51 +08:00
|
|
|
local_irq_save(flags);
|
|
|
|
cpu = raw_smp_processor_id();
|
2008-07-19 00:16:17 +08:00
|
|
|
data = ctx_trace->data[cpu];
|
2008-05-13 03:20:51 +08:00
|
|
|
|
2008-10-04 14:01:00 +08:00
|
|
|
if (likely(!atomic_read(&data->disabled)))
|
2008-07-19 00:16:17 +08:00
|
|
|
tracing_sched_wakeup_trace(ctx_trace, data, wakee, current,
|
2008-10-02 01:14:09 +08:00
|
|
|
flags, pc);
|
2008-05-13 03:20:51 +08:00
|
|
|
|
|
|
|
local_irq_restore(flags);
|
|
|
|
}
|
|
|
|
|
2008-05-13 03:20:51 +08:00
|
|
|
static void sched_switch_reset(struct trace_array *tr)
|
2008-05-13 03:20:42 +08:00
|
|
|
{
|
|
|
|
int cpu;
|
|
|
|
|
2008-05-13 03:20:46 +08:00
|
|
|
tr->time_start = ftrace_now(tr->cpu);
|
2008-05-13 03:20:42 +08:00
|
|
|
|
|
|
|
for_each_online_cpu(cpu)
|
2008-09-30 11:02:41 +08:00
|
|
|
tracing_reset(tr, cpu);
|
2008-05-13 03:20:42 +08:00
|
|
|
}
|
|
|
|
|
2008-05-13 03:21:10 +08:00
|
|
|
static int tracing_sched_register(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2008-07-19 00:16:17 +08:00
|
|
|
ret = register_trace_sched_wakeup(probe_sched_wakeup);
|
2008-05-13 03:21:10 +08:00
|
|
|
if (ret) {
|
2008-07-19 00:16:17 +08:00
|
|
|
pr_info("wakeup trace: Couldn't activate tracepoint"
|
2008-05-13 03:21:10 +08:00
|
|
|
" probe to kernel_sched_wakeup\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-07-19 00:16:17 +08:00
|
|
|
ret = register_trace_sched_wakeup_new(probe_sched_wakeup);
|
2008-05-13 03:21:10 +08:00
|
|
|
if (ret) {
|
2008-07-19 00:16:17 +08:00
|
|
|
pr_info("wakeup trace: Couldn't activate tracepoint"
|
2008-05-13 03:21:10 +08:00
|
|
|
" probe to kernel_sched_wakeup_new\n");
|
|
|
|
goto fail_deprobe;
|
|
|
|
}
|
|
|
|
|
2008-07-19 00:16:17 +08:00
|
|
|
ret = register_trace_sched_switch(probe_sched_switch);
|
2008-05-13 03:21:10 +08:00
|
|
|
if (ret) {
|
2008-07-19 00:16:17 +08:00
|
|
|
pr_info("sched trace: Couldn't activate tracepoint"
|
2008-05-13 03:21:10 +08:00
|
|
|
" probe to kernel_sched_schedule\n");
|
|
|
|
goto fail_deprobe_wake_new;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
fail_deprobe_wake_new:
|
2008-07-19 00:16:17 +08:00
|
|
|
unregister_trace_sched_wakeup_new(probe_sched_wakeup);
|
2008-05-13 03:21:10 +08:00
|
|
|
fail_deprobe:
|
2008-07-19 00:16:17 +08:00
|
|
|
unregister_trace_sched_wakeup(probe_sched_wakeup);
|
2008-05-13 03:21:10 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tracing_sched_unregister(void)
|
|
|
|
{
|
2008-07-19 00:16:17 +08:00
|
|
|
unregister_trace_sched_switch(probe_sched_switch);
|
|
|
|
unregister_trace_sched_wakeup_new(probe_sched_wakeup);
|
|
|
|
unregister_trace_sched_wakeup(probe_sched_wakeup);
|
2008-05-13 03:21:10 +08:00
|
|
|
}
|
|
|
|
|
2008-05-22 16:37:48 +08:00
|
|
|
static void tracing_start_sched_switch(void)
|
2008-05-13 03:21:10 +08:00
|
|
|
{
|
2008-10-31 20:28:58 +08:00
|
|
|
mutex_lock(&sched_register_mutex);
|
2008-11-08 11:36:02 +08:00
|
|
|
if (!(sched_ref++))
|
2008-05-13 03:21:10 +08:00
|
|
|
tracing_sched_register();
|
2008-10-31 20:28:58 +08:00
|
|
|
mutex_unlock(&sched_register_mutex);
|
2008-05-13 03:21:10 +08:00
|
|
|
}
|
|
|
|
|
2008-05-22 16:37:48 +08:00
|
|
|
static void tracing_stop_sched_switch(void)
|
2008-05-13 03:21:10 +08:00
|
|
|
{
|
2008-10-31 20:28:58 +08:00
|
|
|
mutex_lock(&sched_register_mutex);
|
2008-11-08 11:36:02 +08:00
|
|
|
if (!(--sched_ref))
|
2008-05-13 03:21:10 +08:00
|
|
|
tracing_sched_unregister();
|
2008-10-31 20:28:58 +08:00
|
|
|
mutex_unlock(&sched_register_mutex);
|
2008-05-13 03:21:10 +08:00
|
|
|
}
|
|
|
|
|
2008-05-22 23:49:22 +08:00
|
|
|
void tracing_start_cmdline_record(void)
|
|
|
|
{
|
|
|
|
tracing_start_sched_switch();
|
|
|
|
}
|
|
|
|
|
|
|
|
void tracing_stop_cmdline_record(void)
|
|
|
|
{
|
|
|
|
tracing_stop_sched_switch();
|
|
|
|
}
|
|
|
|
|
2008-11-08 11:36:02 +08:00
|
|
|
/**
|
2008-11-08 11:36:02 +08:00
|
|
|
* tracing_start_sched_switch_record - start tracing context switches
|
|
|
|
*
|
|
|
|
* Turns on context switch tracing for a tracer.
|
|
|
|
*/
|
|
|
|
void tracing_start_sched_switch_record(void)
|
|
|
|
{
|
|
|
|
if (unlikely(!ctx_trace)) {
|
|
|
|
WARN_ON(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tracing_start_sched_switch();
|
|
|
|
|
|
|
|
mutex_lock(&sched_register_mutex);
|
|
|
|
tracer_enabled++;
|
|
|
|
mutex_unlock(&sched_register_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tracing_stop_sched_switch_record - start tracing context switches
|
|
|
|
*
|
|
|
|
* Turns off context switch tracing for a tracer.
|
|
|
|
*/
|
|
|
|
void tracing_stop_sched_switch_record(void)
|
|
|
|
{
|
|
|
|
mutex_lock(&sched_register_mutex);
|
|
|
|
tracer_enabled--;
|
|
|
|
WARN_ON(tracer_enabled < 0);
|
|
|
|
mutex_unlock(&sched_register_mutex);
|
|
|
|
|
|
|
|
tracing_stop_sched_switch();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tracing_sched_switch_assign_trace - assign a trace array for ctx switch
|
2008-11-08 11:36:02 +08:00
|
|
|
* @tr: trace array pointer to assign
|
|
|
|
*
|
|
|
|
* Some tracers might want to record the context switches in their
|
|
|
|
* trace. This function lets those tracers assign the trace array
|
|
|
|
* to use.
|
|
|
|
*/
|
2008-11-08 11:36:02 +08:00
|
|
|
void tracing_sched_switch_assign_trace(struct trace_array *tr)
|
2008-11-08 11:36:02 +08:00
|
|
|
{
|
|
|
|
ctx_trace = tr;
|
|
|
|
}
|
|
|
|
|
2008-05-13 03:20:51 +08:00
|
|
|
static void start_sched_trace(struct trace_array *tr)
|
2008-05-13 03:20:42 +08:00
|
|
|
{
|
|
|
|
sched_switch_reset(tr);
|
2008-11-08 11:36:02 +08:00
|
|
|
tracing_start_sched_switch_record();
|
2008-05-13 03:20:42 +08:00
|
|
|
}
|
|
|
|
|
2008-05-13 03:20:51 +08:00
|
|
|
static void stop_sched_trace(struct trace_array *tr)
|
2008-05-13 03:20:42 +08:00
|
|
|
{
|
2008-11-08 11:36:02 +08:00
|
|
|
tracing_stop_sched_switch_record();
|
2008-05-13 03:20:42 +08:00
|
|
|
}
|
|
|
|
|
2008-05-13 03:20:51 +08:00
|
|
|
static void sched_switch_trace_init(struct trace_array *tr)
|
2008-05-13 03:20:42 +08:00
|
|
|
{
|
|
|
|
ctx_trace = tr;
|
2008-11-08 11:36:02 +08:00
|
|
|
start_sched_trace(tr);
|
2008-05-13 03:20:42 +08:00
|
|
|
}
|
|
|
|
|
2008-05-13 03:20:51 +08:00
|
|
|
static void sched_switch_trace_reset(struct trace_array *tr)
|
2008-05-13 03:20:42 +08:00
|
|
|
{
|
2008-11-08 11:36:02 +08:00
|
|
|
if (sched_ref)
|
2008-05-13 03:20:42 +08:00
|
|
|
stop_sched_trace(tr);
|
|
|
|
}
|
|
|
|
|
ftrace: restructure tracing start/stop infrastructure
Impact: change where tracing is started up and stopped
Currently, when a new tracer is selected via echo'ing a tracer name into
the current_tracer file, the startup is only done if tracing_enabled is
set to one. If tracing_enabled is changed to zero (by echo'ing 0 into
the tracing_enabled file) a full shutdown is performed.
The full startup and shutdown of a tracer can be expensive and the
user can lose out traces when echo'ing in 0 to the tracing_enabled file,
because the process takes too long. There can also be places that
the user would like to start and stop the tracer several times and
doing the full startup and shutdown of a tracer might be too expensive.
This patch performs the full startup and shutdown when a tracer is
selected. It also adds a way to do a quick start or stop of a tracer.
The quick version is just a flag that prevents the tracing from
taking place, but the overhead of the code is still there.
For example, the startup of a tracer may enable tracepoints, or enable
the function tracer. The stop and start will just set a flag to
have the tracer ignore the calls when the tracepoint or function trace
is called. The overhead of the tracer may still be present when
the tracer is stopped, but no tracing will occur. Setting the tracer
to the 'nop' tracer (or any other tracer) will perform the shutdown
of the tracer which will disable the tracepoint or disable the
function tracer.
The tracing_enabled file will simply start or stop tracing.
This change is all internal. The end result for the user should be the same
as before. If tracing_enabled is not set, no trace will happen.
If tracing_enabled is set, then the trace will happen. The tracing_enabled
variable is static between tracers. Enabling tracing_enabled and
going to another tracer will keep tracing_enabled enabled. Same
is true with disabling tracing_enabled.
This patch will now provide a fast start/stop method to the users
for enabling or disabling tracing.
Note: There were two methods to the struct tracer that were never
used: The methods start and stop. These were to be used as a hook
to the reading of the trace output, but ended up not being
necessary. These two methods are now used to enable the start
and stop of each tracer, in case the tracer needs to do more than
just not write into the buffer. For example, the irqsoff tracer
must stop recording max latencies when tracing is stopped.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-11-06 05:05:44 +08:00
|
|
|
static void sched_switch_trace_start(struct trace_array *tr)
|
|
|
|
{
|
|
|
|
sched_switch_reset(tr);
|
|
|
|
tracing_start_sched_switch();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sched_switch_trace_stop(struct trace_array *tr)
|
|
|
|
{
|
|
|
|
tracing_stop_sched_switch();
|
|
|
|
}
|
|
|
|
|
2008-11-08 11:36:02 +08:00
|
|
|
static struct tracer sched_switch_trace __read_mostly =
|
2008-05-13 03:20:42 +08:00
|
|
|
{
|
|
|
|
.name = "sched_switch",
|
|
|
|
.init = sched_switch_trace_init,
|
|
|
|
.reset = sched_switch_trace_reset,
|
ftrace: restructure tracing start/stop infrastructure
Impact: change where tracing is started up and stopped
Currently, when a new tracer is selected via echo'ing a tracer name into
the current_tracer file, the startup is only done if tracing_enabled is
set to one. If tracing_enabled is changed to zero (by echo'ing 0 into
the tracing_enabled file) a full shutdown is performed.
The full startup and shutdown of a tracer can be expensive and the
user can lose out traces when echo'ing in 0 to the tracing_enabled file,
because the process takes too long. There can also be places that
the user would like to start and stop the tracer several times and
doing the full startup and shutdown of a tracer might be too expensive.
This patch performs the full startup and shutdown when a tracer is
selected. It also adds a way to do a quick start or stop of a tracer.
The quick version is just a flag that prevents the tracing from
taking place, but the overhead of the code is still there.
For example, the startup of a tracer may enable tracepoints, or enable
the function tracer. The stop and start will just set a flag to
have the tracer ignore the calls when the tracepoint or function trace
is called. The overhead of the tracer may still be present when
the tracer is stopped, but no tracing will occur. Setting the tracer
to the 'nop' tracer (or any other tracer) will perform the shutdown
of the tracer which will disable the tracepoint or disable the
function tracer.
The tracing_enabled file will simply start or stop tracing.
This change is all internal. The end result for the user should be the same
as before. If tracing_enabled is not set, no trace will happen.
If tracing_enabled is set, then the trace will happen. The tracing_enabled
variable is static between tracers. Enabling tracing_enabled and
going to another tracer will keep tracing_enabled enabled. Same
is true with disabling tracing_enabled.
This patch will now provide a fast start/stop method to the users
for enabling or disabling tracing.
Note: There were two methods to the struct tracer that were never
used: The methods start and stop. These were to be used as a hook
to the reading of the trace output, but ended up not being
necessary. These two methods are now used to enable the start
and stop of each tracer, in case the tracer needs to do more than
just not write into the buffer. For example, the irqsoff tracer
must stop recording max latencies when tracing is stopped.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-11-06 05:05:44 +08:00
|
|
|
.start = sched_switch_trace_start,
|
|
|
|
.stop = sched_switch_trace_stop,
|
2008-05-13 03:20:44 +08:00
|
|
|
#ifdef CONFIG_FTRACE_SELFTEST
|
|
|
|
.selftest = trace_selftest_startup_sched_switch,
|
|
|
|
#endif
|
2008-05-13 03:20:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
__init static int init_sched_switch_trace(void)
|
|
|
|
{
|
|
|
|
return register_tracer(&sched_switch_trace);
|
|
|
|
}
|
|
|
|
device_initcall(init_sched_switch_trace);
|