diff options
Diffstat (limited to 'kernel/trace/trace_irqsoff.c')
-rw-r--r-- | kernel/trace/trace_irqsoff.c | 84 |
1 files changed, 53 insertions, 31 deletions
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index ece6cfb649fa..7c2e326bbc8b 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c | |||
@@ -63,7 +63,7 @@ irq_trace(void) | |||
63 | */ | 63 | */ |
64 | static __cacheline_aligned_in_smp unsigned long max_sequence; | 64 | static __cacheline_aligned_in_smp unsigned long max_sequence; |
65 | 65 | ||
66 | #ifdef CONFIG_FTRACE | 66 | #ifdef CONFIG_FUNCTION_TRACER |
67 | /* | 67 | /* |
68 | * irqsoff uses its own tracer function to keep the overhead down: | 68 | * irqsoff uses its own tracer function to keep the overhead down: |
69 | */ | 69 | */ |
@@ -95,7 +95,7 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip) | |||
95 | disabled = atomic_inc_return(&data->disabled); | 95 | disabled = atomic_inc_return(&data->disabled); |
96 | 96 | ||
97 | if (likely(disabled == 1)) | 97 | if (likely(disabled == 1)) |
98 | trace_function(tr, data, ip, parent_ip, flags); | 98 | trace_function(tr, data, ip, parent_ip, flags, preempt_count()); |
99 | 99 | ||
100 | atomic_dec(&data->disabled); | 100 | atomic_dec(&data->disabled); |
101 | } | 101 | } |
@@ -104,7 +104,7 @@ static struct ftrace_ops trace_ops __read_mostly = | |||
104 | { | 104 | { |
105 | .func = irqsoff_tracer_call, | 105 | .func = irqsoff_tracer_call, |
106 | }; | 106 | }; |
107 | #endif /* CONFIG_FTRACE */ | 107 | #endif /* CONFIG_FUNCTION_TRACER */ |
108 | 108 | ||
109 | /* | 109 | /* |
110 | * Should this new latency be reported/recorded? | 110 | * Should this new latency be reported/recorded? |
@@ -130,6 +130,7 @@ check_critical_timing(struct trace_array *tr, | |||
130 | unsigned long latency, t0, t1; | 130 | unsigned long latency, t0, t1; |
131 | cycle_t T0, T1, delta; | 131 | cycle_t T0, T1, delta; |
132 | unsigned long flags; | 132 | unsigned long flags; |
133 | int pc; | ||
133 | 134 | ||
134 | /* | 135 | /* |
135 | * usecs conversion is slow so we try to delay the conversion | 136 | * usecs conversion is slow so we try to delay the conversion |
@@ -141,6 +142,8 @@ check_critical_timing(struct trace_array *tr, | |||
141 | 142 | ||
142 | local_save_flags(flags); | 143 | local_save_flags(flags); |
143 | 144 | ||
145 | pc = preempt_count(); | ||
146 | |||
144 | if (!report_latency(delta)) | 147 | if (!report_latency(delta)) |
145 | goto out; | 148 | goto out; |
146 | 149 | ||
@@ -150,7 +153,7 @@ check_critical_timing(struct trace_array *tr, | |||
150 | if (!report_latency(delta)) | 153 | if (!report_latency(delta)) |
151 | goto out_unlock; | 154 | goto out_unlock; |
152 | 155 | ||
153 | trace_function(tr, data, CALLER_ADDR0, parent_ip, flags); | 156 | trace_function(tr, data, CALLER_ADDR0, parent_ip, flags, pc); |
154 | 157 | ||
155 | latency = nsecs_to_usecs(delta); | 158 | latency = nsecs_to_usecs(delta); |
156 | 159 | ||
@@ -173,8 +176,8 @@ out_unlock: | |||
173 | out: | 176 | out: |
174 | data->critical_sequence = max_sequence; | 177 | data->critical_sequence = max_sequence; |
175 | data->preempt_timestamp = ftrace_now(cpu); | 178 | data->preempt_timestamp = ftrace_now(cpu); |
176 | tracing_reset(data); | 179 | tracing_reset(tr, cpu); |
177 | trace_function(tr, data, CALLER_ADDR0, parent_ip, flags); | 180 | trace_function(tr, data, CALLER_ADDR0, parent_ip, flags, pc); |
178 | } | 181 | } |
179 | 182 | ||
180 | static inline void | 183 | static inline void |
@@ -203,11 +206,11 @@ start_critical_timing(unsigned long ip, unsigned long parent_ip) | |||
203 | data->critical_sequence = max_sequence; | 206 | data->critical_sequence = max_sequence; |
204 | data->preempt_timestamp = ftrace_now(cpu); | 207 | data->preempt_timestamp = ftrace_now(cpu); |
205 | data->critical_start = parent_ip ? : ip; | 208 | data->critical_start = parent_ip ? : ip; |
206 | tracing_reset(data); | 209 | tracing_reset(tr, cpu); |
207 | 210 | ||
208 | local_save_flags(flags); | 211 | local_save_flags(flags); |
209 | 212 | ||
210 | trace_function(tr, data, ip, parent_ip, flags); | 213 | trace_function(tr, data, ip, parent_ip, flags, preempt_count()); |
211 | 214 | ||
212 | per_cpu(tracing_cpu, cpu) = 1; | 215 | per_cpu(tracing_cpu, cpu) = 1; |
213 | 216 | ||
@@ -234,14 +237,14 @@ stop_critical_timing(unsigned long ip, unsigned long parent_ip) | |||
234 | 237 | ||
235 | data = tr->data[cpu]; | 238 | data = tr->data[cpu]; |
236 | 239 | ||
237 | if (unlikely(!data) || unlikely(!head_page(data)) || | 240 | if (unlikely(!data) || |
238 | !data->critical_start || atomic_read(&data->disabled)) | 241 | !data->critical_start || atomic_read(&data->disabled)) |
239 | return; | 242 | return; |
240 | 243 | ||
241 | atomic_inc(&data->disabled); | 244 | atomic_inc(&data->disabled); |
242 | 245 | ||
243 | local_save_flags(flags); | 246 | local_save_flags(flags); |
244 | trace_function(tr, data, ip, parent_ip, flags); | 247 | trace_function(tr, data, ip, parent_ip, flags, preempt_count()); |
245 | check_critical_timing(tr, data, parent_ip ? : ip, cpu); | 248 | check_critical_timing(tr, data, parent_ip ? : ip, cpu); |
246 | data->critical_start = 0; | 249 | data->critical_start = 0; |
247 | atomic_dec(&data->disabled); | 250 | atomic_dec(&data->disabled); |
@@ -350,15 +353,28 @@ void trace_preempt_off(unsigned long a0, unsigned long a1) | |||
350 | } | 353 | } |
351 | #endif /* CONFIG_PREEMPT_TRACER */ | 354 | #endif /* CONFIG_PREEMPT_TRACER */ |
352 | 355 | ||
356 | /* | ||
357 | * save_tracer_enabled is used to save the state of the tracer_enabled | ||
358 | * variable when we disable it when we open a trace output file. | ||
359 | */ | ||
360 | static int save_tracer_enabled; | ||
361 | |||
353 | static void start_irqsoff_tracer(struct trace_array *tr) | 362 | static void start_irqsoff_tracer(struct trace_array *tr) |
354 | { | 363 | { |
355 | register_ftrace_function(&trace_ops); | 364 | register_ftrace_function(&trace_ops); |
356 | tracer_enabled = 1; | 365 | if (tracing_is_enabled()) { |
366 | tracer_enabled = 1; | ||
367 | save_tracer_enabled = 1; | ||
368 | } else { | ||
369 | tracer_enabled = 0; | ||
370 | save_tracer_enabled = 0; | ||
371 | } | ||
357 | } | 372 | } |
358 | 373 | ||
359 | static void stop_irqsoff_tracer(struct trace_array *tr) | 374 | static void stop_irqsoff_tracer(struct trace_array *tr) |
360 | { | 375 | { |
361 | tracer_enabled = 0; | 376 | tracer_enabled = 0; |
377 | save_tracer_enabled = 0; | ||
362 | unregister_ftrace_function(&trace_ops); | 378 | unregister_ftrace_function(&trace_ops); |
363 | } | 379 | } |
364 | 380 | ||
@@ -367,53 +383,55 @@ static void __irqsoff_tracer_init(struct trace_array *tr) | |||
367 | irqsoff_trace = tr; | 383 | irqsoff_trace = tr; |
368 | /* make sure that the tracer is visible */ | 384 | /* make sure that the tracer is visible */ |
369 | smp_wmb(); | 385 | smp_wmb(); |
370 | 386 | start_irqsoff_tracer(tr); | |
371 | if (tr->ctrl) | ||
372 | start_irqsoff_tracer(tr); | ||
373 | } | 387 | } |
374 | 388 | ||
375 | static void irqsoff_tracer_reset(struct trace_array *tr) | 389 | static void irqsoff_tracer_reset(struct trace_array *tr) |
376 | { | 390 | { |
377 | if (tr->ctrl) | 391 | stop_irqsoff_tracer(tr); |
378 | stop_irqsoff_tracer(tr); | ||
379 | } | 392 | } |
380 | 393 | ||
381 | static void irqsoff_tracer_ctrl_update(struct trace_array *tr) | 394 | static void irqsoff_tracer_start(struct trace_array *tr) |
382 | { | 395 | { |
383 | if (tr->ctrl) | 396 | tracer_enabled = 1; |
384 | start_irqsoff_tracer(tr); | 397 | save_tracer_enabled = 1; |
385 | else | 398 | } |
386 | stop_irqsoff_tracer(tr); | 399 | |
400 | static void irqsoff_tracer_stop(struct trace_array *tr) | ||
401 | { | ||
402 | tracer_enabled = 0; | ||
403 | save_tracer_enabled = 0; | ||
387 | } | 404 | } |
388 | 405 | ||
389 | static void irqsoff_tracer_open(struct trace_iterator *iter) | 406 | static void irqsoff_tracer_open(struct trace_iterator *iter) |
390 | { | 407 | { |
391 | /* stop the trace while dumping */ | 408 | /* stop the trace while dumping */ |
392 | if (iter->tr->ctrl) | 409 | tracer_enabled = 0; |
393 | stop_irqsoff_tracer(iter->tr); | ||
394 | } | 410 | } |
395 | 411 | ||
396 | static void irqsoff_tracer_close(struct trace_iterator *iter) | 412 | static void irqsoff_tracer_close(struct trace_iterator *iter) |
397 | { | 413 | { |
398 | if (iter->tr->ctrl) | 414 | /* restart tracing */ |
399 | start_irqsoff_tracer(iter->tr); | 415 | tracer_enabled = save_tracer_enabled; |
400 | } | 416 | } |
401 | 417 | ||
402 | #ifdef CONFIG_IRQSOFF_TRACER | 418 | #ifdef CONFIG_IRQSOFF_TRACER |
403 | static void irqsoff_tracer_init(struct trace_array *tr) | 419 | static int irqsoff_tracer_init(struct trace_array *tr) |
404 | { | 420 | { |
405 | trace_type = TRACER_IRQS_OFF; | 421 | trace_type = TRACER_IRQS_OFF; |
406 | 422 | ||
407 | __irqsoff_tracer_init(tr); | 423 | __irqsoff_tracer_init(tr); |
424 | return 0; | ||
408 | } | 425 | } |
409 | static struct tracer irqsoff_tracer __read_mostly = | 426 | static struct tracer irqsoff_tracer __read_mostly = |
410 | { | 427 | { |
411 | .name = "irqsoff", | 428 | .name = "irqsoff", |
412 | .init = irqsoff_tracer_init, | 429 | .init = irqsoff_tracer_init, |
413 | .reset = irqsoff_tracer_reset, | 430 | .reset = irqsoff_tracer_reset, |
431 | .start = irqsoff_tracer_start, | ||
432 | .stop = irqsoff_tracer_stop, | ||
414 | .open = irqsoff_tracer_open, | 433 | .open = irqsoff_tracer_open, |
415 | .close = irqsoff_tracer_close, | 434 | .close = irqsoff_tracer_close, |
416 | .ctrl_update = irqsoff_tracer_ctrl_update, | ||
417 | .print_max = 1, | 435 | .print_max = 1, |
418 | #ifdef CONFIG_FTRACE_SELFTEST | 436 | #ifdef CONFIG_FTRACE_SELFTEST |
419 | .selftest = trace_selftest_startup_irqsoff, | 437 | .selftest = trace_selftest_startup_irqsoff, |
@@ -425,11 +443,12 @@ static struct tracer irqsoff_tracer __read_mostly = | |||
425 | #endif | 443 | #endif |
426 | 444 | ||
427 | #ifdef CONFIG_PREEMPT_TRACER | 445 | #ifdef CONFIG_PREEMPT_TRACER |
428 | static void preemptoff_tracer_init(struct trace_array *tr) | 446 | static int preemptoff_tracer_init(struct trace_array *tr) |
429 | { | 447 | { |
430 | trace_type = TRACER_PREEMPT_OFF; | 448 | trace_type = TRACER_PREEMPT_OFF; |
431 | 449 | ||
432 | __irqsoff_tracer_init(tr); | 450 | __irqsoff_tracer_init(tr); |
451 | return 0; | ||
433 | } | 452 | } |
434 | 453 | ||
435 | static struct tracer preemptoff_tracer __read_mostly = | 454 | static struct tracer preemptoff_tracer __read_mostly = |
@@ -437,9 +456,10 @@ static struct tracer preemptoff_tracer __read_mostly = | |||
437 | .name = "preemptoff", | 456 | .name = "preemptoff", |
438 | .init = preemptoff_tracer_init, | 457 | .init = preemptoff_tracer_init, |
439 | .reset = irqsoff_tracer_reset, | 458 | .reset = irqsoff_tracer_reset, |
459 | .start = irqsoff_tracer_start, | ||
460 | .stop = irqsoff_tracer_stop, | ||
440 | .open = irqsoff_tracer_open, | 461 | .open = irqsoff_tracer_open, |
441 | .close = irqsoff_tracer_close, | 462 | .close = irqsoff_tracer_close, |
442 | .ctrl_update = irqsoff_tracer_ctrl_update, | ||
443 | .print_max = 1, | 463 | .print_max = 1, |
444 | #ifdef CONFIG_FTRACE_SELFTEST | 464 | #ifdef CONFIG_FTRACE_SELFTEST |
445 | .selftest = trace_selftest_startup_preemptoff, | 465 | .selftest = trace_selftest_startup_preemptoff, |
@@ -453,11 +473,12 @@ static struct tracer preemptoff_tracer __read_mostly = | |||
453 | #if defined(CONFIG_IRQSOFF_TRACER) && \ | 473 | #if defined(CONFIG_IRQSOFF_TRACER) && \ |
454 | defined(CONFIG_PREEMPT_TRACER) | 474 | defined(CONFIG_PREEMPT_TRACER) |
455 | 475 | ||
456 | static void preemptirqsoff_tracer_init(struct trace_array *tr) | 476 | static int preemptirqsoff_tracer_init(struct trace_array *tr) |
457 | { | 477 | { |
458 | trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF; | 478 | trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF; |
459 | 479 | ||
460 | __irqsoff_tracer_init(tr); | 480 | __irqsoff_tracer_init(tr); |
481 | return 0; | ||
461 | } | 482 | } |
462 | 483 | ||
463 | static struct tracer preemptirqsoff_tracer __read_mostly = | 484 | static struct tracer preemptirqsoff_tracer __read_mostly = |
@@ -465,9 +486,10 @@ static struct tracer preemptirqsoff_tracer __read_mostly = | |||
465 | .name = "preemptirqsoff", | 486 | .name = "preemptirqsoff", |
466 | .init = preemptirqsoff_tracer_init, | 487 | .init = preemptirqsoff_tracer_init, |
467 | .reset = irqsoff_tracer_reset, | 488 | .reset = irqsoff_tracer_reset, |
489 | .start = irqsoff_tracer_start, | ||
490 | .stop = irqsoff_tracer_stop, | ||
468 | .open = irqsoff_tracer_open, | 491 | .open = irqsoff_tracer_open, |
469 | .close = irqsoff_tracer_close, | 492 | .close = irqsoff_tracer_close, |
470 | .ctrl_update = irqsoff_tracer_ctrl_update, | ||
471 | .print_max = 1, | 493 | .print_max = 1, |
472 | #ifdef CONFIG_FTRACE_SELFTEST | 494 | #ifdef CONFIG_FTRACE_SELFTEST |
473 | .selftest = trace_selftest_startup_preemptirqsoff, | 495 | .selftest = trace_selftest_startup_preemptirqsoff, |