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 106e309b41dSIngo Molnar static void sched_switch_reset(struct trace_array *tr) 10735e8e302SSteven Rostedt { 10835e8e302SSteven Rostedt int cpu; 10935e8e302SSteven Rostedt 110750ed1a4SIngo Molnar tr->time_start = ftrace_now(tr->cpu); 11135e8e302SSteven Rostedt 11235e8e302SSteven Rostedt for_each_online_cpu(cpu) 11335e8e302SSteven Rostedt tracing_reset(tr->data[cpu]); 11435e8e302SSteven Rostedt } 11535e8e302SSteven Rostedt 116e309b41dSIngo Molnar static void start_sched_trace(struct trace_array *tr) 11735e8e302SSteven Rostedt { 11835e8e302SSteven Rostedt sched_switch_reset(tr); 11935e8e302SSteven Rostedt tracer_enabled = 1; 12035e8e302SSteven Rostedt } 12135e8e302SSteven Rostedt 122e309b41dSIngo Molnar static void stop_sched_trace(struct trace_array *tr) 12335e8e302SSteven Rostedt { 12435e8e302SSteven Rostedt tracer_enabled = 0; 12535e8e302SSteven Rostedt } 12635e8e302SSteven Rostedt 127e309b41dSIngo Molnar static void sched_switch_trace_init(struct trace_array *tr) 12835e8e302SSteven Rostedt { 12935e8e302SSteven Rostedt ctx_trace = tr; 13035e8e302SSteven Rostedt 13135e8e302SSteven Rostedt if (tr->ctrl) 13235e8e302SSteven Rostedt start_sched_trace(tr); 13335e8e302SSteven Rostedt } 13435e8e302SSteven Rostedt 135e309b41dSIngo Molnar static void sched_switch_trace_reset(struct trace_array *tr) 13635e8e302SSteven Rostedt { 13735e8e302SSteven Rostedt if (tr->ctrl) 13835e8e302SSteven Rostedt stop_sched_trace(tr); 13935e8e302SSteven Rostedt } 14035e8e302SSteven Rostedt 14135e8e302SSteven Rostedt static void sched_switch_trace_ctrl_update(struct trace_array *tr) 14235e8e302SSteven Rostedt { 14335e8e302SSteven Rostedt /* When starting a new trace, reset the buffers */ 14435e8e302SSteven Rostedt if (tr->ctrl) 14535e8e302SSteven Rostedt start_sched_trace(tr); 14635e8e302SSteven Rostedt else 14735e8e302SSteven Rostedt stop_sched_trace(tr); 14835e8e302SSteven Rostedt } 14935e8e302SSteven Rostedt 15035e8e302SSteven Rostedt static struct tracer sched_switch_trace __read_mostly = 15135e8e302SSteven Rostedt { 15235e8e302SSteven Rostedt .name = "sched_switch", 15335e8e302SSteven Rostedt .init = sched_switch_trace_init, 15435e8e302SSteven Rostedt .reset = sched_switch_trace_reset, 15535e8e302SSteven Rostedt .ctrl_update = sched_switch_trace_ctrl_update, 15660a11774SSteven Rostedt #ifdef CONFIG_FTRACE_SELFTEST 15760a11774SSteven Rostedt .selftest = trace_selftest_startup_sched_switch, 15860a11774SSteven Rostedt #endif 15935e8e302SSteven Rostedt }; 16035e8e302SSteven Rostedt 16135e8e302SSteven Rostedt __init static int init_sched_switch_trace(void) 16235e8e302SSteven Rostedt { 16335e8e302SSteven Rostedt return register_tracer(&sched_switch_trace); 16435e8e302SSteven Rostedt } 16535e8e302SSteven Rostedt device_initcall(init_sched_switch_trace); 166