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 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 374e655519SIngo Molnar if (likely(disabled == 1)) { 3835e8e302SSteven Rostedt tracing_sched_switch_trace(tr, data, prev, next, flags); 394e655519SIngo Molnar ftrace_all_fair_tasks(__rq, tr, data); 404e655519SIngo Molnar } 4135e8e302SSteven Rostedt 4235e8e302SSteven Rostedt atomic_dec(&data->disabled); 4318cef379SSteven Rostedt local_irq_restore(flags); 4435e8e302SSteven Rostedt } 4535e8e302SSteven Rostedt 464e655519SIngo Molnar static void 474e655519SIngo Molnar wakeup_func(void *__rq, struct task_struct *wakee, struct task_struct *curr) 4857422797SIngo Molnar { 4957422797SIngo Molnar struct trace_array *tr = ctx_trace; 5057422797SIngo Molnar struct trace_array_cpu *data; 5157422797SIngo Molnar unsigned long flags; 5257422797SIngo Molnar long disabled; 5357422797SIngo Molnar int cpu; 5457422797SIngo Molnar 5557422797SIngo Molnar if (!tracer_enabled) 5657422797SIngo Molnar return; 5757422797SIngo Molnar 5857422797SIngo Molnar local_irq_save(flags); 5957422797SIngo Molnar cpu = raw_smp_processor_id(); 6057422797SIngo Molnar data = tr->data[cpu]; 6157422797SIngo Molnar disabled = atomic_inc_return(&data->disabled); 6257422797SIngo Molnar 634e655519SIngo Molnar if (likely(disabled == 1)) { 6457422797SIngo Molnar tracing_sched_wakeup_trace(tr, data, wakee, curr, flags); 654e655519SIngo Molnar ftrace_all_fair_tasks(__rq, tr, data); 664e655519SIngo Molnar } 6757422797SIngo Molnar 6857422797SIngo Molnar atomic_dec(&data->disabled); 6957422797SIngo Molnar local_irq_restore(flags); 7057422797SIngo Molnar } 7157422797SIngo Molnar 724e655519SIngo Molnar void 734e655519SIngo Molnar ftrace_ctx_switch(void *__rq, struct task_struct *prev, 744e655519SIngo Molnar struct task_struct *next) 7535e8e302SSteven Rostedt { 7635e8e302SSteven Rostedt tracing_record_cmdline(prev); 7735e8e302SSteven Rostedt 7835e8e302SSteven Rostedt /* 7935e8e302SSteven Rostedt * If tracer_switch_func only points to the local 8035e8e302SSteven Rostedt * switch func, it still needs the ptr passed to it. 8135e8e302SSteven Rostedt */ 824e655519SIngo Molnar ctx_switch_func(__rq, prev, next); 8335e8e302SSteven Rostedt 8435e8e302SSteven Rostedt /* 8535e8e302SSteven Rostedt * Chain to the wakeup tracer (this is a NOP if disabled): 8635e8e302SSteven Rostedt */ 8735e8e302SSteven Rostedt wakeup_sched_switch(prev, next); 8835e8e302SSteven Rostedt } 8935e8e302SSteven Rostedt 9057422797SIngo Molnar void 914e655519SIngo Molnar ftrace_wake_up_task(void *__rq, struct task_struct *wakee, 924e655519SIngo Molnar struct task_struct *curr) 9357422797SIngo Molnar { 9457422797SIngo Molnar tracing_record_cmdline(curr); 9557422797SIngo Molnar 964e655519SIngo Molnar wakeup_func(__rq, wakee, curr); 9757422797SIngo Molnar 9857422797SIngo Molnar /* 9957422797SIngo Molnar * Chain to the wakeup tracer (this is a NOP if disabled): 10057422797SIngo Molnar */ 10157422797SIngo Molnar wakeup_sched_wakeup(wakee, curr); 10257422797SIngo Molnar } 10357422797SIngo Molnar 104e309b41dSIngo Molnar static void sched_switch_reset(struct trace_array *tr) 10535e8e302SSteven Rostedt { 10635e8e302SSteven Rostedt int cpu; 10735e8e302SSteven Rostedt 108750ed1a4SIngo Molnar tr->time_start = ftrace_now(tr->cpu); 10935e8e302SSteven Rostedt 11035e8e302SSteven Rostedt for_each_online_cpu(cpu) 11135e8e302SSteven Rostedt tracing_reset(tr->data[cpu]); 11235e8e302SSteven Rostedt } 11335e8e302SSteven Rostedt 114e309b41dSIngo Molnar static void start_sched_trace(struct trace_array *tr) 11535e8e302SSteven Rostedt { 11635e8e302SSteven Rostedt sched_switch_reset(tr); 11735e8e302SSteven Rostedt tracer_enabled = 1; 11835e8e302SSteven Rostedt } 11935e8e302SSteven Rostedt 120e309b41dSIngo Molnar static void stop_sched_trace(struct trace_array *tr) 12135e8e302SSteven Rostedt { 12235e8e302SSteven Rostedt tracer_enabled = 0; 12335e8e302SSteven Rostedt } 12435e8e302SSteven Rostedt 125e309b41dSIngo Molnar static void sched_switch_trace_init(struct trace_array *tr) 12635e8e302SSteven Rostedt { 12735e8e302SSteven Rostedt ctx_trace = tr; 12835e8e302SSteven Rostedt 12935e8e302SSteven Rostedt if (tr->ctrl) 13035e8e302SSteven Rostedt start_sched_trace(tr); 13135e8e302SSteven Rostedt } 13235e8e302SSteven Rostedt 133e309b41dSIngo Molnar static void sched_switch_trace_reset(struct trace_array *tr) 13435e8e302SSteven Rostedt { 13535e8e302SSteven Rostedt if (tr->ctrl) 13635e8e302SSteven Rostedt stop_sched_trace(tr); 13735e8e302SSteven Rostedt } 13835e8e302SSteven Rostedt 13935e8e302SSteven Rostedt static void sched_switch_trace_ctrl_update(struct trace_array *tr) 14035e8e302SSteven Rostedt { 14135e8e302SSteven Rostedt /* When starting a new trace, reset the buffers */ 14235e8e302SSteven Rostedt if (tr->ctrl) 14335e8e302SSteven Rostedt start_sched_trace(tr); 14435e8e302SSteven Rostedt else 14535e8e302SSteven Rostedt stop_sched_trace(tr); 14635e8e302SSteven Rostedt } 14735e8e302SSteven Rostedt 14835e8e302SSteven Rostedt static struct tracer sched_switch_trace __read_mostly = 14935e8e302SSteven Rostedt { 15035e8e302SSteven Rostedt .name = "sched_switch", 15135e8e302SSteven Rostedt .init = sched_switch_trace_init, 15235e8e302SSteven Rostedt .reset = sched_switch_trace_reset, 15335e8e302SSteven Rostedt .ctrl_update = sched_switch_trace_ctrl_update, 15460a11774SSteven Rostedt #ifdef CONFIG_FTRACE_SELFTEST 15560a11774SSteven Rostedt .selftest = trace_selftest_startup_sched_switch, 15660a11774SSteven Rostedt #endif 15735e8e302SSteven Rostedt }; 15835e8e302SSteven Rostedt 15935e8e302SSteven Rostedt __init static int init_sched_switch_trace(void) 16035e8e302SSteven Rostedt { 16135e8e302SSteven Rostedt return register_tracer(&sched_switch_trace); 16235e8e302SSteven Rostedt } 16335e8e302SSteven Rostedt device_initcall(init_sched_switch_trace); 164