135e8e302SSteven Rostedt /*
235e8e302SSteven Rostedt  * trace context switch
335e8e302SSteven Rostedt  *
435e8e302SSteven Rostedt  * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
535e8e302SSteven Rostedt  *
635e8e302SSteven Rostedt  */
735e8e302SSteven Rostedt #include <linux/module.h>
835e8e302SSteven Rostedt #include <linux/fs.h>
935e8e302SSteven Rostedt #include <linux/debugfs.h>
1035e8e302SSteven Rostedt #include <linux/kallsyms.h>
1135e8e302SSteven Rostedt #include <linux/uaccess.h>
1235e8e302SSteven Rostedt #include <linux/marker.h>
1335e8e302SSteven Rostedt #include <linux/ftrace.h>
1435e8e302SSteven Rostedt 
1535e8e302SSteven Rostedt #include "trace.h"
1635e8e302SSteven Rostedt 
1735e8e302SSteven Rostedt static struct trace_array	*ctx_trace;
1835e8e302SSteven Rostedt static int __read_mostly	tracer_enabled;
1935e8e302SSteven Rostedt 
20e309b41dSIngo Molnar static void
214e655519SIngo Molnar ctx_switch_func(void *__rq, struct task_struct *prev, struct task_struct *next)
2235e8e302SSteven Rostedt {
2335e8e302SSteven Rostedt 	struct trace_array *tr = ctx_trace;
2435e8e302SSteven Rostedt 	struct trace_array_cpu *data;
2535e8e302SSteven Rostedt 	unsigned long flags;
2635e8e302SSteven Rostedt 	long disabled;
2735e8e302SSteven Rostedt 	int cpu;
2835e8e302SSteven Rostedt 
2935e8e302SSteven Rostedt 	if (!tracer_enabled)
3035e8e302SSteven Rostedt 		return;
3135e8e302SSteven Rostedt 
32d9af56fbSIngo Molnar 	tracing_record_cmdline(prev);
33d9af56fbSIngo Molnar 
3418cef379SSteven Rostedt 	local_irq_save(flags);
3535e8e302SSteven Rostedt 	cpu = raw_smp_processor_id();
3635e8e302SSteven Rostedt 	data = tr->data[cpu];
3735e8e302SSteven Rostedt 	disabled = atomic_inc_return(&data->disabled);
3835e8e302SSteven Rostedt 
394e655519SIngo Molnar 	if (likely(disabled == 1)) {
4035e8e302SSteven Rostedt 		tracing_sched_switch_trace(tr, data, prev, next, flags);
414ac3ba41SIngo Molnar 		if (trace_flags & TRACE_ITER_SCHED_TREE)
424e655519SIngo Molnar 			ftrace_all_fair_tasks(__rq, tr, data);
434e655519SIngo Molnar 	}
4435e8e302SSteven Rostedt 
4535e8e302SSteven Rostedt 	atomic_dec(&data->disabled);
4618cef379SSteven Rostedt 	local_irq_restore(flags);
4735e8e302SSteven Rostedt }
4835e8e302SSteven Rostedt 
494e655519SIngo Molnar static void
504e655519SIngo Molnar wakeup_func(void *__rq, struct task_struct *wakee, struct task_struct *curr)
5157422797SIngo Molnar {
5257422797SIngo Molnar 	struct trace_array *tr = ctx_trace;
5357422797SIngo Molnar 	struct trace_array_cpu *data;
5457422797SIngo Molnar 	unsigned long flags;
5557422797SIngo Molnar 	long disabled;
5657422797SIngo Molnar 	int cpu;
5757422797SIngo Molnar 
5857422797SIngo Molnar 	if (!tracer_enabled)
5957422797SIngo Molnar 		return;
6057422797SIngo Molnar 
61d9af56fbSIngo Molnar 	tracing_record_cmdline(curr);
62d9af56fbSIngo Molnar 
6357422797SIngo Molnar 	local_irq_save(flags);
6457422797SIngo Molnar 	cpu = raw_smp_processor_id();
6557422797SIngo Molnar 	data = tr->data[cpu];
6657422797SIngo Molnar 	disabled = atomic_inc_return(&data->disabled);
6757422797SIngo Molnar 
684e655519SIngo Molnar 	if (likely(disabled == 1)) {
6957422797SIngo Molnar 		tracing_sched_wakeup_trace(tr, data, wakee, curr, flags);
704ac3ba41SIngo Molnar 		if (trace_flags & TRACE_ITER_SCHED_TREE)
714e655519SIngo Molnar 			ftrace_all_fair_tasks(__rq, tr, data);
724e655519SIngo Molnar 	}
7357422797SIngo Molnar 
7457422797SIngo Molnar 	atomic_dec(&data->disabled);
7557422797SIngo Molnar 	local_irq_restore(flags);
7657422797SIngo Molnar }
7757422797SIngo Molnar 
784e655519SIngo Molnar void
794e655519SIngo Molnar ftrace_ctx_switch(void *__rq, struct task_struct *prev,
804e655519SIngo Molnar 		  struct task_struct *next)
8135e8e302SSteven Rostedt {
8235e8e302SSteven Rostedt 	/*
8335e8e302SSteven Rostedt 	 * If tracer_switch_func only points to the local
8435e8e302SSteven Rostedt 	 * switch func, it still needs the ptr passed to it.
8535e8e302SSteven Rostedt 	 */
864e655519SIngo Molnar 	ctx_switch_func(__rq, prev, next);
8735e8e302SSteven Rostedt 
8835e8e302SSteven Rostedt 	/*
8935e8e302SSteven Rostedt 	 * Chain to the wakeup tracer (this is a NOP if disabled):
9035e8e302SSteven Rostedt 	 */
9135e8e302SSteven Rostedt 	wakeup_sched_switch(prev, next);
9235e8e302SSteven Rostedt }
9335e8e302SSteven Rostedt 
9457422797SIngo Molnar void
954e655519SIngo Molnar ftrace_wake_up_task(void *__rq, struct task_struct *wakee,
964e655519SIngo Molnar 		    struct task_struct *curr)
9757422797SIngo Molnar {
984e655519SIngo Molnar 	wakeup_func(__rq, wakee, curr);
9957422797SIngo Molnar 
10057422797SIngo Molnar 	/*
10157422797SIngo Molnar 	 * Chain to the wakeup tracer (this is a NOP if disabled):
10257422797SIngo Molnar 	 */
10357422797SIngo Molnar 	wakeup_sched_wakeup(wakee, curr);
10457422797SIngo Molnar }
10557422797SIngo Molnar 
10688a4216cSIngo Molnar void
10788a4216cSIngo Molnar ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3)
10888a4216cSIngo Molnar {
10988a4216cSIngo Molnar 	struct trace_array *tr = ctx_trace;
11088a4216cSIngo Molnar 	struct trace_array_cpu *data;
11188a4216cSIngo Molnar 	unsigned long flags;
11288a4216cSIngo Molnar 	long disabled;
11388a4216cSIngo Molnar 	int cpu;
11488a4216cSIngo Molnar 
11588a4216cSIngo Molnar 	if (!tracer_enabled)
11688a4216cSIngo Molnar 		return;
11788a4216cSIngo Molnar 
11888a4216cSIngo Molnar 	local_irq_save(flags);
11988a4216cSIngo Molnar 	cpu = raw_smp_processor_id();
12088a4216cSIngo Molnar 	data = tr->data[cpu];
12188a4216cSIngo Molnar 	disabled = atomic_inc_return(&data->disabled);
12288a4216cSIngo Molnar 
12388a4216cSIngo Molnar 	if (likely(disabled == 1))
12488a4216cSIngo Molnar 		__trace_special(tr, data, arg1, arg2, arg3);
12588a4216cSIngo Molnar 
12688a4216cSIngo Molnar 	atomic_dec(&data->disabled);
12788a4216cSIngo Molnar 	local_irq_restore(flags);
12888a4216cSIngo Molnar }
12988a4216cSIngo Molnar 
130e309b41dSIngo Molnar static void sched_switch_reset(struct trace_array *tr)
13135e8e302SSteven Rostedt {
13235e8e302SSteven Rostedt 	int cpu;
13335e8e302SSteven Rostedt 
134750ed1a4SIngo Molnar 	tr->time_start = ftrace_now(tr->cpu);
13535e8e302SSteven Rostedt 
13635e8e302SSteven Rostedt 	for_each_online_cpu(cpu)
13735e8e302SSteven Rostedt 		tracing_reset(tr->data[cpu]);
13835e8e302SSteven Rostedt }
13935e8e302SSteven Rostedt 
140e309b41dSIngo Molnar static void start_sched_trace(struct trace_array *tr)
14135e8e302SSteven Rostedt {
14235e8e302SSteven Rostedt 	sched_switch_reset(tr);
14335e8e302SSteven Rostedt 	tracer_enabled = 1;
14435e8e302SSteven Rostedt }
14535e8e302SSteven Rostedt 
146e309b41dSIngo Molnar static void stop_sched_trace(struct trace_array *tr)
14735e8e302SSteven Rostedt {
14835e8e302SSteven Rostedt 	tracer_enabled = 0;
14935e8e302SSteven Rostedt }
15035e8e302SSteven Rostedt 
151e309b41dSIngo Molnar static void sched_switch_trace_init(struct trace_array *tr)
15235e8e302SSteven Rostedt {
15335e8e302SSteven Rostedt 	ctx_trace = tr;
15435e8e302SSteven Rostedt 
15535e8e302SSteven Rostedt 	if (tr->ctrl)
15635e8e302SSteven Rostedt 		start_sched_trace(tr);
15735e8e302SSteven Rostedt }
15835e8e302SSteven Rostedt 
159e309b41dSIngo Molnar static void sched_switch_trace_reset(struct trace_array *tr)
16035e8e302SSteven Rostedt {
16135e8e302SSteven Rostedt 	if (tr->ctrl)
16235e8e302SSteven Rostedt 		stop_sched_trace(tr);
16335e8e302SSteven Rostedt }
16435e8e302SSteven Rostedt 
16535e8e302SSteven Rostedt static void sched_switch_trace_ctrl_update(struct trace_array *tr)
16635e8e302SSteven Rostedt {
16735e8e302SSteven Rostedt 	/* When starting a new trace, reset the buffers */
16835e8e302SSteven Rostedt 	if (tr->ctrl)
16935e8e302SSteven Rostedt 		start_sched_trace(tr);
17035e8e302SSteven Rostedt 	else
17135e8e302SSteven Rostedt 		stop_sched_trace(tr);
17235e8e302SSteven Rostedt }
17335e8e302SSteven Rostedt 
17435e8e302SSteven Rostedt static struct tracer sched_switch_trace __read_mostly =
17535e8e302SSteven Rostedt {
17635e8e302SSteven Rostedt 	.name		= "sched_switch",
17735e8e302SSteven Rostedt 	.init		= sched_switch_trace_init,
17835e8e302SSteven Rostedt 	.reset		= sched_switch_trace_reset,
17935e8e302SSteven Rostedt 	.ctrl_update	= sched_switch_trace_ctrl_update,
18060a11774SSteven Rostedt #ifdef CONFIG_FTRACE_SELFTEST
18160a11774SSteven Rostedt 	.selftest    = trace_selftest_startup_sched_switch,
18260a11774SSteven Rostedt #endif
18335e8e302SSteven Rostedt };
18435e8e302SSteven Rostedt 
18535e8e302SSteven Rostedt __init static int init_sched_switch_trace(void)
18635e8e302SSteven Rostedt {
18735e8e302SSteven Rostedt 	return register_tracer(&sched_switch_trace);
18835e8e302SSteven Rostedt }
18935e8e302SSteven Rostedt device_initcall(init_sched_switch_trace);
190