diff options
Diffstat (limited to 'kernel/trace/trace_sched_wakeup.c')
-rw-r--r-- | kernel/trace/trace_sched_wakeup.c | 220 |
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 | ||
32 | static void __wakeup_reset(struct trace_array *tr); | 32 | static 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 | ||
93 | static struct ftrace_ops trace_ops __read_mostly = | 86 | static 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 | ||
114 | static void notrace | 107 | static void notrace |
115 | wakeup_sched_switch(void *private, void *rq, struct task_struct *prev, | 108 | probe_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 | ||
179 | out_unlock: | 175 | out_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); |
183 | out: | 179 | out: |
184 | atomic_dec(&tr->data[cpu]->disabled); | 180 | atomic_dec(&wakeup_trace->data[cpu]->disabled); |
185 | } | ||
186 | |||
187 | static notrace void | ||
188 | sched_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 | ||
212 | static void __wakeup_reset(struct trace_array *tr) | 183 | static 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 | ||
242 | static void | 213 | static void |
243 | wakeup_check_start(struct trace_array *tr, struct task_struct *p, | 214 | probe_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 | ||
281 | out_locked: | 259 | out_locked: |
282 | __raw_spin_unlock(&wakeup_lock); | 260 | __raw_spin_unlock(&wakeup_lock); |
283 | out: | 261 | out: |
284 | atomic_dec(&tr->data[cpu]->disabled); | 262 | atomic_dec(&wakeup_trace->data[cpu]->disabled); |
285 | } | 263 | } |
286 | 264 | ||
287 | static notrace void | 265 | /* |
288 | wake_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; | 269 | static 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 | ||
314 | static void start_wakeup_tracer(struct trace_array *tr) | 271 | static 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; |
365 | fail_deprobe_wake_new: | 318 | fail_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); | ||
369 | fail_deprobe: | 320 | fail_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 | ||
375 | static void stop_wakeup_tracer(struct trace_array *tr) | 324 | static 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 | ||
390 | static void wakeup_tracer_init(struct trace_array *tr) | 334 | static 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 | ||
398 | static void wakeup_tracer_reset(struct trace_array *tr) | 341 | static 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 | ||
407 | static void wakeup_tracer_ctrl_update(struct trace_array *tr) | 348 | static 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 | |||
355 | static void wakeup_tracer_stop(struct trace_array *tr) | ||
356 | { | ||
357 | tracer_enabled = 0; | ||
358 | save_tracer_enabled = 0; | ||
413 | } | 359 | } |
414 | 360 | ||
415 | static void wakeup_tracer_open(struct trace_iterator *iter) | 361 | static 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 | ||
422 | static void wakeup_tracer_close(struct trace_iterator *iter) | 367 | static 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 | ||
429 | static struct tracer wakeup_tracer __read_mostly = | 376 | static 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, |