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/ftrace.h> 13ad8d75ffSSteven Rostedt #include <trace/events/sched.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; 19efade6e7SFrederic Weisbecker static int sched_ref; 20efade6e7SFrederic Weisbecker static DEFINE_MUTEX(sched_register_mutex); 215fec6ddcSSteven Rostedt static int sched_stopped; 2235e8e302SSteven Rostedt 23e309b41dSIngo Molnar static void 24b07c3f19SMathieu Desnoyers probe_sched_switch(struct rq *__rq, struct task_struct *prev, 255b82a1b0SMathieu Desnoyers struct task_struct *next) 2635e8e302SSteven Rostedt { 2735e8e302SSteven Rostedt struct trace_array_cpu *data; 2835e8e302SSteven Rostedt unsigned long flags; 2935e8e302SSteven Rostedt int cpu; 3038697053SSteven Rostedt int pc; 3135e8e302SSteven Rostedt 32dcef788eSZhaolei if (unlikely(!sched_ref)) 33b07c3f19SMathieu Desnoyers return; 34b07c3f19SMathieu Desnoyers 3541bc8144SSteven Rostedt tracing_record_cmdline(prev); 3641bc8144SSteven Rostedt tracing_record_cmdline(next); 3741bc8144SSteven Rostedt 38dcef788eSZhaolei if (!tracer_enabled || sched_stopped) 3935e8e302SSteven Rostedt return; 4035e8e302SSteven Rostedt 4138697053SSteven Rostedt pc = preempt_count(); 4218cef379SSteven Rostedt local_irq_save(flags); 4335e8e302SSteven Rostedt cpu = raw_smp_processor_id(); 44b07c3f19SMathieu Desnoyers data = ctx_trace->data[cpu]; 4535e8e302SSteven Rostedt 463ea2e6d7SSteven Rostedt if (likely(!atomic_read(&data->disabled))) 477be42151SArnaldo Carvalho de Melo tracing_sched_switch_trace(ctx_trace, prev, next, flags, pc); 4835e8e302SSteven Rostedt 4918cef379SSteven Rostedt local_irq_restore(flags); 5035e8e302SSteven Rostedt } 5135e8e302SSteven Rostedt 525b82a1b0SMathieu Desnoyers static void 53468a15bbSPeter Zijlstra probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee, int success) 545b82a1b0SMathieu Desnoyers { 5557422797SIngo Molnar struct trace_array_cpu *data; 5657422797SIngo Molnar unsigned long flags; 5738697053SSteven Rostedt int cpu, pc; 5857422797SIngo Molnar 59dcef788eSZhaolei if (unlikely(!sched_ref)) 60dcef788eSZhaolei return; 61dcef788eSZhaolei 62dcef788eSZhaolei tracing_record_cmdline(current); 63dcef788eSZhaolei 64dcef788eSZhaolei if (!tracer_enabled || sched_stopped) 6557422797SIngo Molnar return; 6657422797SIngo Molnar 6738697053SSteven Rostedt pc = preempt_count(); 6857422797SIngo Molnar local_irq_save(flags); 6957422797SIngo Molnar cpu = raw_smp_processor_id(); 70b07c3f19SMathieu Desnoyers data = ctx_trace->data[cpu]; 7157422797SIngo Molnar 723ea2e6d7SSteven Rostedt if (likely(!atomic_read(&data->disabled))) 737be42151SArnaldo Carvalho de Melo tracing_sched_wakeup_trace(ctx_trace, wakee, current, 7438697053SSteven Rostedt flags, pc); 7557422797SIngo Molnar 7657422797SIngo Molnar local_irq_restore(flags); 7757422797SIngo Molnar } 7857422797SIngo Molnar 795b82a1b0SMathieu Desnoyers static int tracing_sched_register(void) 805b82a1b0SMathieu Desnoyers { 815b82a1b0SMathieu Desnoyers int ret; 825b82a1b0SMathieu Desnoyers 83b07c3f19SMathieu Desnoyers ret = register_trace_sched_wakeup(probe_sched_wakeup); 845b82a1b0SMathieu Desnoyers if (ret) { 85b07c3f19SMathieu Desnoyers pr_info("wakeup trace: Couldn't activate tracepoint" 865b82a1b0SMathieu Desnoyers " probe to kernel_sched_wakeup\n"); 875b82a1b0SMathieu Desnoyers return ret; 885b82a1b0SMathieu Desnoyers } 895b82a1b0SMathieu Desnoyers 90b07c3f19SMathieu Desnoyers ret = register_trace_sched_wakeup_new(probe_sched_wakeup); 915b82a1b0SMathieu Desnoyers if (ret) { 92b07c3f19SMathieu Desnoyers pr_info("wakeup trace: Couldn't activate tracepoint" 935b82a1b0SMathieu Desnoyers " probe to kernel_sched_wakeup_new\n"); 945b82a1b0SMathieu Desnoyers goto fail_deprobe; 955b82a1b0SMathieu Desnoyers } 965b82a1b0SMathieu Desnoyers 97b07c3f19SMathieu Desnoyers ret = register_trace_sched_switch(probe_sched_switch); 985b82a1b0SMathieu Desnoyers if (ret) { 99b07c3f19SMathieu Desnoyers pr_info("sched trace: Couldn't activate tracepoint" 10073d8b8bcSWenji Huang " probe to kernel_sched_switch\n"); 1015b82a1b0SMathieu Desnoyers goto fail_deprobe_wake_new; 1025b82a1b0SMathieu Desnoyers } 1035b82a1b0SMathieu Desnoyers 1045b82a1b0SMathieu Desnoyers return ret; 1055b82a1b0SMathieu Desnoyers fail_deprobe_wake_new: 106b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup_new(probe_sched_wakeup); 1075b82a1b0SMathieu Desnoyers fail_deprobe: 108b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup(probe_sched_wakeup); 1095b82a1b0SMathieu Desnoyers return ret; 1105b82a1b0SMathieu Desnoyers } 1115b82a1b0SMathieu Desnoyers 1125b82a1b0SMathieu Desnoyers static void tracing_sched_unregister(void) 1135b82a1b0SMathieu Desnoyers { 114b07c3f19SMathieu Desnoyers unregister_trace_sched_switch(probe_sched_switch); 115b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup_new(probe_sched_wakeup); 116b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup(probe_sched_wakeup); 1175b82a1b0SMathieu Desnoyers } 1185b82a1b0SMathieu Desnoyers 119f2252935SIngo Molnar static void tracing_start_sched_switch(void) 1205b82a1b0SMathieu Desnoyers { 121efade6e7SFrederic Weisbecker mutex_lock(&sched_register_mutex); 122e168e051SSteven Rostedt if (!(sched_ref++)) 1235b82a1b0SMathieu Desnoyers tracing_sched_register(); 124efade6e7SFrederic Weisbecker mutex_unlock(&sched_register_mutex); 1255b82a1b0SMathieu Desnoyers } 1265b82a1b0SMathieu Desnoyers 127f2252935SIngo Molnar static void tracing_stop_sched_switch(void) 1285b82a1b0SMathieu Desnoyers { 129efade6e7SFrederic Weisbecker mutex_lock(&sched_register_mutex); 130e168e051SSteven Rostedt if (!(--sched_ref)) 1315b82a1b0SMathieu Desnoyers tracing_sched_unregister(); 132efade6e7SFrederic Weisbecker mutex_unlock(&sched_register_mutex); 1335b82a1b0SMathieu Desnoyers } 1345b82a1b0SMathieu Desnoyers 13541bc8144SSteven Rostedt void tracing_start_cmdline_record(void) 13641bc8144SSteven Rostedt { 13741bc8144SSteven Rostedt tracing_start_sched_switch(); 13841bc8144SSteven Rostedt } 13941bc8144SSteven Rostedt 14041bc8144SSteven Rostedt void tracing_stop_cmdline_record(void) 14141bc8144SSteven Rostedt { 14241bc8144SSteven Rostedt tracing_stop_sched_switch(); 14341bc8144SSteven Rostedt } 14441bc8144SSteven Rostedt 14575f5c47dSSteven Rostedt /** 146e168e051SSteven Rostedt * tracing_start_sched_switch_record - start tracing context switches 147e168e051SSteven Rostedt * 148e168e051SSteven Rostedt * Turns on context switch tracing for a tracer. 149e168e051SSteven Rostedt */ 150e168e051SSteven Rostedt void tracing_start_sched_switch_record(void) 151e168e051SSteven Rostedt { 152e168e051SSteven Rostedt if (unlikely(!ctx_trace)) { 153e168e051SSteven Rostedt WARN_ON(1); 154e168e051SSteven Rostedt return; 155e168e051SSteven Rostedt } 156e168e051SSteven Rostedt 157e168e051SSteven Rostedt tracing_start_sched_switch(); 158e168e051SSteven Rostedt 159e168e051SSteven Rostedt mutex_lock(&sched_register_mutex); 160e168e051SSteven Rostedt tracer_enabled++; 161e168e051SSteven Rostedt mutex_unlock(&sched_register_mutex); 162e168e051SSteven Rostedt } 163e168e051SSteven Rostedt 164e168e051SSteven Rostedt /** 165e168e051SSteven Rostedt * tracing_stop_sched_switch_record - start tracing context switches 166e168e051SSteven Rostedt * 167e168e051SSteven Rostedt * Turns off context switch tracing for a tracer. 168e168e051SSteven Rostedt */ 169e168e051SSteven Rostedt void tracing_stop_sched_switch_record(void) 170e168e051SSteven Rostedt { 171e168e051SSteven Rostedt mutex_lock(&sched_register_mutex); 172e168e051SSteven Rostedt tracer_enabled--; 173e168e051SSteven Rostedt WARN_ON(tracer_enabled < 0); 174e168e051SSteven Rostedt mutex_unlock(&sched_register_mutex); 175e168e051SSteven Rostedt 176e168e051SSteven Rostedt tracing_stop_sched_switch(); 177e168e051SSteven Rostedt } 178e168e051SSteven Rostedt 179e168e051SSteven Rostedt /** 180e168e051SSteven Rostedt * tracing_sched_switch_assign_trace - assign a trace array for ctx switch 18175f5c47dSSteven Rostedt * @tr: trace array pointer to assign 18275f5c47dSSteven Rostedt * 18375f5c47dSSteven Rostedt * Some tracers might want to record the context switches in their 18475f5c47dSSteven Rostedt * trace. This function lets those tracers assign the trace array 18575f5c47dSSteven Rostedt * to use. 18675f5c47dSSteven Rostedt */ 187e168e051SSteven Rostedt void tracing_sched_switch_assign_trace(struct trace_array *tr) 18875f5c47dSSteven Rostedt { 18975f5c47dSSteven Rostedt ctx_trace = tr; 19075f5c47dSSteven Rostedt } 19175f5c47dSSteven Rostedt 192e309b41dSIngo Molnar static void stop_sched_trace(struct trace_array *tr) 19335e8e302SSteven Rostedt { 194e168e051SSteven Rostedt tracing_stop_sched_switch_record(); 19535e8e302SSteven Rostedt } 19635e8e302SSteven Rostedt 1971c80025aSFrederic Weisbecker static int sched_switch_trace_init(struct trace_array *tr) 19835e8e302SSteven Rostedt { 19935e8e302SSteven Rostedt ctx_trace = tr; 2005fec6ddcSSteven Rostedt tracing_reset_online_cpus(tr); 201b6f11df2SArnaldo Carvalho de Melo tracing_start_sched_switch_record(); 2021c80025aSFrederic Weisbecker return 0; 20335e8e302SSteven Rostedt } 20435e8e302SSteven Rostedt 205e309b41dSIngo Molnar static void sched_switch_trace_reset(struct trace_array *tr) 20635e8e302SSteven Rostedt { 207c76f0694SSteven Rostedt if (sched_ref) 20835e8e302SSteven Rostedt stop_sched_trace(tr); 20935e8e302SSteven Rostedt } 21035e8e302SSteven Rostedt 2119036990dSSteven Rostedt static void sched_switch_trace_start(struct trace_array *tr) 2129036990dSSteven Rostedt { 2135fec6ddcSSteven Rostedt sched_stopped = 0; 2149036990dSSteven Rostedt } 2159036990dSSteven Rostedt 2169036990dSSteven Rostedt static void sched_switch_trace_stop(struct trace_array *tr) 2179036990dSSteven Rostedt { 2185fec6ddcSSteven Rostedt sched_stopped = 1; 2199036990dSSteven Rostedt } 2209036990dSSteven Rostedt 22175f5c47dSSteven Rostedt static struct tracer sched_switch_trace __read_mostly = 22235e8e302SSteven Rostedt { 22335e8e302SSteven Rostedt .name = "sched_switch", 22435e8e302SSteven Rostedt .init = sched_switch_trace_init, 22535e8e302SSteven Rostedt .reset = sched_switch_trace_reset, 2269036990dSSteven Rostedt .start = sched_switch_trace_start, 2279036990dSSteven Rostedt .stop = sched_switch_trace_stop, 2286eaaa5d5SFrederic Weisbecker .wait_pipe = poll_wait_pipe, 22960a11774SSteven Rostedt #ifdef CONFIG_FTRACE_SELFTEST 23060a11774SSteven Rostedt .selftest = trace_selftest_startup_sched_switch, 23160a11774SSteven Rostedt #endif 23235e8e302SSteven Rostedt }; 23335e8e302SSteven Rostedt 23435e8e302SSteven Rostedt __init static int init_sched_switch_trace(void) 23535e8e302SSteven Rostedt { 23635e8e302SSteven Rostedt return register_tracer(&sched_switch_trace); 23735e8e302SSteven Rostedt } 23835e8e302SSteven Rostedt device_initcall(init_sched_switch_trace); 239c71dd42dSIngo Molnar 240