4 * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
7 #include <linux/module.h>
9 #include <linux/debugfs.h>
10 #include <linux/kallsyms.h>
11 #include <linux/uaccess.h>
12 #include <linux/ftrace.h>
13 #include <trace/events/sched.h>
17 static struct trace_array *ctx_trace;
18 static int __read_mostly tracer_enabled;
20 static DEFINE_MUTEX(sched_register_mutex);
21 static int sched_stopped;
25 tracing_sched_switch_trace(struct trace_array *tr,
26 struct task_struct *prev,
27 struct task_struct *next,
28 unsigned long flags, int pc)
30 struct ftrace_event_call *call = &event_context_switch;
31 struct ring_buffer_event *event;
32 struct ctx_switch_entry *entry;
34 event = trace_buffer_lock_reserve(tr, TRACE_CTX,
35 sizeof(*entry), flags, pc);
38 entry = ring_buffer_event_data(event);
39 entry->prev_pid = prev->pid;
40 entry->prev_prio = prev->prio;
41 entry->prev_state = prev->state;
42 entry->next_pid = next->pid;
43 entry->next_prio = next->prio;
44 entry->next_state = next->state;
45 entry->next_cpu = task_cpu(next);
47 if (!filter_check_discard(call, entry, tr->buffer, event))
48 trace_buffer_unlock_commit(tr, event, flags, pc);
52 probe_sched_switch(struct rq *__rq, struct task_struct *prev,
53 struct task_struct *next)
55 struct trace_array_cpu *data;
60 if (unlikely(!sched_ref))
63 tracing_record_cmdline(prev);
64 tracing_record_cmdline(next);
66 if (!tracer_enabled || sched_stopped)
70 local_irq_save(flags);
71 cpu = raw_smp_processor_id();
72 data = ctx_trace->data[cpu];
74 if (likely(!atomic_read(&data->disabled)))
75 tracing_sched_switch_trace(ctx_trace, prev, next, flags, pc);
77 local_irq_restore(flags);
81 tracing_sched_wakeup_trace(struct trace_array *tr,
82 struct task_struct *wakee,
83 struct task_struct *curr,
84 unsigned long flags, int pc)
86 struct ftrace_event_call *call = &event_wakeup;
87 struct ring_buffer_event *event;
88 struct ctx_switch_entry *entry;
90 event = trace_buffer_lock_reserve(tr, TRACE_WAKE,
91 sizeof(*entry), flags, pc);
94 entry = ring_buffer_event_data(event);
95 entry->prev_pid = curr->pid;
96 entry->prev_prio = curr->prio;
97 entry->prev_state = curr->state;
98 entry->next_pid = wakee->pid;
99 entry->next_prio = wakee->prio;
100 entry->next_state = wakee->state;
101 entry->next_cpu = task_cpu(wakee);
103 if (!filter_check_discard(call, entry, tr->buffer, event))
104 ring_buffer_unlock_commit(tr->buffer, event);
105 ftrace_trace_stack(tr, flags, 6, pc);
106 ftrace_trace_userstack(tr, flags, pc);
110 probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee, int success)
112 struct trace_array_cpu *data;
116 if (unlikely(!sched_ref))
119 tracing_record_cmdline(current);
121 if (!tracer_enabled || sched_stopped)
124 pc = preempt_count();
125 local_irq_save(flags);
126 cpu = raw_smp_processor_id();
127 data = ctx_trace->data[cpu];
129 if (likely(!atomic_read(&data->disabled)))
130 tracing_sched_wakeup_trace(ctx_trace, wakee, current,
133 local_irq_restore(flags);
136 static int tracing_sched_register(void)
140 ret = register_trace_sched_wakeup(probe_sched_wakeup);
142 pr_info("wakeup trace: Couldn't activate tracepoint"
143 " probe to kernel_sched_wakeup\n");
147 ret = register_trace_sched_wakeup_new(probe_sched_wakeup);
149 pr_info("wakeup trace: Couldn't activate tracepoint"
150 " probe to kernel_sched_wakeup_new\n");
154 ret = register_trace_sched_switch(probe_sched_switch);
156 pr_info("sched trace: Couldn't activate tracepoint"
157 " probe to kernel_sched_switch\n");
158 goto fail_deprobe_wake_new;
162 fail_deprobe_wake_new:
163 unregister_trace_sched_wakeup_new(probe_sched_wakeup);
165 unregister_trace_sched_wakeup(probe_sched_wakeup);
169 static void tracing_sched_unregister(void)
171 unregister_trace_sched_switch(probe_sched_switch);
172 unregister_trace_sched_wakeup_new(probe_sched_wakeup);
173 unregister_trace_sched_wakeup(probe_sched_wakeup);
176 static void tracing_start_sched_switch(void)
178 mutex_lock(&sched_register_mutex);
180 tracing_sched_register();
181 mutex_unlock(&sched_register_mutex);
184 static void tracing_stop_sched_switch(void)
186 mutex_lock(&sched_register_mutex);
188 tracing_sched_unregister();
189 mutex_unlock(&sched_register_mutex);
192 void tracing_start_cmdline_record(void)
194 tracing_start_sched_switch();
197 void tracing_stop_cmdline_record(void)
199 tracing_stop_sched_switch();
203 * tracing_start_sched_switch_record - start tracing context switches
205 * Turns on context switch tracing for a tracer.
207 void tracing_start_sched_switch_record(void)
209 if (unlikely(!ctx_trace)) {
214 tracing_start_sched_switch();
216 mutex_lock(&sched_register_mutex);
218 mutex_unlock(&sched_register_mutex);
222 * tracing_stop_sched_switch_record - start tracing context switches
224 * Turns off context switch tracing for a tracer.
226 void tracing_stop_sched_switch_record(void)
228 mutex_lock(&sched_register_mutex);
230 WARN_ON(tracer_enabled < 0);
231 mutex_unlock(&sched_register_mutex);
233 tracing_stop_sched_switch();
237 * tracing_sched_switch_assign_trace - assign a trace array for ctx switch
238 * @tr: trace array pointer to assign
240 * Some tracers might want to record the context switches in their
241 * trace. This function lets those tracers assign the trace array
244 void tracing_sched_switch_assign_trace(struct trace_array *tr)
249 static void stop_sched_trace(struct trace_array *tr)
251 tracing_stop_sched_switch_record();
254 static int sched_switch_trace_init(struct trace_array *tr)
257 tracing_reset_online_cpus(tr);
258 tracing_start_sched_switch_record();
262 static void sched_switch_trace_reset(struct trace_array *tr)
265 stop_sched_trace(tr);
268 static void sched_switch_trace_start(struct trace_array *tr)
273 static void sched_switch_trace_stop(struct trace_array *tr)
278 static struct tracer sched_switch_trace __read_mostly =
280 .name = "sched_switch",
281 .init = sched_switch_trace_init,
282 .reset = sched_switch_trace_reset,
283 .start = sched_switch_trace_start,
284 .stop = sched_switch_trace_stop,
285 .wait_pipe = poll_wait_pipe,
286 #ifdef CONFIG_FTRACE_SELFTEST
287 .selftest = trace_selftest_startup_sched_switch,
291 __init static int init_sched_switch_trace(void)
293 return register_tracer(&sched_switch_trace);
295 device_initcall(init_sched_switch_trace);