Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * trace task wakeup timings
4 : : *
5 : : * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
6 : : * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
7 : : *
8 : : * Based on code from the latency_tracer, that is:
9 : : *
10 : : * Copyright (C) 2004-2006 Ingo Molnar
11 : : * Copyright (C) 2004 Nadia Yvette Chambers
12 : : */
13 : : #include <linux/module.h>
14 : : #include <linux/kallsyms.h>
15 : : #include <linux/uaccess.h>
16 : : #include <linux/ftrace.h>
17 : : #include <linux/sched/rt.h>
18 : : #include <linux/sched/deadline.h>
19 : : #include <trace/events/sched.h>
20 : : #include "trace.h"
21 : :
22 : : static struct trace_array *wakeup_trace;
23 : : static int __read_mostly tracer_enabled;
24 : :
25 : : static struct task_struct *wakeup_task;
26 : : static int wakeup_cpu;
27 : : static int wakeup_current_cpu;
28 : : static unsigned wakeup_prio = -1;
29 : : static int wakeup_rt;
30 : : static int wakeup_dl;
31 : : static int tracing_dl = 0;
32 : :
33 : : static arch_spinlock_t wakeup_lock =
34 : : (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
35 : :
36 : : static void wakeup_reset(struct trace_array *tr);
37 : : static void __wakeup_reset(struct trace_array *tr);
38 : : static int start_func_tracer(struct trace_array *tr, int graph);
39 : : static void stop_func_tracer(struct trace_array *tr, int graph);
40 : :
41 : : static int save_flags;
42 : :
43 : : #ifdef CONFIG_FUNCTION_GRAPH_TRACER
44 : : # define is_graph(tr) ((tr)->trace_flags & TRACE_ITER_DISPLAY_GRAPH)
45 : : #else
46 : : # define is_graph(tr) false
47 : : #endif
48 : :
49 : : #ifdef CONFIG_FUNCTION_TRACER
50 : :
51 : : static bool function_enabled;
52 : :
53 : : /*
54 : : * Prologue for the wakeup function tracers.
55 : : *
56 : : * Returns 1 if it is OK to continue, and preemption
57 : : * is disabled and data->disabled is incremented.
58 : : * 0 if the trace is to be ignored, and preemption
59 : : * is not disabled and data->disabled is
60 : : * kept the same.
61 : : *
62 : : * Note, this function is also used outside this ifdef but
63 : : * inside the #ifdef of the function graph tracer below.
64 : : * This is OK, since the function graph tracer is
65 : : * dependent on the function tracer.
66 : : */
67 : : static int
68 : 0 : func_prolog_preempt_disable(struct trace_array *tr,
69 : : struct trace_array_cpu **data,
70 : : int *pc)
71 : : {
72 : : long disabled;
73 : : int cpu;
74 : :
75 : 0 : if (likely(!wakeup_task))
76 : : return 0;
77 : :
78 : 0 : *pc = preempt_count();
79 : 0 : preempt_disable_notrace();
80 : :
81 : 0 : cpu = raw_smp_processor_id();
82 : 0 : if (cpu != wakeup_current_cpu)
83 : : goto out_enable;
84 : :
85 : 0 : *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
86 : 0 : disabled = atomic_inc_return(&(*data)->disabled);
87 : 0 : if (unlikely(disabled != 1))
88 : : goto out;
89 : :
90 : : return 1;
91 : :
92 : : out:
93 : 0 : atomic_dec(&(*data)->disabled);
94 : :
95 : : out_enable:
96 : 0 : preempt_enable_notrace();
97 : 0 : return 0;
98 : : }
99 : :
100 : : #ifdef CONFIG_FUNCTION_GRAPH_TRACER
101 : :
102 : 0 : static int wakeup_display_graph(struct trace_array *tr, int set)
103 : : {
104 : 0 : if (!(is_graph(tr) ^ set))
105 : : return 0;
106 : :
107 : 0 : stop_func_tracer(tr, !set);
108 : :
109 : 0 : wakeup_reset(wakeup_trace);
110 : 0 : tr->max_latency = 0;
111 : :
112 : 0 : return start_func_tracer(tr, set);
113 : : }
114 : :
115 : 0 : static int wakeup_graph_entry(struct ftrace_graph_ent *trace)
116 : : {
117 : 0 : struct trace_array *tr = wakeup_trace;
118 : : struct trace_array_cpu *data;
119 : : unsigned long flags;
120 : : int pc, ret = 0;
121 : :
122 : 0 : if (ftrace_graph_ignore_func(trace))
123 : : return 0;
124 : : /*
125 : : * Do not trace a function if it's filtered by set_graph_notrace.
126 : : * Make the index of ret stack negative to indicate that it should
127 : : * ignore further functions. But it needs its own ret stack entry
128 : : * to recover the original index in order to continue tracing after
129 : : * returning from the function.
130 : : */
131 : 0 : if (ftrace_graph_notrace_addr(trace->func))
132 : : return 1;
133 : :
134 : 0 : if (!func_prolog_preempt_disable(tr, &data, &pc))
135 : : return 0;
136 : :
137 : : local_save_flags(flags);
138 : 0 : ret = __trace_graph_entry(tr, trace, flags, pc);
139 : 0 : atomic_dec(&data->disabled);
140 : 0 : preempt_enable_notrace();
141 : :
142 : 0 : return ret;
143 : : }
144 : :
145 : 0 : static void wakeup_graph_return(struct ftrace_graph_ret *trace)
146 : : {
147 : 0 : struct trace_array *tr = wakeup_trace;
148 : : struct trace_array_cpu *data;
149 : : unsigned long flags;
150 : : int pc;
151 : :
152 : 0 : ftrace_graph_addr_finish(trace);
153 : :
154 : 0 : if (!func_prolog_preempt_disable(tr, &data, &pc))
155 : : return;
156 : :
157 : : local_save_flags(flags);
158 : 0 : __trace_graph_return(tr, trace, flags, pc);
159 : 0 : atomic_dec(&data->disabled);
160 : :
161 : 0 : preempt_enable_notrace();
162 : 0 : return;
163 : : }
164 : :
165 : : static struct fgraph_ops fgraph_wakeup_ops = {
166 : : .entryfunc = &wakeup_graph_entry,
167 : : .retfunc = &wakeup_graph_return,
168 : : };
169 : :
170 : 0 : static void wakeup_trace_open(struct trace_iterator *iter)
171 : : {
172 : 0 : if (is_graph(iter->tr))
173 : 0 : graph_trace_open(iter);
174 : 0 : }
175 : :
176 : 0 : static void wakeup_trace_close(struct trace_iterator *iter)
177 : : {
178 : 0 : if (iter->private)
179 : 0 : graph_trace_close(iter);
180 : 0 : }
181 : :
182 : : #define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_PROC | \
183 : : TRACE_GRAPH_PRINT_CPU | \
184 : : TRACE_GRAPH_PRINT_REL_TIME | \
185 : : TRACE_GRAPH_PRINT_DURATION | \
186 : : TRACE_GRAPH_PRINT_OVERHEAD | \
187 : : TRACE_GRAPH_PRINT_IRQS)
188 : :
189 : 0 : static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
190 : : {
191 : : /*
192 : : * In graph mode call the graph tracer output function,
193 : : * otherwise go with the TRACE_FN event handler
194 : : */
195 : 0 : if (is_graph(iter->tr))
196 : 0 : return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
197 : :
198 : : return TRACE_TYPE_UNHANDLED;
199 : : }
200 : :
201 : 0 : static void wakeup_print_header(struct seq_file *s)
202 : : {
203 : 0 : if (is_graph(wakeup_trace))
204 : 0 : print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
205 : : else
206 : 0 : trace_default_header(s);
207 : 0 : }
208 : : #endif /* else CONFIG_FUNCTION_GRAPH_TRACER */
209 : :
210 : : /*
211 : : * wakeup uses its own tracer function to keep the overhead down:
212 : : */
213 : : static void
214 : 0 : wakeup_tracer_call(unsigned long ip, unsigned long parent_ip,
215 : : struct ftrace_ops *op, struct pt_regs *pt_regs)
216 : : {
217 : 0 : struct trace_array *tr = wakeup_trace;
218 : : struct trace_array_cpu *data;
219 : : unsigned long flags;
220 : : int pc;
221 : :
222 : 0 : if (!func_prolog_preempt_disable(tr, &data, &pc))
223 : 0 : return;
224 : :
225 : 0 : local_irq_save(flags);
226 : 0 : trace_function(tr, ip, parent_ip, flags, pc);
227 : 0 : local_irq_restore(flags);
228 : :
229 : 0 : atomic_dec(&data->disabled);
230 : 0 : preempt_enable_notrace();
231 : : }
232 : :
233 : 0 : static int register_wakeup_function(struct trace_array *tr, int graph, int set)
234 : : {
235 : : int ret;
236 : :
237 : : /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
238 : 0 : if (function_enabled || (!set && !(tr->trace_flags & TRACE_ITER_FUNCTION)))
239 : : return 0;
240 : :
241 : 0 : if (graph)
242 : 0 : ret = register_ftrace_graph(&fgraph_wakeup_ops);
243 : : else
244 : 0 : ret = register_ftrace_function(tr->ops);
245 : :
246 : 0 : if (!ret)
247 : 0 : function_enabled = true;
248 : :
249 : 0 : return ret;
250 : : }
251 : :
252 : 0 : static void unregister_wakeup_function(struct trace_array *tr, int graph)
253 : : {
254 : 0 : if (!function_enabled)
255 : 0 : return;
256 : :
257 : 0 : if (graph)
258 : 0 : unregister_ftrace_graph(&fgraph_wakeup_ops);
259 : : else
260 : 0 : unregister_ftrace_function(tr->ops);
261 : :
262 : 0 : function_enabled = false;
263 : : }
264 : :
265 : 0 : static int wakeup_function_set(struct trace_array *tr, u32 mask, int set)
266 : : {
267 : 0 : if (!(mask & TRACE_ITER_FUNCTION))
268 : : return 0;
269 : :
270 : 0 : if (set)
271 : 0 : register_wakeup_function(tr, is_graph(tr), 1);
272 : : else
273 : 0 : unregister_wakeup_function(tr, is_graph(tr));
274 : : return 1;
275 : : }
276 : : #else /* CONFIG_FUNCTION_TRACER */
277 : : static int register_wakeup_function(struct trace_array *tr, int graph, int set)
278 : : {
279 : : return 0;
280 : : }
281 : : static void unregister_wakeup_function(struct trace_array *tr, int graph) { }
282 : : static int wakeup_function_set(struct trace_array *tr, u32 mask, int set)
283 : : {
284 : : return 0;
285 : : }
286 : : #endif /* else CONFIG_FUNCTION_TRACER */
287 : :
288 : : #ifndef CONFIG_FUNCTION_GRAPH_TRACER
289 : : static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
290 : : {
291 : : return TRACE_TYPE_UNHANDLED;
292 : : }
293 : :
294 : : static void wakeup_trace_open(struct trace_iterator *iter) { }
295 : : static void wakeup_trace_close(struct trace_iterator *iter) { }
296 : :
297 : : static void wakeup_print_header(struct seq_file *s)
298 : : {
299 : : trace_default_header(s);
300 : : }
301 : : #endif /* !CONFIG_FUNCTION_GRAPH_TRACER */
302 : :
303 : : static void
304 : 0 : __trace_function(struct trace_array *tr,
305 : : unsigned long ip, unsigned long parent_ip,
306 : : unsigned long flags, int pc)
307 : : {
308 : 0 : if (is_graph(tr))
309 : 0 : trace_graph_function(tr, ip, parent_ip, flags, pc);
310 : : else
311 : 0 : trace_function(tr, ip, parent_ip, flags, pc);
312 : 0 : }
313 : :
314 : 0 : static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set)
315 : : {
316 : 0 : struct tracer *tracer = tr->current_trace;
317 : :
318 : 0 : if (wakeup_function_set(tr, mask, set))
319 : : return 0;
320 : :
321 : : #ifdef CONFIG_FUNCTION_GRAPH_TRACER
322 : 0 : if (mask & TRACE_ITER_DISPLAY_GRAPH)
323 : 0 : return wakeup_display_graph(tr, set);
324 : : #endif
325 : :
326 : 0 : return trace_keep_overwrite(tracer, mask, set);
327 : : }
328 : :
329 : 0 : static int start_func_tracer(struct trace_array *tr, int graph)
330 : : {
331 : : int ret;
332 : :
333 : 0 : ret = register_wakeup_function(tr, graph, 0);
334 : :
335 : 0 : if (!ret && tracing_is_enabled())
336 : 0 : tracer_enabled = 1;
337 : : else
338 : 0 : tracer_enabled = 0;
339 : :
340 : 0 : return ret;
341 : : }
342 : :
343 : : static void stop_func_tracer(struct trace_array *tr, int graph)
344 : : {
345 : 0 : tracer_enabled = 0;
346 : :
347 : 0 : unregister_wakeup_function(tr, graph);
348 : : }
349 : :
350 : : /*
351 : : * Should this new latency be reported/recorded?
352 : : */
353 : : static bool report_latency(struct trace_array *tr, u64 delta)
354 : : {
355 : 0 : if (tracing_thresh) {
356 : 0 : if (delta < tracing_thresh)
357 : : return false;
358 : : } else {
359 : 0 : if (delta <= tr->max_latency)
360 : : return false;
361 : : }
362 : : return true;
363 : : }
364 : :
365 : : static void
366 : 0 : probe_wakeup_migrate_task(void *ignore, struct task_struct *task, int cpu)
367 : : {
368 : 0 : if (task != wakeup_task)
369 : 0 : return;
370 : :
371 : 0 : wakeup_current_cpu = cpu;
372 : : }
373 : :
374 : : static void
375 : 0 : tracing_sched_switch_trace(struct trace_array *tr,
376 : : struct task_struct *prev,
377 : : struct task_struct *next,
378 : : unsigned long flags, int pc)
379 : : {
380 : : struct trace_event_call *call = &event_context_switch;
381 : 0 : struct ring_buffer *buffer = tr->trace_buffer.buffer;
382 : : struct ring_buffer_event *event;
383 : : struct ctx_switch_entry *entry;
384 : :
385 : 0 : event = trace_buffer_lock_reserve(buffer, TRACE_CTX,
386 : : sizeof(*entry), flags, pc);
387 : 0 : if (!event)
388 : 0 : return;
389 : 0 : entry = ring_buffer_event_data(event);
390 : 0 : entry->prev_pid = prev->pid;
391 : 0 : entry->prev_prio = prev->prio;
392 : 0 : entry->prev_state = task_state_index(prev);
393 : 0 : entry->next_pid = next->pid;
394 : 0 : entry->next_prio = next->prio;
395 : 0 : entry->next_state = task_state_index(next);
396 : 0 : entry->next_cpu = task_cpu(next);
397 : :
398 : 0 : if (!call_filter_check_discard(call, entry, buffer, event))
399 : : trace_buffer_unlock_commit(tr, buffer, event, flags, pc);
400 : : }
401 : :
402 : : static void
403 : 0 : tracing_sched_wakeup_trace(struct trace_array *tr,
404 : : struct task_struct *wakee,
405 : : struct task_struct *curr,
406 : : unsigned long flags, int pc)
407 : : {
408 : : struct trace_event_call *call = &event_wakeup;
409 : : struct ring_buffer_event *event;
410 : : struct ctx_switch_entry *entry;
411 : 0 : struct ring_buffer *buffer = tr->trace_buffer.buffer;
412 : :
413 : 0 : event = trace_buffer_lock_reserve(buffer, TRACE_WAKE,
414 : : sizeof(*entry), flags, pc);
415 : 0 : if (!event)
416 : 0 : return;
417 : 0 : entry = ring_buffer_event_data(event);
418 : 0 : entry->prev_pid = curr->pid;
419 : 0 : entry->prev_prio = curr->prio;
420 : 0 : entry->prev_state = task_state_index(curr);
421 : 0 : entry->next_pid = wakee->pid;
422 : 0 : entry->next_prio = wakee->prio;
423 : 0 : entry->next_state = task_state_index(wakee);
424 : 0 : entry->next_cpu = task_cpu(wakee);
425 : :
426 : 0 : if (!call_filter_check_discard(call, entry, buffer, event))
427 : : trace_buffer_unlock_commit(tr, buffer, event, flags, pc);
428 : : }
429 : :
430 : : static void notrace
431 : 0 : probe_wakeup_sched_switch(void *ignore, bool preempt,
432 : : struct task_struct *prev, struct task_struct *next)
433 : : {
434 : : struct trace_array_cpu *data;
435 : : u64 T0, T1, delta;
436 : : unsigned long flags;
437 : : long disabled;
438 : : int cpu;
439 : : int pc;
440 : :
441 : 0 : tracing_record_cmdline(prev);
442 : :
443 : 0 : if (unlikely(!tracer_enabled))
444 : : return;
445 : :
446 : : /*
447 : : * When we start a new trace, we set wakeup_task to NULL
448 : : * and then set tracer_enabled = 1. We want to make sure
449 : : * that another CPU does not see the tracer_enabled = 1
450 : : * and the wakeup_task with an older task, that might
451 : : * actually be the same as next.
452 : : */
453 : 0 : smp_rmb();
454 : :
455 : 0 : if (next != wakeup_task)
456 : : return;
457 : :
458 : : pc = preempt_count();
459 : :
460 : : /* disable local data, not wakeup_cpu data */
461 : 0 : cpu = raw_smp_processor_id();
462 : 0 : disabled = atomic_inc_return(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
463 : 0 : if (likely(disabled != 1))
464 : : goto out;
465 : :
466 : 0 : local_irq_save(flags);
467 : 0 : arch_spin_lock(&wakeup_lock);
468 : :
469 : : /* We could race with grabbing wakeup_lock */
470 : 0 : if (unlikely(!tracer_enabled || next != wakeup_task))
471 : : goto out_unlock;
472 : :
473 : : /* The task we are waiting for is waking up */
474 : 0 : data = per_cpu_ptr(wakeup_trace->trace_buffer.data, wakeup_cpu);
475 : :
476 : 0 : __trace_function(wakeup_trace, CALLER_ADDR0, CALLER_ADDR1, flags, pc);
477 : 0 : tracing_sched_switch_trace(wakeup_trace, prev, next, flags, pc);
478 : 0 : __trace_stack(wakeup_trace, flags, 0, pc);
479 : :
480 : 0 : T0 = data->preempt_timestamp;
481 : 0 : T1 = ftrace_now(cpu);
482 : 0 : delta = T1-T0;
483 : :
484 : 0 : if (!report_latency(wakeup_trace, delta))
485 : : goto out_unlock;
486 : :
487 : 0 : if (likely(!is_tracing_stopped())) {
488 : 0 : wakeup_trace->max_latency = delta;
489 : 0 : update_max_tr(wakeup_trace, wakeup_task, wakeup_cpu, NULL);
490 : : }
491 : :
492 : : out_unlock:
493 : 0 : __wakeup_reset(wakeup_trace);
494 : : arch_spin_unlock(&wakeup_lock);
495 : 0 : local_irq_restore(flags);
496 : : out:
497 : 0 : atomic_dec(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
498 : : }
499 : :
500 : 0 : static void __wakeup_reset(struct trace_array *tr)
501 : : {
502 : 0 : wakeup_cpu = -1;
503 : 0 : wakeup_prio = -1;
504 : 0 : tracing_dl = 0;
505 : :
506 : 0 : if (wakeup_task)
507 : 0 : put_task_struct(wakeup_task);
508 : :
509 : 0 : wakeup_task = NULL;
510 : 0 : }
511 : :
512 : 0 : static void wakeup_reset(struct trace_array *tr)
513 : : {
514 : : unsigned long flags;
515 : :
516 : 0 : tracing_reset_online_cpus(&tr->trace_buffer);
517 : :
518 : 0 : local_irq_save(flags);
519 : 0 : arch_spin_lock(&wakeup_lock);
520 : 0 : __wakeup_reset(tr);
521 : : arch_spin_unlock(&wakeup_lock);
522 : 0 : local_irq_restore(flags);
523 : 0 : }
524 : :
525 : : static void
526 : 0 : probe_wakeup(void *ignore, struct task_struct *p)
527 : : {
528 : : struct trace_array_cpu *data;
529 : 0 : int cpu = smp_processor_id();
530 : : unsigned long flags;
531 : : long disabled;
532 : : int pc;
533 : :
534 : 0 : if (likely(!tracer_enabled))
535 : : return;
536 : :
537 : 0 : tracing_record_cmdline(p);
538 : 0 : tracing_record_cmdline(current);
539 : :
540 : : /*
541 : : * Semantic is like this:
542 : : * - wakeup tracer handles all tasks in the system, independently
543 : : * from their scheduling class;
544 : : * - wakeup_rt tracer handles tasks belonging to sched_dl and
545 : : * sched_rt class;
546 : : * - wakeup_dl handles tasks belonging to sched_dl class only.
547 : : */
548 : 0 : if (tracing_dl || (wakeup_dl && !dl_task(p)) ||
549 : 0 : (wakeup_rt && !dl_task(p) && !rt_task(p)) ||
550 : 0 : (!dl_task(p) && (p->prio >= wakeup_prio || p->prio >= current->prio)))
551 : : return;
552 : :
553 : : pc = preempt_count();
554 : 0 : disabled = atomic_inc_return(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
555 : 0 : if (unlikely(disabled != 1))
556 : : goto out;
557 : :
558 : : /* interrupts should be off from try_to_wake_up */
559 : 0 : arch_spin_lock(&wakeup_lock);
560 : :
561 : : /* check for races. */
562 : 0 : if (!tracer_enabled || tracing_dl ||
563 : 0 : (!dl_task(p) && p->prio >= wakeup_prio))
564 : : goto out_locked;
565 : :
566 : : /* reset the trace */
567 : 0 : __wakeup_reset(wakeup_trace);
568 : :
569 : 0 : wakeup_cpu = task_cpu(p);
570 : 0 : wakeup_current_cpu = wakeup_cpu;
571 : 0 : wakeup_prio = p->prio;
572 : :
573 : : /*
574 : : * Once you start tracing a -deadline task, don't bother tracing
575 : : * another task until the first one wakes up.
576 : : */
577 : 0 : if (dl_task(p))
578 : 0 : tracing_dl = 1;
579 : : else
580 : 0 : tracing_dl = 0;
581 : :
582 : 0 : wakeup_task = get_task_struct(p);
583 : :
584 : : local_save_flags(flags);
585 : :
586 : 0 : data = per_cpu_ptr(wakeup_trace->trace_buffer.data, wakeup_cpu);
587 : 0 : data->preempt_timestamp = ftrace_now(cpu);
588 : 0 : tracing_sched_wakeup_trace(wakeup_trace, p, current, flags, pc);
589 : 0 : __trace_stack(wakeup_trace, flags, 0, pc);
590 : :
591 : : /*
592 : : * We must be careful in using CALLER_ADDR2. But since wake_up
593 : : * is not called by an assembly function (where as schedule is)
594 : : * it should be safe to use it here.
595 : : */
596 : 0 : __trace_function(wakeup_trace, CALLER_ADDR1, CALLER_ADDR2, flags, pc);
597 : :
598 : : out_locked:
599 : : arch_spin_unlock(&wakeup_lock);
600 : : out:
601 : 0 : atomic_dec(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
602 : : }
603 : :
604 : 0 : static void start_wakeup_tracer(struct trace_array *tr)
605 : : {
606 : : int ret;
607 : :
608 : : ret = register_trace_sched_wakeup(probe_wakeup, NULL);
609 : 0 : if (ret) {
610 : 0 : pr_info("wakeup trace: Couldn't activate tracepoint"
611 : : " probe to kernel_sched_wakeup\n");
612 : 0 : return;
613 : : }
614 : :
615 : : ret = register_trace_sched_wakeup_new(probe_wakeup, NULL);
616 : 0 : if (ret) {
617 : 0 : pr_info("wakeup trace: Couldn't activate tracepoint"
618 : : " probe to kernel_sched_wakeup_new\n");
619 : 0 : goto fail_deprobe;
620 : : }
621 : :
622 : : ret = register_trace_sched_switch(probe_wakeup_sched_switch, NULL);
623 : 0 : if (ret) {
624 : 0 : pr_info("sched trace: Couldn't activate tracepoint"
625 : : " probe to kernel_sched_switch\n");
626 : 0 : goto fail_deprobe_wake_new;
627 : : }
628 : :
629 : : ret = register_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL);
630 : 0 : if (ret) {
631 : 0 : pr_info("wakeup trace: Couldn't activate tracepoint"
632 : : " probe to kernel_sched_migrate_task\n");
633 : : goto fail_deprobe_sched_switch;
634 : : }
635 : :
636 : 0 : wakeup_reset(tr);
637 : :
638 : : /*
639 : : * Don't let the tracer_enabled = 1 show up before
640 : : * the wakeup_task is reset. This may be overkill since
641 : : * wakeup_reset does a spin_unlock after setting the
642 : : * wakeup_task to NULL, but I want to be safe.
643 : : * This is a slow path anyway.
644 : : */
645 : 0 : smp_wmb();
646 : :
647 : 0 : if (start_func_tracer(tr, is_graph(tr)))
648 : 0 : printk(KERN_ERR "failed to start wakeup tracer\n");
649 : :
650 : : return;
651 : : fail_deprobe_sched_switch:
652 : : unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL);
653 : : fail_deprobe_wake_new:
654 : : unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
655 : : fail_deprobe:
656 : : unregister_trace_sched_wakeup(probe_wakeup, NULL);
657 : : }
658 : :
659 : 0 : static void stop_wakeup_tracer(struct trace_array *tr)
660 : : {
661 : 0 : tracer_enabled = 0;
662 : 0 : stop_func_tracer(tr, is_graph(tr));
663 : : unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL);
664 : : unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
665 : : unregister_trace_sched_wakeup(probe_wakeup, NULL);
666 : : unregister_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL);
667 : 0 : }
668 : :
669 : : static bool wakeup_busy;
670 : :
671 : 0 : static int __wakeup_tracer_init(struct trace_array *tr)
672 : : {
673 : 0 : save_flags = tr->trace_flags;
674 : :
675 : : /* non overwrite screws up the latency tracers */
676 : 0 : set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
677 : 0 : set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
678 : :
679 : 0 : tr->max_latency = 0;
680 : 0 : wakeup_trace = tr;
681 : 0 : ftrace_init_array_ops(tr, wakeup_tracer_call);
682 : 0 : start_wakeup_tracer(tr);
683 : :
684 : 0 : wakeup_busy = true;
685 : 0 : return 0;
686 : : }
687 : :
688 : 0 : static int wakeup_tracer_init(struct trace_array *tr)
689 : : {
690 : 0 : if (wakeup_busy)
691 : : return -EBUSY;
692 : :
693 : 0 : wakeup_dl = 0;
694 : 0 : wakeup_rt = 0;
695 : 0 : return __wakeup_tracer_init(tr);
696 : : }
697 : :
698 : 0 : static int wakeup_rt_tracer_init(struct trace_array *tr)
699 : : {
700 : 0 : if (wakeup_busy)
701 : : return -EBUSY;
702 : :
703 : 0 : wakeup_dl = 0;
704 : 0 : wakeup_rt = 1;
705 : 0 : return __wakeup_tracer_init(tr);
706 : : }
707 : :
708 : 0 : static int wakeup_dl_tracer_init(struct trace_array *tr)
709 : : {
710 : 0 : if (wakeup_busy)
711 : : return -EBUSY;
712 : :
713 : 0 : wakeup_dl = 1;
714 : 0 : wakeup_rt = 0;
715 : 0 : return __wakeup_tracer_init(tr);
716 : : }
717 : :
718 : 0 : static void wakeup_tracer_reset(struct trace_array *tr)
719 : : {
720 : 0 : int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
721 : 0 : int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
722 : :
723 : 0 : stop_wakeup_tracer(tr);
724 : : /* make sure we put back any tasks we are tracing */
725 : 0 : wakeup_reset(tr);
726 : :
727 : 0 : set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
728 : 0 : set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
729 : 0 : ftrace_reset_array_ops(tr);
730 : 0 : wakeup_busy = false;
731 : 0 : }
732 : :
733 : 0 : static void wakeup_tracer_start(struct trace_array *tr)
734 : : {
735 : 0 : wakeup_reset(tr);
736 : 0 : tracer_enabled = 1;
737 : 0 : }
738 : :
739 : 0 : static void wakeup_tracer_stop(struct trace_array *tr)
740 : : {
741 : 0 : tracer_enabled = 0;
742 : 0 : }
743 : :
744 : : static struct tracer wakeup_tracer __read_mostly =
745 : : {
746 : : .name = "wakeup",
747 : : .init = wakeup_tracer_init,
748 : : .reset = wakeup_tracer_reset,
749 : : .start = wakeup_tracer_start,
750 : : .stop = wakeup_tracer_stop,
751 : : .print_max = true,
752 : : .print_header = wakeup_print_header,
753 : : .print_line = wakeup_print_line,
754 : : .flag_changed = wakeup_flag_changed,
755 : : #ifdef CONFIG_FTRACE_SELFTEST
756 : : .selftest = trace_selftest_startup_wakeup,
757 : : #endif
758 : : .open = wakeup_trace_open,
759 : : .close = wakeup_trace_close,
760 : : .allow_instances = true,
761 : : .use_max_tr = true,
762 : : };
763 : :
764 : : static struct tracer wakeup_rt_tracer __read_mostly =
765 : : {
766 : : .name = "wakeup_rt",
767 : : .init = wakeup_rt_tracer_init,
768 : : .reset = wakeup_tracer_reset,
769 : : .start = wakeup_tracer_start,
770 : : .stop = wakeup_tracer_stop,
771 : : .print_max = true,
772 : : .print_header = wakeup_print_header,
773 : : .print_line = wakeup_print_line,
774 : : .flag_changed = wakeup_flag_changed,
775 : : #ifdef CONFIG_FTRACE_SELFTEST
776 : : .selftest = trace_selftest_startup_wakeup,
777 : : #endif
778 : : .open = wakeup_trace_open,
779 : : .close = wakeup_trace_close,
780 : : .allow_instances = true,
781 : : .use_max_tr = true,
782 : : };
783 : :
784 : : static struct tracer wakeup_dl_tracer __read_mostly =
785 : : {
786 : : .name = "wakeup_dl",
787 : : .init = wakeup_dl_tracer_init,
788 : : .reset = wakeup_tracer_reset,
789 : : .start = wakeup_tracer_start,
790 : : .stop = wakeup_tracer_stop,
791 : : .print_max = true,
792 : : .print_header = wakeup_print_header,
793 : : .print_line = wakeup_print_line,
794 : : .flag_changed = wakeup_flag_changed,
795 : : #ifdef CONFIG_FTRACE_SELFTEST
796 : : .selftest = trace_selftest_startup_wakeup,
797 : : #endif
798 : : .open = wakeup_trace_open,
799 : : .close = wakeup_trace_close,
800 : : .allow_instances = true,
801 : : .use_max_tr = true,
802 : : };
803 : :
804 : 3 : __init static int init_wakeup_tracer(void)
805 : : {
806 : : int ret;
807 : :
808 : 3 : ret = register_tracer(&wakeup_tracer);
809 : 3 : if (ret)
810 : : return ret;
811 : :
812 : 3 : ret = register_tracer(&wakeup_rt_tracer);
813 : 3 : if (ret)
814 : : return ret;
815 : :
816 : 3 : ret = register_tracer(&wakeup_dl_tracer);
817 : 3 : if (ret)
818 : 0 : return ret;
819 : :
820 : : return 0;
821 : : }
822 : : core_initcall(init_wakeup_tracer);
|