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> 13b07c3f19SMathieu Desnoyers #include <trace/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 325fec6ddcSSteven Rostedt if (!sched_ref || sched_stopped) 33b07c3f19SMathieu Desnoyers return; 34b07c3f19SMathieu Desnoyers 3541bc8144SSteven Rostedt tracing_record_cmdline(prev); 3641bc8144SSteven Rostedt tracing_record_cmdline(next); 3741bc8144SSteven Rostedt 3835e8e302SSteven Rostedt if (!tracer_enabled) 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 59b07c3f19SMathieu Desnoyers if (!likely(tracer_enabled)) 6057422797SIngo Molnar return; 6157422797SIngo Molnar 6238697053SSteven Rostedt pc = preempt_count(); 63b07c3f19SMathieu Desnoyers tracing_record_cmdline(current); 64d9af56fbSIngo Molnar 6557422797SIngo Molnar local_irq_save(flags); 6657422797SIngo Molnar cpu = raw_smp_processor_id(); 67b07c3f19SMathieu Desnoyers data = ctx_trace->data[cpu]; 6857422797SIngo Molnar 693ea2e6d7SSteven Rostedt if (likely(!atomic_read(&data->disabled))) 707be42151SArnaldo Carvalho de Melo tracing_sched_wakeup_trace(ctx_trace, wakee, current, 7138697053SSteven Rostedt flags, pc); 7257422797SIngo Molnar 7357422797SIngo Molnar local_irq_restore(flags); 7457422797SIngo Molnar } 7557422797SIngo Molnar 765b82a1b0SMathieu Desnoyers static int tracing_sched_register(void) 775b82a1b0SMathieu Desnoyers { 785b82a1b0SMathieu Desnoyers int ret; 795b82a1b0SMathieu Desnoyers 80b07c3f19SMathieu Desnoyers ret = register_trace_sched_wakeup(probe_sched_wakeup); 815b82a1b0SMathieu Desnoyers if (ret) { 82b07c3f19SMathieu Desnoyers pr_info("wakeup trace: Couldn't activate tracepoint" 835b82a1b0SMathieu Desnoyers " probe to kernel_sched_wakeup\n"); 845b82a1b0SMathieu Desnoyers return ret; 855b82a1b0SMathieu Desnoyers } 865b82a1b0SMathieu Desnoyers 87b07c3f19SMathieu Desnoyers ret = register_trace_sched_wakeup_new(probe_sched_wakeup); 885b82a1b0SMathieu Desnoyers if (ret) { 89b07c3f19SMathieu Desnoyers pr_info("wakeup trace: Couldn't activate tracepoint" 905b82a1b0SMathieu Desnoyers " probe to kernel_sched_wakeup_new\n"); 915b82a1b0SMathieu Desnoyers goto fail_deprobe; 925b82a1b0SMathieu Desnoyers } 935b82a1b0SMathieu Desnoyers 94b07c3f19SMathieu Desnoyers ret = register_trace_sched_switch(probe_sched_switch); 955b82a1b0SMathieu Desnoyers if (ret) { 96b07c3f19SMathieu Desnoyers pr_info("sched trace: Couldn't activate tracepoint" 9773d8b8bcSWenji Huang " probe to kernel_sched_switch\n"); 985b82a1b0SMathieu Desnoyers goto fail_deprobe_wake_new; 995b82a1b0SMathieu Desnoyers } 1005b82a1b0SMathieu Desnoyers 1015b82a1b0SMathieu Desnoyers return ret; 1025b82a1b0SMathieu Desnoyers fail_deprobe_wake_new: 103b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup_new(probe_sched_wakeup); 1045b82a1b0SMathieu Desnoyers fail_deprobe: 105b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup(probe_sched_wakeup); 1065b82a1b0SMathieu Desnoyers return ret; 1075b82a1b0SMathieu Desnoyers } 1085b82a1b0SMathieu Desnoyers 1095b82a1b0SMathieu Desnoyers static void tracing_sched_unregister(void) 1105b82a1b0SMathieu Desnoyers { 111b07c3f19SMathieu Desnoyers unregister_trace_sched_switch(probe_sched_switch); 112b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup_new(probe_sched_wakeup); 113b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup(probe_sched_wakeup); 1145b82a1b0SMathieu Desnoyers } 1155b82a1b0SMathieu Desnoyers 116f2252935SIngo Molnar static void tracing_start_sched_switch(void) 1175b82a1b0SMathieu Desnoyers { 118efade6e7SFrederic Weisbecker mutex_lock(&sched_register_mutex); 119e168e051SSteven Rostedt if (!(sched_ref++)) 1205b82a1b0SMathieu Desnoyers tracing_sched_register(); 121efade6e7SFrederic Weisbecker mutex_unlock(&sched_register_mutex); 1225b82a1b0SMathieu Desnoyers } 1235b82a1b0SMathieu Desnoyers 124f2252935SIngo Molnar static void tracing_stop_sched_switch(void) 1255b82a1b0SMathieu Desnoyers { 126efade6e7SFrederic Weisbecker mutex_lock(&sched_register_mutex); 127e168e051SSteven Rostedt if (!(--sched_ref)) 1285b82a1b0SMathieu Desnoyers tracing_sched_unregister(); 129efade6e7SFrederic Weisbecker mutex_unlock(&sched_register_mutex); 1305b82a1b0SMathieu Desnoyers } 1315b82a1b0SMathieu Desnoyers 13241bc8144SSteven Rostedt void tracing_start_cmdline_record(void) 13341bc8144SSteven Rostedt { 13441bc8144SSteven Rostedt tracing_start_sched_switch(); 13541bc8144SSteven Rostedt } 13641bc8144SSteven Rostedt 13741bc8144SSteven Rostedt void tracing_stop_cmdline_record(void) 13841bc8144SSteven Rostedt { 13941bc8144SSteven Rostedt tracing_stop_sched_switch(); 14041bc8144SSteven Rostedt } 14141bc8144SSteven Rostedt 14275f5c47dSSteven Rostedt /** 143e168e051SSteven Rostedt * tracing_start_sched_switch_record - start tracing context switches 144e168e051SSteven Rostedt * 145e168e051SSteven Rostedt * Turns on context switch tracing for a tracer. 146e168e051SSteven Rostedt */ 147e168e051SSteven Rostedt void tracing_start_sched_switch_record(void) 148e168e051SSteven Rostedt { 149e168e051SSteven Rostedt if (unlikely(!ctx_trace)) { 150e168e051SSteven Rostedt WARN_ON(1); 151e168e051SSteven Rostedt return; 152e168e051SSteven Rostedt } 153e168e051SSteven Rostedt 154e168e051SSteven Rostedt tracing_start_sched_switch(); 155e168e051SSteven Rostedt 156e168e051SSteven Rostedt mutex_lock(&sched_register_mutex); 157e168e051SSteven Rostedt tracer_enabled++; 158e168e051SSteven Rostedt mutex_unlock(&sched_register_mutex); 159e168e051SSteven Rostedt } 160e168e051SSteven Rostedt 161e168e051SSteven Rostedt /** 162e168e051SSteven Rostedt * tracing_stop_sched_switch_record - start tracing context switches 163e168e051SSteven Rostedt * 164e168e051SSteven Rostedt * Turns off context switch tracing for a tracer. 165e168e051SSteven Rostedt */ 166e168e051SSteven Rostedt void tracing_stop_sched_switch_record(void) 167e168e051SSteven Rostedt { 168e168e051SSteven Rostedt mutex_lock(&sched_register_mutex); 169e168e051SSteven Rostedt tracer_enabled--; 170e168e051SSteven Rostedt WARN_ON(tracer_enabled < 0); 171e168e051SSteven Rostedt mutex_unlock(&sched_register_mutex); 172e168e051SSteven Rostedt 173e168e051SSteven Rostedt tracing_stop_sched_switch(); 174e168e051SSteven Rostedt } 175e168e051SSteven Rostedt 176e168e051SSteven Rostedt /** 177e168e051SSteven Rostedt * tracing_sched_switch_assign_trace - assign a trace array for ctx switch 17875f5c47dSSteven Rostedt * @tr: trace array pointer to assign 17975f5c47dSSteven Rostedt * 18075f5c47dSSteven Rostedt * Some tracers might want to record the context switches in their 18175f5c47dSSteven Rostedt * trace. This function lets those tracers assign the trace array 18275f5c47dSSteven Rostedt * to use. 18375f5c47dSSteven Rostedt */ 184e168e051SSteven Rostedt void tracing_sched_switch_assign_trace(struct trace_array *tr) 18575f5c47dSSteven Rostedt { 18675f5c47dSSteven Rostedt ctx_trace = tr; 18775f5c47dSSteven Rostedt } 18875f5c47dSSteven Rostedt 189e309b41dSIngo Molnar static void stop_sched_trace(struct trace_array *tr) 19035e8e302SSteven Rostedt { 191e168e051SSteven Rostedt tracing_stop_sched_switch_record(); 19235e8e302SSteven Rostedt } 19335e8e302SSteven Rostedt 1941c80025aSFrederic Weisbecker static int sched_switch_trace_init(struct trace_array *tr) 19535e8e302SSteven Rostedt { 19635e8e302SSteven Rostedt ctx_trace = tr; 1975fec6ddcSSteven Rostedt tracing_reset_online_cpus(tr); 198b6f11df2SArnaldo Carvalho de Melo tracing_start_sched_switch_record(); 1991c80025aSFrederic Weisbecker return 0; 20035e8e302SSteven Rostedt } 20135e8e302SSteven Rostedt 202e309b41dSIngo Molnar static void sched_switch_trace_reset(struct trace_array *tr) 20335e8e302SSteven Rostedt { 204c76f0694SSteven Rostedt if (sched_ref) 20535e8e302SSteven Rostedt stop_sched_trace(tr); 20635e8e302SSteven Rostedt } 20735e8e302SSteven Rostedt 2089036990dSSteven Rostedt static void sched_switch_trace_start(struct trace_array *tr) 2099036990dSSteven Rostedt { 2105fec6ddcSSteven Rostedt sched_stopped = 0; 2119036990dSSteven Rostedt } 2129036990dSSteven Rostedt 2139036990dSSteven Rostedt static void sched_switch_trace_stop(struct trace_array *tr) 2149036990dSSteven Rostedt { 2155fec6ddcSSteven Rostedt sched_stopped = 1; 2169036990dSSteven Rostedt } 2179036990dSSteven Rostedt 21875f5c47dSSteven Rostedt static struct tracer sched_switch_trace __read_mostly = 21935e8e302SSteven Rostedt { 22035e8e302SSteven Rostedt .name = "sched_switch", 22135e8e302SSteven Rostedt .init = sched_switch_trace_init, 22235e8e302SSteven Rostedt .reset = sched_switch_trace_reset, 2239036990dSSteven Rostedt .start = sched_switch_trace_start, 2249036990dSSteven Rostedt .stop = sched_switch_trace_stop, 2256eaaa5d5SFrederic Weisbecker .wait_pipe = poll_wait_pipe, 22660a11774SSteven Rostedt #ifdef CONFIG_FTRACE_SELFTEST 22760a11774SSteven Rostedt .selftest = trace_selftest_startup_sched_switch, 22860a11774SSteven Rostedt #endif 22935e8e302SSteven Rostedt }; 23035e8e302SSteven Rostedt 23135e8e302SSteven Rostedt __init static int init_sched_switch_trace(void) 23235e8e302SSteven Rostedt { 23335e8e302SSteven Rostedt return register_tracer(&sched_switch_trace); 23435e8e302SSteven Rostedt } 23535e8e302SSteven Rostedt device_initcall(init_sched_switch_trace); 236c71dd42dSIngo Molnar 237