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 67
	if (sched_stopped)
		return;

68 69
	local_irq_save(flags);
	cpu = raw_smp_processor_id();
M
Mathieu Desnoyers 已提交
70
	data = ctx_trace->data[cpu];
71

72
	if (likely(!atomic_read(&data->disabled)))
73
		tracing_sched_wakeup_trace(ctx_trace, wakee, current,
74
					   flags, pc);
75 76 77 78

	local_irq_restore(flags);
}

M
Mathieu Desnoyers 已提交
79 80 81 82
static int tracing_sched_register(void)
{
	int ret;

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

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

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

	return ret;
fail_deprobe_wake_new:
M
Mathieu Desnoyers 已提交
106
	unregister_trace_sched_wakeup_new(probe_sched_wakeup);
M
Mathieu Desnoyers 已提交
107
fail_deprobe:
M
Mathieu Desnoyers 已提交
108
	unregister_trace_sched_wakeup(probe_sched_wakeup);
M
Mathieu Desnoyers 已提交
109 110 111 112 113
	return ret;
}

static void tracing_sched_unregister(void)
{
M
Mathieu Desnoyers 已提交
114 115 116
	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 已提交
117 118
}

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

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

135 136 137 138 139 140 141 142 143 144
void tracing_start_cmdline_record(void)
{
	tracing_start_sched_switch();
}

void tracing_stop_cmdline_record(void)
{
	tracing_stop_sched_switch();
}

145
/**
S
Steven Rostedt 已提交
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 178 179 180
 * 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
181 182 183 184 185 186
 * @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 已提交
187
void tracing_sched_switch_assign_trace(struct trace_array *tr)
188 189 190 191
{
	ctx_trace = tr;
}

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

197
static int sched_switch_trace_init(struct trace_array *tr)
198 199
{
	ctx_trace = tr;
200
	tracing_reset_online_cpus(tr);
201
	tracing_start_sched_switch_record();
202
	return 0;
203 204
}

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

211 212
static void sched_switch_trace_start(struct trace_array *tr)
{
213
	sched_stopped = 0;
214 215 216 217
}

static void sched_switch_trace_stop(struct trace_array *tr)
{
218
	sched_stopped = 1;
219 220
}

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

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