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 2135e8e302SSteven Rostedt ctx_switch_func(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 3218cef379SSteven Rostedt local_irq_save(flags); 3335e8e302SSteven Rostedt cpu = raw_smp_processor_id(); 3435e8e302SSteven Rostedt data = tr->data[cpu]; 3535e8e302SSteven Rostedt disabled = atomic_inc_return(&data->disabled); 3635e8e302SSteven Rostedt 3735e8e302SSteven Rostedt if (likely(disabled == 1)) 3835e8e302SSteven Rostedt tracing_sched_switch_trace(tr, data, prev, next, flags); 3935e8e302SSteven Rostedt 4035e8e302SSteven Rostedt atomic_dec(&data->disabled); 4118cef379SSteven Rostedt local_irq_restore(flags); 4235e8e302SSteven Rostedt } 4335e8e302SSteven Rostedt 4457422797SIngo Molnar static void wakeup_func(struct task_struct *wakee, struct task_struct *curr) 4557422797SIngo Molnar { 4657422797SIngo Molnar struct trace_array *tr = ctx_trace; 4757422797SIngo Molnar struct trace_array_cpu *data; 4857422797SIngo Molnar unsigned long flags; 4957422797SIngo Molnar long disabled; 5057422797SIngo Molnar int cpu; 5157422797SIngo Molnar 5257422797SIngo Molnar if (!tracer_enabled) 5357422797SIngo Molnar return; 5457422797SIngo Molnar 5557422797SIngo Molnar local_irq_save(flags); 5657422797SIngo Molnar cpu = raw_smp_processor_id(); 5757422797SIngo Molnar data = tr->data[cpu]; 5857422797SIngo Molnar disabled = atomic_inc_return(&data->disabled); 5957422797SIngo Molnar 6057422797SIngo Molnar if (likely(disabled == 1)) 6157422797SIngo Molnar tracing_sched_wakeup_trace(tr, data, wakee, curr, flags); 6257422797SIngo Molnar 6357422797SIngo Molnar atomic_dec(&data->disabled); 6457422797SIngo Molnar local_irq_restore(flags); 6557422797SIngo Molnar } 6657422797SIngo Molnar 6735e8e302SSteven Rostedt void ftrace_ctx_switch(struct task_struct *prev, struct task_struct *next) 6835e8e302SSteven Rostedt { 6935e8e302SSteven Rostedt tracing_record_cmdline(prev); 7035e8e302SSteven Rostedt 7135e8e302SSteven Rostedt /* 7235e8e302SSteven Rostedt * If tracer_switch_func only points to the local 7335e8e302SSteven Rostedt * switch func, it still needs the ptr passed to it. 7435e8e302SSteven Rostedt */ 7535e8e302SSteven Rostedt ctx_switch_func(prev, next); 7635e8e302SSteven Rostedt 7735e8e302SSteven Rostedt /* 7835e8e302SSteven Rostedt * Chain to the wakeup tracer (this is a NOP if disabled): 7935e8e302SSteven Rostedt */ 8035e8e302SSteven Rostedt wakeup_sched_switch(prev, next); 8135e8e302SSteven Rostedt } 8235e8e302SSteven Rostedt 8357422797SIngo Molnar void 8457422797SIngo Molnar ftrace_wake_up_task(struct task_struct *wakee, struct task_struct *curr) 8557422797SIngo Molnar { 8657422797SIngo Molnar tracing_record_cmdline(curr); 8757422797SIngo Molnar 8857422797SIngo Molnar wakeup_func(wakee, curr); 8957422797SIngo Molnar 9057422797SIngo Molnar /* 9157422797SIngo Molnar * Chain to the wakeup tracer (this is a NOP if disabled): 9257422797SIngo Molnar */ 9357422797SIngo Molnar wakeup_sched_wakeup(wakee, curr); 9457422797SIngo Molnar } 9557422797SIngo Molnar 96e309b41dSIngo Molnar static void sched_switch_reset(struct trace_array *tr) 9735e8e302SSteven Rostedt { 9835e8e302SSteven Rostedt int cpu; 9935e8e302SSteven Rostedt 100750ed1a4SIngo Molnar tr->time_start = ftrace_now(tr->cpu); 10135e8e302SSteven Rostedt 10235e8e302SSteven Rostedt for_each_online_cpu(cpu) 10335e8e302SSteven Rostedt tracing_reset(tr->data[cpu]); 10435e8e302SSteven Rostedt } 10535e8e302SSteven Rostedt 106e309b41dSIngo Molnar static void start_sched_trace(struct trace_array *tr) 10735e8e302SSteven Rostedt { 10835e8e302SSteven Rostedt sched_switch_reset(tr); 10935e8e302SSteven Rostedt tracer_enabled = 1; 11035e8e302SSteven Rostedt } 11135e8e302SSteven Rostedt 112e309b41dSIngo Molnar static void stop_sched_trace(struct trace_array *tr) 11335e8e302SSteven Rostedt { 11435e8e302SSteven Rostedt tracer_enabled = 0; 11535e8e302SSteven Rostedt } 11635e8e302SSteven Rostedt 117e309b41dSIngo Molnar static void sched_switch_trace_init(struct trace_array *tr) 11835e8e302SSteven Rostedt { 11935e8e302SSteven Rostedt ctx_trace = tr; 12035e8e302SSteven Rostedt 12135e8e302SSteven Rostedt if (tr->ctrl) 12235e8e302SSteven Rostedt start_sched_trace(tr); 12335e8e302SSteven Rostedt } 12435e8e302SSteven Rostedt 125e309b41dSIngo Molnar static void sched_switch_trace_reset(struct trace_array *tr) 12635e8e302SSteven Rostedt { 12735e8e302SSteven Rostedt if (tr->ctrl) 12835e8e302SSteven Rostedt stop_sched_trace(tr); 12935e8e302SSteven Rostedt } 13035e8e302SSteven Rostedt 13135e8e302SSteven Rostedt static void sched_switch_trace_ctrl_update(struct trace_array *tr) 13235e8e302SSteven Rostedt { 13335e8e302SSteven Rostedt /* When starting a new trace, reset the buffers */ 13435e8e302SSteven Rostedt if (tr->ctrl) 13535e8e302SSteven Rostedt start_sched_trace(tr); 13635e8e302SSteven Rostedt else 13735e8e302SSteven Rostedt stop_sched_trace(tr); 13835e8e302SSteven Rostedt } 13935e8e302SSteven Rostedt 14035e8e302SSteven Rostedt static struct tracer sched_switch_trace __read_mostly = 14135e8e302SSteven Rostedt { 14235e8e302SSteven Rostedt .name = "sched_switch", 14335e8e302SSteven Rostedt .init = sched_switch_trace_init, 14435e8e302SSteven Rostedt .reset = sched_switch_trace_reset, 14535e8e302SSteven Rostedt .ctrl_update = sched_switch_trace_ctrl_update, 14660a11774SSteven Rostedt #ifdef CONFIG_FTRACE_SELFTEST 14760a11774SSteven Rostedt .selftest = trace_selftest_startup_sched_switch, 14860a11774SSteven Rostedt #endif 14935e8e302SSteven Rostedt }; 15035e8e302SSteven Rostedt 15135e8e302SSteven Rostedt __init static int init_sched_switch_trace(void) 15235e8e302SSteven Rostedt { 15335e8e302SSteven Rostedt return register_tracer(&sched_switch_trace); 15435e8e302SSteven Rostedt } 15535e8e302SSteven Rostedt device_initcall(init_sched_switch_trace); 156