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; 195b82a1b0SMathieu Desnoyers static atomic_t sched_ref; 2035e8e302SSteven Rostedt 21e309b41dSIngo Molnar static void 22b07c3f19SMathieu Desnoyers probe_sched_switch(struct rq *__rq, struct task_struct *prev, 235b82a1b0SMathieu Desnoyers struct task_struct *next) 2435e8e302SSteven Rostedt { 2535e8e302SSteven Rostedt struct trace_array_cpu *data; 2635e8e302SSteven Rostedt unsigned long flags; 2735e8e302SSteven Rostedt long disabled; 2835e8e302SSteven Rostedt int cpu; 2938697053SSteven Rostedt int pc; 3035e8e302SSteven Rostedt 31b07c3f19SMathieu Desnoyers if (!atomic_read(&sched_ref)) 32b07c3f19SMathieu Desnoyers return; 33b07c3f19SMathieu Desnoyers 3441bc8144SSteven Rostedt tracing_record_cmdline(prev); 3541bc8144SSteven Rostedt tracing_record_cmdline(next); 3641bc8144SSteven Rostedt 3735e8e302SSteven Rostedt if (!tracer_enabled) 3835e8e302SSteven Rostedt return; 3935e8e302SSteven Rostedt 4038697053SSteven Rostedt pc = preempt_count(); 4118cef379SSteven Rostedt local_irq_save(flags); 4235e8e302SSteven Rostedt cpu = raw_smp_processor_id(); 43b07c3f19SMathieu Desnoyers data = ctx_trace->data[cpu]; 4435e8e302SSteven Rostedt disabled = atomic_inc_return(&data->disabled); 4535e8e302SSteven Rostedt 464d9493c9SIngo Molnar if (likely(disabled == 1)) 4738697053SSteven Rostedt tracing_sched_switch_trace(ctx_trace, data, prev, next, flags, pc); 4835e8e302SSteven Rostedt 4935e8e302SSteven Rostedt atomic_dec(&data->disabled); 5018cef379SSteven Rostedt local_irq_restore(flags); 5135e8e302SSteven Rostedt } 5235e8e302SSteven Rostedt 535b82a1b0SMathieu Desnoyers static void 54b07c3f19SMathieu Desnoyers probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee) 555b82a1b0SMathieu Desnoyers { 5657422797SIngo Molnar struct trace_array_cpu *data; 5757422797SIngo Molnar unsigned long flags; 5857422797SIngo Molnar long disabled; 5938697053SSteven Rostedt int cpu, pc; 6057422797SIngo Molnar 61b07c3f19SMathieu Desnoyers if (!likely(tracer_enabled)) 6257422797SIngo Molnar return; 6357422797SIngo Molnar 6438697053SSteven Rostedt pc = preempt_count(); 65b07c3f19SMathieu Desnoyers tracing_record_cmdline(current); 66d9af56fbSIngo Molnar 6757422797SIngo Molnar local_irq_save(flags); 6857422797SIngo Molnar cpu = raw_smp_processor_id(); 69b07c3f19SMathieu Desnoyers data = ctx_trace->data[cpu]; 7057422797SIngo Molnar disabled = atomic_inc_return(&data->disabled); 7157422797SIngo Molnar 724d9493c9SIngo Molnar if (likely(disabled == 1)) 73b07c3f19SMathieu Desnoyers tracing_sched_wakeup_trace(ctx_trace, data, wakee, current, 7438697053SSteven Rostedt flags, pc); 7557422797SIngo Molnar 7657422797SIngo Molnar atomic_dec(&data->disabled); 7757422797SIngo Molnar local_irq_restore(flags); 7857422797SIngo Molnar } 7957422797SIngo Molnar 80e309b41dSIngo Molnar static void sched_switch_reset(struct trace_array *tr) 8135e8e302SSteven Rostedt { 8235e8e302SSteven Rostedt int cpu; 8335e8e302SSteven Rostedt 84750ed1a4SIngo Molnar tr->time_start = ftrace_now(tr->cpu); 8535e8e302SSteven Rostedt 8635e8e302SSteven Rostedt for_each_online_cpu(cpu) 873928a8a2SSteven Rostedt tracing_reset(tr, cpu); 8835e8e302SSteven Rostedt } 8935e8e302SSteven Rostedt 905b82a1b0SMathieu Desnoyers static int tracing_sched_register(void) 915b82a1b0SMathieu Desnoyers { 925b82a1b0SMathieu Desnoyers int ret; 935b82a1b0SMathieu Desnoyers 94b07c3f19SMathieu Desnoyers ret = register_trace_sched_wakeup(probe_sched_wakeup); 955b82a1b0SMathieu Desnoyers if (ret) { 96b07c3f19SMathieu Desnoyers pr_info("wakeup trace: Couldn't activate tracepoint" 975b82a1b0SMathieu Desnoyers " probe to kernel_sched_wakeup\n"); 985b82a1b0SMathieu Desnoyers return ret; 995b82a1b0SMathieu Desnoyers } 1005b82a1b0SMathieu Desnoyers 101b07c3f19SMathieu Desnoyers ret = register_trace_sched_wakeup_new(probe_sched_wakeup); 1025b82a1b0SMathieu Desnoyers if (ret) { 103b07c3f19SMathieu Desnoyers pr_info("wakeup trace: Couldn't activate tracepoint" 1045b82a1b0SMathieu Desnoyers " probe to kernel_sched_wakeup_new\n"); 1055b82a1b0SMathieu Desnoyers goto fail_deprobe; 1065b82a1b0SMathieu Desnoyers } 1075b82a1b0SMathieu Desnoyers 108b07c3f19SMathieu Desnoyers ret = register_trace_sched_switch(probe_sched_switch); 1095b82a1b0SMathieu Desnoyers if (ret) { 110b07c3f19SMathieu Desnoyers pr_info("sched trace: Couldn't activate tracepoint" 1115b82a1b0SMathieu Desnoyers " probe to kernel_sched_schedule\n"); 1125b82a1b0SMathieu Desnoyers goto fail_deprobe_wake_new; 1135b82a1b0SMathieu Desnoyers } 1145b82a1b0SMathieu Desnoyers 1155b82a1b0SMathieu Desnoyers return ret; 1165b82a1b0SMathieu Desnoyers fail_deprobe_wake_new: 117b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup_new(probe_sched_wakeup); 1185b82a1b0SMathieu Desnoyers fail_deprobe: 119b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup(probe_sched_wakeup); 1205b82a1b0SMathieu Desnoyers return ret; 1215b82a1b0SMathieu Desnoyers } 1225b82a1b0SMathieu Desnoyers 1235b82a1b0SMathieu Desnoyers static void tracing_sched_unregister(void) 1245b82a1b0SMathieu Desnoyers { 125b07c3f19SMathieu Desnoyers unregister_trace_sched_switch(probe_sched_switch); 126b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup_new(probe_sched_wakeup); 127b07c3f19SMathieu Desnoyers unregister_trace_sched_wakeup(probe_sched_wakeup); 1285b82a1b0SMathieu Desnoyers } 1295b82a1b0SMathieu Desnoyers 130f2252935SIngo Molnar static void tracing_start_sched_switch(void) 1315b82a1b0SMathieu Desnoyers { 1325b82a1b0SMathieu Desnoyers long ref; 1335b82a1b0SMathieu Desnoyers 1345b82a1b0SMathieu Desnoyers ref = atomic_inc_return(&sched_ref); 1355b82a1b0SMathieu Desnoyers if (ref == 1) 1365b82a1b0SMathieu Desnoyers tracing_sched_register(); 1375b82a1b0SMathieu Desnoyers } 1385b82a1b0SMathieu Desnoyers 139f2252935SIngo Molnar static void tracing_stop_sched_switch(void) 1405b82a1b0SMathieu Desnoyers { 1415b82a1b0SMathieu Desnoyers long ref; 1425b82a1b0SMathieu Desnoyers 1435b82a1b0SMathieu Desnoyers ref = atomic_dec_and_test(&sched_ref); 1445b82a1b0SMathieu Desnoyers if (ref) 1455b82a1b0SMathieu Desnoyers tracing_sched_unregister(); 1465b82a1b0SMathieu Desnoyers } 1475b82a1b0SMathieu Desnoyers 14841bc8144SSteven Rostedt void tracing_start_cmdline_record(void) 14941bc8144SSteven Rostedt { 15041bc8144SSteven Rostedt tracing_start_sched_switch(); 15141bc8144SSteven Rostedt } 15241bc8144SSteven Rostedt 15341bc8144SSteven Rostedt void tracing_stop_cmdline_record(void) 15441bc8144SSteven Rostedt { 15541bc8144SSteven Rostedt tracing_stop_sched_switch(); 15641bc8144SSteven Rostedt } 15741bc8144SSteven Rostedt 158e309b41dSIngo Molnar static void start_sched_trace(struct trace_array *tr) 15935e8e302SSteven Rostedt { 16035e8e302SSteven Rostedt sched_switch_reset(tr); 16141bc8144SSteven Rostedt tracing_start_cmdline_record(); 162007c05d4SSteven Rostedt tracer_enabled = 1; 16335e8e302SSteven Rostedt } 16435e8e302SSteven Rostedt 165e309b41dSIngo Molnar static void stop_sched_trace(struct trace_array *tr) 16635e8e302SSteven Rostedt { 16735e8e302SSteven Rostedt tracer_enabled = 0; 168007c05d4SSteven Rostedt tracing_stop_cmdline_record(); 16935e8e302SSteven Rostedt } 17035e8e302SSteven Rostedt 171e309b41dSIngo Molnar static void sched_switch_trace_init(struct trace_array *tr) 17235e8e302SSteven Rostedt { 17335e8e302SSteven Rostedt ctx_trace = tr; 17435e8e302SSteven Rostedt 17535e8e302SSteven Rostedt if (tr->ctrl) 17635e8e302SSteven Rostedt start_sched_trace(tr); 17735e8e302SSteven Rostedt } 17835e8e302SSteven Rostedt 179e309b41dSIngo Molnar static void sched_switch_trace_reset(struct trace_array *tr) 18035e8e302SSteven Rostedt { 18135e8e302SSteven Rostedt if (tr->ctrl) 18235e8e302SSteven Rostedt stop_sched_trace(tr); 18335e8e302SSteven Rostedt } 18435e8e302SSteven Rostedt 18535e8e302SSteven Rostedt static void sched_switch_trace_ctrl_update(struct trace_array *tr) 18635e8e302SSteven Rostedt { 18735e8e302SSteven Rostedt /* When starting a new trace, reset the buffers */ 18835e8e302SSteven Rostedt if (tr->ctrl) 18935e8e302SSteven Rostedt start_sched_trace(tr); 19035e8e302SSteven Rostedt else 19135e8e302SSteven Rostedt stop_sched_trace(tr); 19235e8e302SSteven Rostedt } 19335e8e302SSteven Rostedt 19435e8e302SSteven Rostedt static struct tracer sched_switch_trace __read_mostly = 19535e8e302SSteven Rostedt { 19635e8e302SSteven Rostedt .name = "sched_switch", 19735e8e302SSteven Rostedt .init = sched_switch_trace_init, 19835e8e302SSteven Rostedt .reset = sched_switch_trace_reset, 19935e8e302SSteven Rostedt .ctrl_update = sched_switch_trace_ctrl_update, 20060a11774SSteven Rostedt #ifdef CONFIG_FTRACE_SELFTEST 20160a11774SSteven Rostedt .selftest = trace_selftest_startup_sched_switch, 20260a11774SSteven Rostedt #endif 20335e8e302SSteven Rostedt }; 20435e8e302SSteven Rostedt 20535e8e302SSteven Rostedt __init static int init_sched_switch_trace(void) 20635e8e302SSteven Rostedt { 2075b82a1b0SMathieu Desnoyers int ret = 0; 2085b82a1b0SMathieu Desnoyers 2095b82a1b0SMathieu Desnoyers if (atomic_read(&sched_ref)) 2105b82a1b0SMathieu Desnoyers ret = tracing_sched_register(); 2115b82a1b0SMathieu Desnoyers if (ret) { 2125b82a1b0SMathieu Desnoyers pr_info("error registering scheduler trace\n"); 2135b82a1b0SMathieu Desnoyers return ret; 2145b82a1b0SMathieu Desnoyers } 21535e8e302SSteven Rostedt return register_tracer(&sched_switch_trace); 21635e8e302SSteven Rostedt } 21735e8e302SSteven Rostedt device_initcall(init_sched_switch_trace); 218