aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_sched_wakeup.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_sched_wakeup.c')
-rw-r--r--kernel/trace/trace_sched_wakeup.c220
1 files changed, 84 insertions, 136 deletions
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index e303ccb62cdf..43586b689e31 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -15,7 +15,7 @@
15#include <linux/kallsyms.h> 15#include <linux/kallsyms.h>
16#include <linux/uaccess.h> 16#include <linux/uaccess.h>
17#include <linux/ftrace.h> 17#include <linux/ftrace.h>
18#include <linux/marker.h> 18#include <trace/sched.h>
19 19
20#include "trace.h" 20#include "trace.h"
21 21
@@ -31,7 +31,7 @@ static raw_spinlock_t wakeup_lock =
31 31
32static void __wakeup_reset(struct trace_array *tr); 32static void __wakeup_reset(struct trace_array *tr);
33 33
34#ifdef CONFIG_FTRACE 34#ifdef CONFIG_FUNCTION_TRACER
35/* 35/*
36 * irqsoff uses its own tracer function to keep the overhead down: 36 * irqsoff uses its own tracer function to keep the overhead down:
37 */ 37 */
@@ -44,12 +44,13 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
44 long disabled; 44 long disabled;
45 int resched; 45 int resched;
46 int cpu; 46 int cpu;
47 int pc;
47 48
48 if (likely(!wakeup_task)) 49 if (likely(!wakeup_task))
49 return; 50 return;
50 51
51 resched = need_resched(); 52 pc = preempt_count();
52 preempt_disable_notrace(); 53 resched = ftrace_preempt_disable();
53 54
54 cpu = raw_smp_processor_id(); 55 cpu = raw_smp_processor_id();
55 data = tr->data[cpu]; 56 data = tr->data[cpu];
@@ -70,7 +71,7 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
70 if (task_cpu(wakeup_task) != cpu) 71 if (task_cpu(wakeup_task) != cpu)
71 goto unlock; 72 goto unlock;
72 73
73 trace_function(tr, data, ip, parent_ip, flags); 74 trace_function(tr, data, ip, parent_ip, flags, pc);
74 75
75 unlock: 76 unlock:
76 __raw_spin_unlock(&wakeup_lock); 77 __raw_spin_unlock(&wakeup_lock);
@@ -79,22 +80,14 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
79 out: 80 out:
80 atomic_dec(&data->disabled); 81 atomic_dec(&data->disabled);
81 82
82 /* 83 ftrace_preempt_enable(resched);
83 * To prevent recursion from the scheduler, if the
84 * resched flag was set before we entered, then
85 * don't reschedule.
86 */
87 if (resched)
88 preempt_enable_no_resched_notrace();
89 else
90 preempt_enable_notrace();
91} 84}
92 85
93static struct ftrace_ops trace_ops __read_mostly = 86static struct ftrace_ops trace_ops __read_mostly =
94{ 87{
95 .func = wakeup_tracer_call, 88 .func = wakeup_tracer_call,
96}; 89};
97#endif /* CONFIG_FTRACE */ 90#endif /* CONFIG_FUNCTION_TRACER */
98 91
99/* 92/*
100 * Should this new latency be reported/recorded? 93 * Should this new latency be reported/recorded?
@@ -112,17 +105,18 @@ static int report_latency(cycle_t delta)
112} 105}
113 106
114static void notrace 107static void notrace
115wakeup_sched_switch(void *private, void *rq, struct task_struct *prev, 108probe_wakeup_sched_switch(struct rq *rq, struct task_struct *prev,
116 struct task_struct *next) 109 struct task_struct *next)
117{ 110{
118 unsigned long latency = 0, t0 = 0, t1 = 0; 111 unsigned long latency = 0, t0 = 0, t1 = 0;
119 struct trace_array **ptr = private;
120 struct trace_array *tr = *ptr;
121 struct trace_array_cpu *data; 112 struct trace_array_cpu *data;
122 cycle_t T0, T1, delta; 113 cycle_t T0, T1, delta;
123 unsigned long flags; 114 unsigned long flags;
124 long disabled; 115 long disabled;
125 int cpu; 116 int cpu;
117 int pc;
118
119 tracing_record_cmdline(prev);
126 120
127 if (unlikely(!tracer_enabled)) 121 if (unlikely(!tracer_enabled))
128 return; 122 return;
@@ -139,12 +133,14 @@ wakeup_sched_switch(void *private, void *rq, struct task_struct *prev,
139 if (next != wakeup_task) 133 if (next != wakeup_task)
140 return; 134 return;
141 135
136 pc = preempt_count();
137
142 /* The task we are waiting for is waking up */ 138 /* The task we are waiting for is waking up */
143 data = tr->data[wakeup_cpu]; 139 data = wakeup_trace->data[wakeup_cpu];
144 140
145 /* disable local data, not wakeup_cpu data */ 141 /* disable local data, not wakeup_cpu data */
146 cpu = raw_smp_processor_id(); 142 cpu = raw_smp_processor_id();
147 disabled = atomic_inc_return(&tr->data[cpu]->disabled); 143 disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
148 if (likely(disabled != 1)) 144 if (likely(disabled != 1))
149 goto out; 145 goto out;
150 146
@@ -155,7 +151,7 @@ wakeup_sched_switch(void *private, void *rq, struct task_struct *prev,
155 if (unlikely(!tracer_enabled || next != wakeup_task)) 151 if (unlikely(!tracer_enabled || next != wakeup_task))
156 goto out_unlock; 152 goto out_unlock;
157 153
158 trace_function(tr, data, CALLER_ADDR1, CALLER_ADDR2, flags); 154 trace_function(wakeup_trace, data, CALLER_ADDR1, CALLER_ADDR2, flags, pc);
159 155
160 /* 156 /*
161 * usecs conversion is slow so we try to delay the conversion 157 * usecs conversion is slow so we try to delay the conversion
@@ -174,39 +170,14 @@ wakeup_sched_switch(void *private, void *rq, struct task_struct *prev,
174 t0 = nsecs_to_usecs(T0); 170 t0 = nsecs_to_usecs(T0);
175 t1 = nsecs_to_usecs(T1); 171 t1 = nsecs_to_usecs(T1);
176 172
177 update_max_tr(tr, wakeup_task, wakeup_cpu); 173 update_max_tr(wakeup_trace, wakeup_task, wakeup_cpu);
178 174
179out_unlock: 175out_unlock:
180 __wakeup_reset(tr); 176 __wakeup_reset(wakeup_trace);
181 __raw_spin_unlock(&wakeup_lock); 177 __raw_spin_unlock(&wakeup_lock);
182 local_irq_restore(flags); 178 local_irq_restore(flags);
183out: 179out:
184 atomic_dec(&tr->data[cpu]->disabled); 180 atomic_dec(&wakeup_trace->data[cpu]->disabled);
185}
186
187static notrace void
188sched_switch_callback(void *probe_data, void *call_data,
189 const char *format, va_list *args)
190{
191 struct task_struct *prev;
192 struct task_struct *next;
193 struct rq *__rq;
194
195 /* skip prev_pid %d next_pid %d prev_state %ld */
196 (void)va_arg(*args, int);
197 (void)va_arg(*args, int);
198 (void)va_arg(*args, long);
199 __rq = va_arg(*args, typeof(__rq));
200 prev = va_arg(*args, typeof(prev));
201 next = va_arg(*args, typeof(next));
202
203 tracing_record_cmdline(prev);
204
205 /*
206 * If tracer_switch_func only points to the local
207 * switch func, it still needs the ptr passed to it.
208 */
209 wakeup_sched_switch(probe_data, __rq, prev, next);
210} 181}
211 182
212static void __wakeup_reset(struct trace_array *tr) 183static void __wakeup_reset(struct trace_array *tr)
@@ -216,7 +187,7 @@ static void __wakeup_reset(struct trace_array *tr)
216 187
217 for_each_possible_cpu(cpu) { 188 for_each_possible_cpu(cpu) {
218 data = tr->data[cpu]; 189 data = tr->data[cpu];
219 tracing_reset(data); 190 tracing_reset(tr, cpu);
220 } 191 }
221 192
222 wakeup_cpu = -1; 193 wakeup_cpu = -1;
@@ -240,19 +211,26 @@ static void wakeup_reset(struct trace_array *tr)
240} 211}
241 212
242static void 213static void
243wakeup_check_start(struct trace_array *tr, struct task_struct *p, 214probe_wakeup(struct rq *rq, struct task_struct *p, int success)
244 struct task_struct *curr)
245{ 215{
246 int cpu = smp_processor_id(); 216 int cpu = smp_processor_id();
247 unsigned long flags; 217 unsigned long flags;
248 long disabled; 218 long disabled;
219 int pc;
220
221 if (likely(!tracer_enabled))
222 return;
223
224 tracing_record_cmdline(p);
225 tracing_record_cmdline(current);
249 226
250 if (likely(!rt_task(p)) || 227 if (likely(!rt_task(p)) ||
251 p->prio >= wakeup_prio || 228 p->prio >= wakeup_prio ||
252 p->prio >= curr->prio) 229 p->prio >= current->prio)
253 return; 230 return;
254 231
255 disabled = atomic_inc_return(&tr->data[cpu]->disabled); 232 pc = preempt_count();
233 disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
256 if (unlikely(disabled != 1)) 234 if (unlikely(disabled != 1))
257 goto out; 235 goto out;
258 236
@@ -264,7 +242,7 @@ wakeup_check_start(struct trace_array *tr, struct task_struct *p,
264 goto out_locked; 242 goto out_locked;
265 243
266 /* reset the trace */ 244 /* reset the trace */
267 __wakeup_reset(tr); 245 __wakeup_reset(wakeup_trace);
268 246
269 wakeup_cpu = task_cpu(p); 247 wakeup_cpu = task_cpu(p);
270 wakeup_prio = p->prio; 248 wakeup_prio = p->prio;
@@ -274,74 +252,43 @@ wakeup_check_start(struct trace_array *tr, struct task_struct *p,
274 252
275 local_save_flags(flags); 253 local_save_flags(flags);
276 254
277 tr->data[wakeup_cpu]->preempt_timestamp = ftrace_now(cpu); 255 wakeup_trace->data[wakeup_cpu]->preempt_timestamp = ftrace_now(cpu);
278 trace_function(tr, tr->data[wakeup_cpu], 256 trace_function(wakeup_trace, wakeup_trace->data[wakeup_cpu],
279 CALLER_ADDR1, CALLER_ADDR2, flags); 257 CALLER_ADDR1, CALLER_ADDR2, flags, pc);
280 258
281out_locked: 259out_locked:
282 __raw_spin_unlock(&wakeup_lock); 260 __raw_spin_unlock(&wakeup_lock);
283out: 261out:
284 atomic_dec(&tr->data[cpu]->disabled); 262 atomic_dec(&wakeup_trace->data[cpu]->disabled);
285} 263}
286 264
287static notrace void 265/*
288wake_up_callback(void *probe_data, void *call_data, 266 * save_tracer_enabled is used to save the state of the tracer_enabled
289 const char *format, va_list *args) 267 * variable when we disable it when we open a trace output file.
290{ 268 */
291 struct trace_array **ptr = probe_data; 269static int save_tracer_enabled;
292 struct trace_array *tr = *ptr;
293 struct task_struct *curr;
294 struct task_struct *task;
295 struct rq *__rq;
296
297 if (likely(!tracer_enabled))
298 return;
299
300 /* Skip pid %d state %ld */
301 (void)va_arg(*args, int);
302 (void)va_arg(*args, long);
303 /* now get the meat: "rq %p task %p rq->curr %p" */
304 __rq = va_arg(*args, typeof(__rq));
305 task = va_arg(*args, typeof(task));
306 curr = va_arg(*args, typeof(curr));
307
308 tracing_record_cmdline(task);
309 tracing_record_cmdline(curr);
310
311 wakeup_check_start(tr, task, curr);
312}
313 270
314static void start_wakeup_tracer(struct trace_array *tr) 271static void start_wakeup_tracer(struct trace_array *tr)
315{ 272{
316 int ret; 273 int ret;
317 274
318 ret = marker_probe_register("kernel_sched_wakeup", 275 ret = register_trace_sched_wakeup(probe_wakeup);
319 "pid %d state %ld ## rq %p task %p rq->curr %p",
320 wake_up_callback,
321 &wakeup_trace);
322 if (ret) { 276 if (ret) {
323 pr_info("wakeup trace: Couldn't add marker" 277 pr_info("wakeup trace: Couldn't activate tracepoint"
324 " probe to kernel_sched_wakeup\n"); 278 " probe to kernel_sched_wakeup\n");
325 return; 279 return;
326 } 280 }
327 281
328 ret = marker_probe_register("kernel_sched_wakeup_new", 282 ret = register_trace_sched_wakeup_new(probe_wakeup);
329 "pid %d state %ld ## rq %p task %p rq->curr %p",
330 wake_up_callback,
331 &wakeup_trace);
332 if (ret) { 283 if (ret) {
333 pr_info("wakeup trace: Couldn't add marker" 284 pr_info("wakeup trace: Couldn't activate tracepoint"
334 " probe to kernel_sched_wakeup_new\n"); 285 " probe to kernel_sched_wakeup_new\n");
335 goto fail_deprobe; 286 goto fail_deprobe;
336 } 287 }
337 288
338 ret = marker_probe_register("kernel_sched_schedule", 289 ret = register_trace_sched_switch(probe_wakeup_sched_switch);
339 "prev_pid %d next_pid %d prev_state %ld "
340 "## rq %p prev %p next %p",
341 sched_switch_callback,
342 &wakeup_trace);
343 if (ret) { 290 if (ret) {
344 pr_info("sched trace: Couldn't add marker" 291 pr_info("sched trace: Couldn't activate tracepoint"
345 " probe to kernel_sched_schedule\n"); 292 " probe to kernel_sched_schedule\n");
346 goto fail_deprobe_wake_new; 293 goto fail_deprobe_wake_new;
347 } 294 }
@@ -359,71 +306,71 @@ static void start_wakeup_tracer(struct trace_array *tr)
359 306
360 register_ftrace_function(&trace_ops); 307 register_ftrace_function(&trace_ops);
361 308
362 tracer_enabled = 1; 309 if (tracing_is_enabled()) {
310 tracer_enabled = 1;
311 save_tracer_enabled = 1;
312 } else {
313 tracer_enabled = 0;
314 save_tracer_enabled = 0;
315 }
363 316
364 return; 317 return;
365fail_deprobe_wake_new: 318fail_deprobe_wake_new:
366 marker_probe_unregister("kernel_sched_wakeup_new", 319 unregister_trace_sched_wakeup_new(probe_wakeup);
367 wake_up_callback,
368 &wakeup_trace);
369fail_deprobe: 320fail_deprobe:
370 marker_probe_unregister("kernel_sched_wakeup", 321 unregister_trace_sched_wakeup(probe_wakeup);
371 wake_up_callback,
372 &wakeup_trace);
373} 322}
374 323
375static void stop_wakeup_tracer(struct trace_array *tr) 324static void stop_wakeup_tracer(struct trace_array *tr)
376{ 325{
377 tracer_enabled = 0; 326 tracer_enabled = 0;
327 save_tracer_enabled = 0;
378 unregister_ftrace_function(&trace_ops); 328 unregister_ftrace_function(&trace_ops);
379 marker_probe_unregister("kernel_sched_schedule", 329 unregister_trace_sched_switch(probe_wakeup_sched_switch);
380 sched_switch_callback, 330 unregister_trace_sched_wakeup_new(probe_wakeup);
381 &wakeup_trace); 331 unregister_trace_sched_wakeup(probe_wakeup);
382 marker_probe_unregister("kernel_sched_wakeup_new",
383 wake_up_callback,
384 &wakeup_trace);
385 marker_probe_unregister("kernel_sched_wakeup",
386 wake_up_callback,
387 &wakeup_trace);
388} 332}
389 333
390static void wakeup_tracer_init(struct trace_array *tr) 334static int wakeup_tracer_init(struct trace_array *tr)
391{ 335{
392 wakeup_trace = tr; 336 wakeup_trace = tr;
393 337 start_wakeup_tracer(tr);
394 if (tr->ctrl) 338 return 0;
395 start_wakeup_tracer(tr);
396} 339}
397 340
398static void wakeup_tracer_reset(struct trace_array *tr) 341static void wakeup_tracer_reset(struct trace_array *tr)
399{ 342{
400 if (tr->ctrl) { 343 stop_wakeup_tracer(tr);
401 stop_wakeup_tracer(tr); 344 /* make sure we put back any tasks we are tracing */
402 /* make sure we put back any tasks we are tracing */ 345 wakeup_reset(tr);
403 wakeup_reset(tr);
404 }
405} 346}
406 347
407static void wakeup_tracer_ctrl_update(struct trace_array *tr) 348static void wakeup_tracer_start(struct trace_array *tr)
408{ 349{
409 if (tr->ctrl) 350 wakeup_reset(tr);
410 start_wakeup_tracer(tr); 351 tracer_enabled = 1;
411 else 352 save_tracer_enabled = 1;
412 stop_wakeup_tracer(tr); 353}
354
355static void wakeup_tracer_stop(struct trace_array *tr)
356{
357 tracer_enabled = 0;
358 save_tracer_enabled = 0;
413} 359}
414 360
415static void wakeup_tracer_open(struct trace_iterator *iter) 361static void wakeup_tracer_open(struct trace_iterator *iter)
416{ 362{
417 /* stop the trace while dumping */ 363 /* stop the trace while dumping */
418 if (iter->tr->ctrl) 364 tracer_enabled = 0;
419 stop_wakeup_tracer(iter->tr);
420} 365}
421 366
422static void wakeup_tracer_close(struct trace_iterator *iter) 367static void wakeup_tracer_close(struct trace_iterator *iter)
423{ 368{
424 /* forget about any processes we were recording */ 369 /* forget about any processes we were recording */
425 if (iter->tr->ctrl) 370 if (save_tracer_enabled) {
426 start_wakeup_tracer(iter->tr); 371 wakeup_reset(iter->tr);
372 tracer_enabled = 1;
373 }
427} 374}
428 375
429static struct tracer wakeup_tracer __read_mostly = 376static struct tracer wakeup_tracer __read_mostly =
@@ -431,9 +378,10 @@ static struct tracer wakeup_tracer __read_mostly =
431 .name = "wakeup", 378 .name = "wakeup",
432 .init = wakeup_tracer_init, 379 .init = wakeup_tracer_init,
433 .reset = wakeup_tracer_reset, 380 .reset = wakeup_tracer_reset,
381 .start = wakeup_tracer_start,
382 .stop = wakeup_tracer_stop,
434 .open = wakeup_tracer_open, 383 .open = wakeup_tracer_open,
435 .close = wakeup_tracer_close, 384 .close = wakeup_tracer_close,
436 .ctrl_update = wakeup_tracer_ctrl_update,
437 .print_max = 1, 385 .print_max = 1,
438#ifdef CONFIG_FTRACE_SELFTEST 386#ifdef CONFIG_FTRACE_SELFTEST
439 .selftest = trace_selftest_startup_wakeup, 387 .selftest = trace_selftest_startup_wakeup,