trace_sched_switch.c 5.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * 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>
M
Mathieu Desnoyers 已提交
13
#include <trace/sched.h>
14 15 16 17 18

#include "trace.h"

static struct trace_array	*ctx_trace;
static int __read_mostly	tracer_enabled;
19 20
static int			sched_ref;
static DEFINE_MUTEX(sched_register_mutex);
21
static int			sched_stopped;
22

I
Ingo Molnar 已提交
23
static void
M
Mathieu Desnoyers 已提交
24
probe_sched_switch(struct rq *__rq, struct task_struct *prev,
M
Mathieu Desnoyers 已提交
25
			struct task_struct *next)
26 27 28 29
{
	struct trace_array_cpu *data;
	unsigned long flags;
	int cpu;
30
	int pc;
31

32
	if (!sched_ref || sched_stopped)
M
Mathieu Desnoyers 已提交
33 34
		return;

35 36 37
	tracing_record_cmdline(prev);
	tracing_record_cmdline(next);

38 39 40
	if (!tracer_enabled)
		return;

41
	pc = preempt_count();
42
	local_irq_save(flags);
43
	cpu = raw_smp_processor_id();
M
Mathieu Desnoyers 已提交
44
	data = ctx_trace->data[cpu];
45

46
	if (likely(!atomic_read(&data->disabled)))
47
		tracing_sched_switch_trace(ctx_trace, prev, next, flags, pc);
48

49
	local_irq_restore(flags);
50 51
}

52
static void
53
probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee, int success)
54 55 56
{
	struct trace_array_cpu *data;
	unsigned long flags;
57
	int cpu, pc;
58

M
Mathieu Desnoyers 已提交
59
	if (!likely(tracer_enabled))
60 61
		return;

62
	pc = preempt_count();
M
Mathieu Desnoyers 已提交
63
	tracing_record_cmdline(current);
I
Ingo Molnar 已提交
64

65 66
	local_irq_save(flags);
	cpu = raw_smp_processor_id();
M
Mathieu Desnoyers 已提交
67
	data = ctx_trace->data[cpu];
68

69
	if (likely(!atomic_read(&data->disabled)))
70
		tracing_sched_wakeup_trace(ctx_trace, wakee, current,
71
					   flags, pc);
72 73 74 75

	local_irq_restore(flags);
}

M
Mathieu Desnoyers 已提交
76 77 78 79
static int tracing_sched_register(void)
{
	int ret;

M
Mathieu Desnoyers 已提交
80
	ret = register_trace_sched_wakeup(probe_sched_wakeup);
M
Mathieu Desnoyers 已提交
81
	if (ret) {
M
Mathieu Desnoyers 已提交
82
		pr_info("wakeup trace: Couldn't activate tracepoint"
M
Mathieu Desnoyers 已提交
83 84 85 86
			" probe to kernel_sched_wakeup\n");
		return ret;
	}

M
Mathieu Desnoyers 已提交
87
	ret = register_trace_sched_wakeup_new(probe_sched_wakeup);
M
Mathieu Desnoyers 已提交
88
	if (ret) {
M
Mathieu Desnoyers 已提交
89
		pr_info("wakeup trace: Couldn't activate tracepoint"
M
Mathieu Desnoyers 已提交
90 91 92 93
			" probe to kernel_sched_wakeup_new\n");
		goto fail_deprobe;
	}

M
Mathieu Desnoyers 已提交
94
	ret = register_trace_sched_switch(probe_sched_switch);
M
Mathieu Desnoyers 已提交
95
	if (ret) {
M
Mathieu Desnoyers 已提交
96
		pr_info("sched trace: Couldn't activate tracepoint"
97
			" probe to kernel_sched_switch\n");
M
Mathieu Desnoyers 已提交
98 99 100 101 102
		goto fail_deprobe_wake_new;
	}

	return ret;
fail_deprobe_wake_new:
M
Mathieu Desnoyers 已提交
103
	unregister_trace_sched_wakeup_new(probe_sched_wakeup);
M
Mathieu Desnoyers 已提交
104
fail_deprobe:
M
Mathieu Desnoyers 已提交
105
	unregister_trace_sched_wakeup(probe_sched_wakeup);
M
Mathieu Desnoyers 已提交
106 107 108 109 110
	return ret;
}

static void tracing_sched_unregister(void)
{
M
Mathieu Desnoyers 已提交
111 112 113
	unregister_trace_sched_switch(probe_sched_switch);
	unregister_trace_sched_wakeup_new(probe_sched_wakeup);
	unregister_trace_sched_wakeup(probe_sched_wakeup);
M
Mathieu Desnoyers 已提交
114 115
}

I
Ingo Molnar 已提交
116
static void tracing_start_sched_switch(void)
M
Mathieu Desnoyers 已提交
117
{
118
	mutex_lock(&sched_register_mutex);
S
Steven Rostedt 已提交
119
	if (!(sched_ref++))
M
Mathieu Desnoyers 已提交
120
		tracing_sched_register();
121
	mutex_unlock(&sched_register_mutex);
M
Mathieu Desnoyers 已提交
122 123
}

I
Ingo Molnar 已提交
124
static void tracing_stop_sched_switch(void)
M
Mathieu Desnoyers 已提交
125
{
126
	mutex_lock(&sched_register_mutex);
S
Steven Rostedt 已提交
127
	if (!(--sched_ref))
M
Mathieu Desnoyers 已提交
128
		tracing_sched_unregister();
129
	mutex_unlock(&sched_register_mutex);
M
Mathieu Desnoyers 已提交
130 131
}

132 133 134 135 136 137 138 139 140 141
void tracing_start_cmdline_record(void)
{
	tracing_start_sched_switch();
}

void tracing_stop_cmdline_record(void)
{
	tracing_stop_sched_switch();
}

142
/**
S
Steven Rostedt 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
 * 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
178 179 180 181 182 183
 * @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.
 */
S
Steven Rostedt 已提交
184
void tracing_sched_switch_assign_trace(struct trace_array *tr)
185 186 187 188
{
	ctx_trace = tr;
}

I
Ingo Molnar 已提交
189
static void stop_sched_trace(struct trace_array *tr)
190
{
S
Steven Rostedt 已提交
191
	tracing_stop_sched_switch_record();
192 193
}

194
static int sched_switch_trace_init(struct trace_array *tr)
195 196
{
	ctx_trace = tr;
197
	tracing_reset_online_cpus(tr);
198
	tracing_start_sched_switch_record();
199
	return 0;
200 201
}

I
Ingo Molnar 已提交
202
static void sched_switch_trace_reset(struct trace_array *tr)
203
{
S
Steven Rostedt 已提交
204
	if (sched_ref)
205 206 207
		stop_sched_trace(tr);
}

208 209
static void sched_switch_trace_start(struct trace_array *tr)
{
210
	sched_stopped = 0;
211 212 213 214
}

static void sched_switch_trace_stop(struct trace_array *tr)
{
215
	sched_stopped = 1;
216 217
}

218
static struct tracer sched_switch_trace __read_mostly =
219 220 221 222
{
	.name		= "sched_switch",
	.init		= sched_switch_trace_init,
	.reset		= sched_switch_trace_reset,
223 224
	.start		= sched_switch_trace_start,
	.stop		= sched_switch_trace_stop,
225
	.wait_pipe	= poll_wait_pipe,
S
Steven Rostedt 已提交
226 227 228
#ifdef CONFIG_FTRACE_SELFTEST
	.selftest    = trace_selftest_startup_sched_switch,
#endif
229 230 231 232 233 234 235
};

__init static int init_sched_switch_trace(void)
{
	return register_tracer(&sched_switch_trace);
}
device_initcall(init_sched_switch_trace);
236