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