ftrace: make work with new ring buffer
[linux-2.6.git] / kernel / trace / trace_sched_switch.c
1 /*
2  * trace context switch
3  *
4  * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
5  *
6  */
7 #include <linux/module.h>
8 #include <linux/fs.h>
9 #include <linux/debugfs.h>
10 #include <linux/kallsyms.h>
11 #include <linux/uaccess.h>
12 #include <linux/ftrace.h>
13 #include <trace/sched.h>
14
15 #include "trace.h"
16
17 static struct trace_array       *ctx_trace;
18 static int __read_mostly        tracer_enabled;
19 static atomic_t                 sched_ref;
20
21 static void
22 probe_sched_switch(struct rq *__rq, struct task_struct *prev,
23                         struct task_struct *next)
24 {
25         struct trace_array_cpu *data;
26         unsigned long flags;
27         long disabled;
28         int cpu;
29
30         if (!atomic_read(&sched_ref))
31                 return;
32
33         tracing_record_cmdline(prev);
34         tracing_record_cmdline(next);
35
36         if (!tracer_enabled)
37                 return;
38
39         local_irq_save(flags);
40         cpu = raw_smp_processor_id();
41         data = ctx_trace->data[cpu];
42         disabled = atomic_inc_return(&data->disabled);
43
44         if (likely(disabled == 1))
45                 tracing_sched_switch_trace(ctx_trace, data, prev, next, flags);
46
47         atomic_dec(&data->disabled);
48         local_irq_restore(flags);
49 }
50
51 static void
52 probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee)
53 {
54         struct trace_array_cpu *data;
55         unsigned long flags;
56         long disabled;
57         int cpu;
58
59         if (!likely(tracer_enabled))
60                 return;
61
62         tracing_record_cmdline(current);
63
64         local_irq_save(flags);
65         cpu = raw_smp_processor_id();
66         data = ctx_trace->data[cpu];
67         disabled = atomic_inc_return(&data->disabled);
68
69         if (likely(disabled == 1))
70                 tracing_sched_wakeup_trace(ctx_trace, data, wakee, current,
71                         flags);
72
73         atomic_dec(&data->disabled);
74         local_irq_restore(flags);
75 }
76
77 static void sched_switch_reset(struct trace_array *tr)
78 {
79         int cpu;
80
81         tr->time_start = ftrace_now(tr->cpu);
82
83         for_each_online_cpu(cpu)
84                 tracing_reset(tr, cpu);
85 }
86
87 static int tracing_sched_register(void)
88 {
89         int ret;
90
91         ret = register_trace_sched_wakeup(probe_sched_wakeup);
92         if (ret) {
93                 pr_info("wakeup trace: Couldn't activate tracepoint"
94                         " probe to kernel_sched_wakeup\n");
95                 return ret;
96         }
97
98         ret = register_trace_sched_wakeup_new(probe_sched_wakeup);
99         if (ret) {
100                 pr_info("wakeup trace: Couldn't activate tracepoint"
101                         " probe to kernel_sched_wakeup_new\n");
102                 goto fail_deprobe;
103         }
104
105         ret = register_trace_sched_switch(probe_sched_switch);
106         if (ret) {
107                 pr_info("sched trace: Couldn't activate tracepoint"
108                         " probe to kernel_sched_schedule\n");
109                 goto fail_deprobe_wake_new;
110         }
111
112         return ret;
113 fail_deprobe_wake_new:
114         unregister_trace_sched_wakeup_new(probe_sched_wakeup);
115 fail_deprobe:
116         unregister_trace_sched_wakeup(probe_sched_wakeup);
117         return ret;
118 }
119
120 static void tracing_sched_unregister(void)
121 {
122         unregister_trace_sched_switch(probe_sched_switch);
123         unregister_trace_sched_wakeup_new(probe_sched_wakeup);
124         unregister_trace_sched_wakeup(probe_sched_wakeup);
125 }
126
127 static void tracing_start_sched_switch(void)
128 {
129         long ref;
130
131         ref = atomic_inc_return(&sched_ref);
132         if (ref == 1)
133                 tracing_sched_register();
134 }
135
136 static void tracing_stop_sched_switch(void)
137 {
138         long ref;
139
140         ref = atomic_dec_and_test(&sched_ref);
141         if (ref)
142                 tracing_sched_unregister();
143 }
144
145 void tracing_start_cmdline_record(void)
146 {
147         tracing_start_sched_switch();
148 }
149
150 void tracing_stop_cmdline_record(void)
151 {
152         tracing_stop_sched_switch();
153 }
154
155 static void start_sched_trace(struct trace_array *tr)
156 {
157         sched_switch_reset(tr);
158         tracing_start_cmdline_record();
159         tracer_enabled = 1;
160 }
161
162 static void stop_sched_trace(struct trace_array *tr)
163 {
164         tracer_enabled = 0;
165         tracing_stop_cmdline_record();
166 }
167
168 static void sched_switch_trace_init(struct trace_array *tr)
169 {
170         ctx_trace = tr;
171
172         if (tr->ctrl)
173                 start_sched_trace(tr);
174 }
175
176 static void sched_switch_trace_reset(struct trace_array *tr)
177 {
178         if (tr->ctrl)
179                 stop_sched_trace(tr);
180 }
181
182 static void sched_switch_trace_ctrl_update(struct trace_array *tr)
183 {
184         /* When starting a new trace, reset the buffers */
185         if (tr->ctrl)
186                 start_sched_trace(tr);
187         else
188                 stop_sched_trace(tr);
189 }
190
191 static struct tracer sched_switch_trace __read_mostly =
192 {
193         .name           = "sched_switch",
194         .init           = sched_switch_trace_init,
195         .reset          = sched_switch_trace_reset,
196         .ctrl_update    = sched_switch_trace_ctrl_update,
197 #ifdef CONFIG_FTRACE_SELFTEST
198         .selftest    = trace_selftest_startup_sched_switch,
199 #endif
200 };
201
202 __init static int init_sched_switch_trace(void)
203 {
204         int ret = 0;
205
206         if (atomic_read(&sched_ref))
207                 ret = tracing_sched_register();
208         if (ret) {
209                 pr_info("error registering scheduler trace\n");
210                 return ret;
211         }
212         return register_tracer(&sched_switch_trace);
213 }
214 device_initcall(init_sched_switch_trace);