trace_irqsoff.c 18.2 KB
Newer Older
1
/*
2
 * trace irqs off critical timings
3 4 5 6 7 8 9
 *
 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
 * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
 *
 * From code in the latency_tracer, that is:
 *
 *  Copyright (C) 2004-2006 Ingo Molnar
10
 *  Copyright (C) 2004 Nadia Yvette Chambers
11 12 13 14 15 16 17 18 19 20 21
 */
#include <linux/kallsyms.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/ftrace.h>

#include "trace.h"

static struct trace_array		*irqsoff_trace __read_mostly;
static int				tracer_enabled __read_mostly;

22 23
static DEFINE_PER_CPU(int, tracing_cpu);

24
static DEFINE_RAW_SPINLOCK(max_trace_lock);
25

26 27 28 29 30 31 32
enum {
	TRACER_IRQS_OFF		= (1 << 1),
	TRACER_PREEMPT_OFF	= (1 << 2),
};

static int trace_type __read_mostly;

33
static int save_flags;
34

35 36 37
static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
static int start_irqsoff_tracer(struct trace_array *tr, int graph);

38
#ifdef CONFIG_PREEMPT_TRACER
Ingo Molnar's avatar
Ingo Molnar committed
39
static inline int
40 41 42 43 44 45 46 47 48
preempt_trace(void)
{
	return ((trace_type & TRACER_PREEMPT_OFF) && preempt_count());
}
#else
# define preempt_trace() (0)
#endif

#ifdef CONFIG_IRQSOFF_TRACER
Ingo Molnar's avatar
Ingo Molnar committed
49
static inline int
50 51 52 53 54 55 56 57 58
irq_trace(void)
{
	return ((trace_type & TRACER_IRQS_OFF) &&
		irqs_disabled());
}
#else
# define irq_trace() (0)
#endif

59
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
60
static int irqsoff_display_graph(struct trace_array *tr, int set);
61
# define is_graph(tr) ((tr)->trace_flags & TRACE_ITER_DISPLAY_GRAPH)
62 63 64 65 66
#else
static inline int irqsoff_display_graph(struct trace_array *tr, int set)
{
	return -EINVAL;
}
67
# define is_graph(tr) false
68 69
#endif

70 71 72 73 74
/*
 * Sequence count - we record it when starting a measurement and
 * skip the latency if the sequence has changed - some other section
 * did a maximum and could disturb our measurement with serial console
 * printouts, etc. Truly coinciding maximum latencies should be rare
Lucas De Marchi's avatar
Lucas De Marchi committed
75
 * and what happens together happens separately as well, so this doesn't
76 77 78 79
 * decrease the validity of the maximum found:
 */
static __cacheline_aligned_in_smp	unsigned long max_sequence;

80
#ifdef CONFIG_FUNCTION_TRACER
81
/*
82 83 84 85 86 87 88 89 90 91 92
 * Prologue for the preempt and irqs off function tracers.
 *
 * Returns 1 if it is OK to continue, and data->disabled is
 *            incremented.
 *         0 if the trace is to be ignored, and data->disabled
 *            is kept the same.
 *
 * Note, this function is also used outside this ifdef but
 *  inside the #ifdef of the function graph tracer below.
 *  This is OK, since the function graph tracer is
 *  dependent on the function tracer.
93
 */
94 95 96
static int func_prolog_dec(struct trace_array *tr,
			   struct trace_array_cpu **data,
			   unsigned long *flags)
97 98 99 100
{
	long disabled;
	int cpu;

101 102 103 104 105 106 107 108
	/*
	 * Does not matter if we preempt. We test the flags
	 * afterward, to see if irqs are disabled or not.
	 * If we preempt and get a false positive, the flags
	 * test will fail.
	 */
	cpu = raw_smp_processor_id();
	if (likely(!per_cpu(tracing_cpu, cpu)))
109
		return 0;
110

111
	local_save_flags(*flags);
112 113 114 115 116 117
	/*
	 * Slight chance to get a false positive on tracing_cpu,
	 * although I'm starting to think there isn't a chance.
	 * Leave this for now just to be paranoid.
	 */
	if (!irqs_disabled_flags(*flags) && !preempt_count())
118
		return 0;
119

120
	*data = per_cpu_ptr(tr->trace_buffer.data, cpu);
121
	disabled = atomic_inc_return(&(*data)->disabled);
122 123

	if (likely(disabled == 1))
124 125 126 127 128 129 130 131 132 133 134
		return 1;

	atomic_dec(&(*data)->disabled);

	return 0;
}

/*
 * irqsoff uses its own tracer function to keep the overhead down:
 */
static void
135
irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip,
136
		    struct ftrace_ops *op, struct pt_regs *pt_regs)
137 138 139 140 141 142 143 144 145
{
	struct trace_array *tr = irqsoff_trace;
	struct trace_array_cpu *data;
	unsigned long flags;

	if (!func_prolog_dec(tr, &data, &flags))
		return;

	trace_function(tr, ip, parent_ip, flags, preempt_count());
146 147 148

	atomic_dec(&data->disabled);
}
149
#endif /* CONFIG_FUNCTION_TRACER */
150

151
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
152
static int irqsoff_display_graph(struct trace_array *tr, int set)
153 154 155
{
	int cpu;

156
	if (!(is_graph(tr) ^ set))
157 158 159 160 161 162 163
		return 0;

	stop_irqsoff_tracer(irqsoff_trace, !set);

	for_each_possible_cpu(cpu)
		per_cpu(tracing_cpu, cpu) = 0;

164
	tr->max_latency = 0;
165
	tracing_reset_online_cpus(&irqsoff_trace->trace_buffer);
166 167 168 169 170 171 172 173 174 175 176 177

	return start_irqsoff_tracer(irqsoff_trace, set);
}

static int irqsoff_graph_entry(struct ftrace_graph_ent *trace)
{
	struct trace_array *tr = irqsoff_trace;
	struct trace_array_cpu *data;
	unsigned long flags;
	int ret;
	int pc;

178 179 180 181 182 183 184 185 186 187 188 189
	if (ftrace_graph_ignore_func(trace))
		return 0;
	/*
	 * Do not trace a function if it's filtered by set_graph_notrace.
	 * Make the index of ret stack negative to indicate that it should
	 * ignore further functions.  But it needs its own ret stack entry
	 * to recover the original index in order to continue tracing after
	 * returning from the function.
	 */
	if (ftrace_graph_notrace_addr(trace->func))
		return 1;

190
	if (!func_prolog_dec(tr, &data, &flags))
191 192
		return 0;

193 194
	pc = preempt_count();
	ret = __trace_graph_entry(tr, trace, flags, pc);
195
	atomic_dec(&data->disabled);
196

197 198 199 200 201 202 203 204 205 206
	return ret;
}

static void irqsoff_graph_return(struct ftrace_graph_ret *trace)
{
	struct trace_array *tr = irqsoff_trace;
	struct trace_array_cpu *data;
	unsigned long flags;
	int pc;

207
	if (!func_prolog_dec(tr, &data, &flags))
208 209
		return;

210 211
	pc = preempt_count();
	__trace_graph_return(tr, trace, flags, pc);
212 213 214 215 216
	atomic_dec(&data->disabled);
}

static void irqsoff_trace_open(struct trace_iterator *iter)
{
217
	if (is_graph(iter->tr))
218 219 220 221 222 223 224 225 226 227 228
		graph_trace_open(iter);

}

static void irqsoff_trace_close(struct trace_iterator *iter)
{
	if (iter->private)
		graph_trace_close(iter);
}

#define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_CPU | \
229 230 231
			    TRACE_GRAPH_PRINT_PROC | \
			    TRACE_GRAPH_PRINT_ABS_TIME | \
			    TRACE_GRAPH_PRINT_DURATION)
232 233 234 235 236 237 238

static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
{
	/*
	 * In graph mode call the graph tracer output function,
	 * otherwise go with the TRACE_FN event handler
	 */
239
	if (is_graph(iter->tr))
240
		return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
241 242 243 244 245 246

	return TRACE_TYPE_UNHANDLED;
}

static void irqsoff_print_header(struct seq_file *s)
{
247 248 249
	struct trace_array *tr = irqsoff_trace;

	if (is_graph(tr))
250 251
		print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
	else
252 253 254 255 256 257 258 259
		trace_default_header(s);
}

static void
__trace_function(struct trace_array *tr,
		 unsigned long ip, unsigned long parent_ip,
		 unsigned long flags, int pc)
{
260
	if (is_graph(tr))
261 262
		trace_graph_function(tr, ip, parent_ip, flags, pc);
	else
263 264 265 266 267 268
		trace_function(tr, ip, parent_ip, flags, pc);
}

#else
#define __trace_function trace_function

269
#ifdef CONFIG_FUNCTION_TRACER
270 271 272 273
static int irqsoff_graph_entry(struct ftrace_graph_ent *trace)
{
	return -1;
}
274
#endif
275 276 277 278 279 280 281 282

static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
{
	return TRACE_TYPE_UNHANDLED;
}

static void irqsoff_trace_open(struct trace_iterator *iter) { }
static void irqsoff_trace_close(struct trace_iterator *iter) { }
283 284

#ifdef CONFIG_FUNCTION_TRACER
285
static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { }
286 287 288 289 290 291 292 293 294 295
static void irqsoff_print_header(struct seq_file *s)
{
	trace_default_header(s);
}
#else
static void irqsoff_print_header(struct seq_file *s)
{
	trace_latency_header(s);
}
#endif /* CONFIG_FUNCTION_TRACER */
296 297
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

298 299 300
/*
 * Should this new latency be reported/recorded?
 */
301
static bool report_latency(struct trace_array *tr, u64 delta)
302 303 304
{
	if (tracing_thresh) {
		if (delta < tracing_thresh)
305
			return false;
306
	} else {
307
		if (delta <= tr->max_latency)
308
			return false;
309
	}
310
	return true;
311 312
}

Ingo Molnar's avatar
Ingo Molnar committed
313
static void
314 315 316 317 318
check_critical_timing(struct trace_array *tr,
		      struct trace_array_cpu *data,
		      unsigned long parent_ip,
		      int cpu)
{
319
	u64 T0, T1, delta;
320
	unsigned long flags;
321
	int pc;
322 323

	T0 = data->preempt_timestamp;
324
	T1 = ftrace_now(cpu);
325 326 327 328
	delta = T1-T0;

	local_save_flags(flags);

329 330
	pc = preempt_count();

331
	if (!report_latency(tr, delta))
332 333
		goto out;

334
	raw_spin_lock_irqsave(&max_trace_lock, flags);
335

336
	/* check if we are still the max latency */
337
	if (!report_latency(tr, delta))
338 339
		goto out_unlock;

340
	__trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc);
341 342
	/* Skip 5 functions to get to the irq/preempt enable function */
	__trace_stack(tr, flags, 5, pc);
343 344

	if (data->critical_sequence != max_sequence)
345
		goto out_unlock;
346 347 348

	data->critical_end = parent_ip;

349
	if (likely(!is_tracing_stopped())) {
350
		tr->max_latency = delta;
351 352
		update_max_tr_single(tr, current, cpu);
	}
353 354 355

	max_sequence++;

356
out_unlock:
357
	raw_spin_unlock_irqrestore(&max_trace_lock, flags);
358

359 360
out:
	data->critical_sequence = max_sequence;
361
	data->preempt_timestamp = ftrace_now(cpu);
362
	__trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc);
363 364
}

Ingo Molnar's avatar
Ingo Molnar committed
365
static inline void
366 367 368 369 370 371 372
start_critical_timing(unsigned long ip, unsigned long parent_ip)
{
	int cpu;
	struct trace_array *tr = irqsoff_trace;
	struct trace_array_cpu *data;
	unsigned long flags;

373
	if (!tracer_enabled || !tracing_is_enabled())
374 375
		return;

376 377 378
	cpu = raw_smp_processor_id();

	if (per_cpu(tracing_cpu, cpu))
379 380
		return;

381
	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
382

383
	if (unlikely(!data) || atomic_read(&data->disabled))
384 385 386 387 388
		return;

	atomic_inc(&data->disabled);

	data->critical_sequence = max_sequence;
389
	data->preempt_timestamp = ftrace_now(cpu);
390
	data->critical_start = parent_ip ? : ip;
391 392

	local_save_flags(flags);
393

394
	__trace_function(tr, ip, parent_ip, flags, preempt_count());
395

396
	per_cpu(tracing_cpu, cpu) = 1;
397

398 399 400
	atomic_dec(&data->disabled);
}

Ingo Molnar's avatar
Ingo Molnar committed
401
static inline void
402 403 404 405 406 407 408
stop_critical_timing(unsigned long ip, unsigned long parent_ip)
{
	int cpu;
	struct trace_array *tr = irqsoff_trace;
	struct trace_array_cpu *data;
	unsigned long flags;

409
	cpu = raw_smp_processor_id();
410
	/* Always clear the tracing cpu on stopping the trace */
411 412
	if (unlikely(per_cpu(tracing_cpu, cpu)))
		per_cpu(tracing_cpu, cpu) = 0;
413 414 415
	else
		return;

416
	if (!tracer_enabled || !tracing_is_enabled())
417 418
		return;

419
	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
420

421
	if (unlikely(!data) ||
422 423 424 425
	    !data->critical_start || atomic_read(&data->disabled))
		return;

	atomic_inc(&data->disabled);
426

427
	local_save_flags(flags);
428
	__trace_function(tr, ip, parent_ip, flags, preempt_count());
429
	check_critical_timing(tr, data, parent_ip ? : ip, cpu);
430 431 432 433
	data->critical_start = 0;
	atomic_dec(&data->disabled);
}

434
/* start and stop critical timings used to for stoppage (in idle) */
Ingo Molnar's avatar
Ingo Molnar committed
435
void start_critical_timings(void)
436
{
437
	if (preempt_trace() || irq_trace())
438 439
		start_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
}
Ingo Molnar's avatar
Ingo Molnar committed
440
EXPORT_SYMBOL_GPL(start_critical_timings);
441

Ingo Molnar's avatar
Ingo Molnar committed
442
void stop_critical_timings(void)
443
{
444
	if (preempt_trace() || irq_trace())
445 446
		stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
}
Ingo Molnar's avatar
Ingo Molnar committed
447
EXPORT_SYMBOL_GPL(stop_critical_timings);
448

449
#ifdef CONFIG_IRQSOFF_TRACER
450
#ifdef CONFIG_PROVE_LOCKING
Ingo Molnar's avatar
Ingo Molnar committed
451
void time_hardirqs_on(unsigned long a0, unsigned long a1)
452
{
453
	if (!preempt_trace() && irq_trace())
454 455 456
		stop_critical_timing(a0, a1);
}

Ingo Molnar's avatar
Ingo Molnar committed
457
void time_hardirqs_off(unsigned long a0, unsigned long a1)
458
{
459
	if (!preempt_trace() && irq_trace())
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
		start_critical_timing(a0, a1);
}

#else /* !CONFIG_PROVE_LOCKING */

/*
 * Stubs:
 */

void trace_softirqs_on(unsigned long ip)
{
}

void trace_softirqs_off(unsigned long ip)
{
}

Ingo Molnar's avatar
Ingo Molnar committed
477
inline void print_irqtrace_events(struct task_struct *curr)
478 479 480 481 482 483
{
}

/*
 * We are only interested in hardirq on/off events:
 */
Ingo Molnar's avatar
Ingo Molnar committed
484
void trace_hardirqs_on(void)
485
{
486
	if (ipipe_root_p && !preempt_trace() && irq_trace())
487 488 489 490
		stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
}
EXPORT_SYMBOL(trace_hardirqs_on);

Ingo Molnar's avatar
Ingo Molnar committed
491
void trace_hardirqs_off(void)
492
{
493
	if (ipipe_root_p && !preempt_trace() && irq_trace())
494 495 496 497
		start_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
}
EXPORT_SYMBOL(trace_hardirqs_off);

498
__visible void trace_hardirqs_on_caller(unsigned long caller_addr)
499
{
500
	if (ipipe_root_p && !preempt_trace() && irq_trace())
501 502 503 504
		stop_critical_timing(CALLER_ADDR0, caller_addr);
}
EXPORT_SYMBOL(trace_hardirqs_on_caller);

505 506 507 508 509 510
__visible void trace_hardirqs_on_virt_caller(unsigned long caller_addr)
{
	if (ipipe_root_p && !raw_irqs_disabled())
		trace_hardirqs_on_caller(caller_addr);
}

511
__visible void trace_hardirqs_off_caller(unsigned long caller_addr)
512
{
513
	if (ipipe_root_p && !preempt_trace() && irq_trace())
514 515 516 517 518
		start_critical_timing(CALLER_ADDR0, caller_addr);
}
EXPORT_SYMBOL(trace_hardirqs_off_caller);

#endif /* CONFIG_PROVE_LOCKING */
519 520 521
#endif /*  CONFIG_IRQSOFF_TRACER */

#ifdef CONFIG_PREEMPT_TRACER
Ingo Molnar's avatar
Ingo Molnar committed
522
void trace_preempt_on(unsigned long a0, unsigned long a1)
523
{
524
	if (preempt_trace() && !irq_trace())
525
		stop_critical_timing(a0, a1);
526 527
}

Ingo Molnar's avatar
Ingo Molnar committed
528
void trace_preempt_off(unsigned long a0, unsigned long a1)
529
{
530
	if (preempt_trace() && !irq_trace())
531
		start_critical_timing(a0, a1);
532 533
}
#endif /* CONFIG_PREEMPT_TRACER */
534

535 536 537
#ifdef CONFIG_FUNCTION_TRACER
static bool function_enabled;

538
static int register_irqsoff_function(struct trace_array *tr, int graph, int set)
539
{
540
	int ret;
541

542
	/* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
543
	if (function_enabled || (!set && !(tr->trace_flags & TRACE_ITER_FUNCTION)))
544 545 546
		return 0;

	if (graph)
547 548
		ret = register_ftrace_graph(&irqsoff_graph_return,
					    &irqsoff_graph_entry);
549
	else
550
		ret = register_ftrace_function(tr->ops);
551 552 553 554 555 556 557

	if (!ret)
		function_enabled = true;

	return ret;
}

558
static void unregister_irqsoff_function(struct trace_array *tr, int graph)
559 560 561 562 563 564 565
{
	if (!function_enabled)
		return;

	if (graph)
		unregister_ftrace_graph();
	else
566
		unregister_ftrace_function(tr->ops);
567 568 569 570

	function_enabled = false;
}

571
static int irqsoff_function_set(struct trace_array *tr, u32 mask, int set)
572
{
573 574 575
	if (!(mask & TRACE_ITER_FUNCTION))
		return 0;

576
	if (set)
577
		register_irqsoff_function(tr, is_graph(tr), 1);
578
	else
579
		unregister_irqsoff_function(tr, is_graph(tr));
580 581 582 583 584
	return 1;
}
#else
static int register_irqsoff_function(struct trace_array *tr, int graph, int set)
{
585
	return 0;
586
}
587 588 589 590 591 592
static void unregister_irqsoff_function(struct trace_array *tr, int graph) { }
static inline int irqsoff_function_set(struct trace_array *tr, u32 mask, int set)
{
	return 0;
}
#endif /* CONFIG_FUNCTION_TRACER */
593

594
static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set)
595
{
596 597
	struct tracer *tracer = tr->current_trace;

598 599
	if (irqsoff_function_set(tr, mask, set))
		return 0;
600

601
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
602 603
	if (mask & TRACE_ITER_DISPLAY_GRAPH)
		return irqsoff_display_graph(tr, set);
604
#endif
605 606 607 608 609 610 611 612

	return trace_keep_overwrite(tracer, mask, set);
}

static int start_irqsoff_tracer(struct trace_array *tr, int graph)
{
	int ret;

613
	ret = register_irqsoff_function(tr, graph, 0);
614 615

	if (!ret && tracing_is_enabled())
616
		tracer_enabled = 1;
617
	else
618
		tracer_enabled = 0;
619 620

	return ret;
621 622
}

623
static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
624 625
{
	tracer_enabled = 0;
626

627
	unregister_irqsoff_function(tr, graph);
628 629
}

630 631 632
static bool irqsoff_busy;

static int __irqsoff_tracer_init(struct trace_array *tr)
633
{
634 635 636
	if (irqsoff_busy)
		return -EBUSY;

637
	save_flags = tr->trace_flags;
638 639

	/* non overwrite screws up the latency tracers */
640 641
	set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
	set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
642

643
	tr->max_latency = 0;
644
	irqsoff_trace = tr;
645
	/* make sure that the tracer is visible */
646
	smp_wmb();
647

648 649 650 651
	ftrace_init_array_ops(tr, irqsoff_tracer_call);

	/* Only toplevel instance supports graph tracing */
	if (start_irqsoff_tracer(tr, (tr->flags & TRACE_ARRAY_FL_GLOBAL &&
652
				      is_graph(tr))))
653
		printk(KERN_ERR "failed to start irqsoff tracer\n");
654 655 656

	irqsoff_busy = true;
	return 0;
657 658 659 660
}

static void irqsoff_tracer_reset(struct trace_array *tr)
{
661 662 663
	int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
	int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;

664
	stop_irqsoff_tracer(tr, is_graph(tr));
665

666 667
	set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
	set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
668
	ftrace_reset_array_ops(tr);
669 670

	irqsoff_busy = false;
671 672
}

673 674 675 676 677 678 679 680
static void irqsoff_tracer_start(struct trace_array *tr)
{
	tracer_enabled = 1;
}

static void irqsoff_tracer_stop(struct trace_array *tr)
{
	tracer_enabled = 0;
681 682
}

683
#ifdef CONFIG_IRQSOFF_TRACER
684
static int irqsoff_tracer_init(struct trace_array *tr)
685 686 687
{
	trace_type = TRACER_IRQS_OFF;

688
	return __irqsoff_tracer_init(tr);
689
}
690 691 692 693 694
static struct tracer irqsoff_tracer __read_mostly =
{
	.name		= "irqsoff",
	.init		= irqsoff_tracer_init,
	.reset		= irqsoff_tracer_reset,
695 696
	.start		= irqsoff_tracer_start,
	.stop		= irqsoff_tracer_stop,
697
	.print_max	= true,
698 699
	.print_header   = irqsoff_print_header,
	.print_line     = irqsoff_print_line,
700
	.flag_changed	= irqsoff_flag_changed,
Steven Rostedt's avatar
Steven Rostedt committed
701 702 703
#ifdef CONFIG_FTRACE_SELFTEST
	.selftest    = trace_selftest_startup_irqsoff,
#endif
704 705
	.open           = irqsoff_trace_open,
	.close          = irqsoff_trace_close,
706
	.allow_instances = true,
707
	.use_max_tr	= true,
708
};
709 710 711 712 713 714
# define register_irqsoff(trace) register_tracer(&trace)
#else
# define register_irqsoff(trace) do { } while (0)
#endif

#ifdef CONFIG_PREEMPT_TRACER
715
static int preemptoff_tracer_init(struct trace_array *tr)
716 717 718
{
	trace_type = TRACER_PREEMPT_OFF;

719
	return __irqsoff_tracer_init(tr);
720 721 722 723 724 725 726
}

static struct tracer preemptoff_tracer __read_mostly =
{
	.name		= "preemptoff",
	.init		= preemptoff_tracer_init,
	.reset		= irqsoff_tracer_reset,
727 728
	.start		= irqsoff_tracer_start,
	.stop		= irqsoff_tracer_stop,
729
	.print_max	= true,
730 731
	.print_header   = irqsoff_print_header,
	.print_line     = irqsoff_print_line,
732
	.flag_changed	= irqsoff_flag_changed,
Steven Rostedt's avatar
Steven Rostedt committed
733 734 735
#ifdef CONFIG_FTRACE_SELFTEST
	.selftest    = trace_selftest_startup_preemptoff,
#endif
736 737
	.open		= irqsoff_trace_open,
	.close		= irqsoff_trace_close,
738
	.allow_instances = true,
739
	.use_max_tr	= true,
740 741 742 743 744 745 746 747 748
};
# define register_preemptoff(trace) register_tracer(&trace)
#else
# define register_preemptoff(trace) do { } while (0)
#endif

#if defined(CONFIG_IRQSOFF_TRACER) && \
	defined(CONFIG_PREEMPT_TRACER)

749
static int preemptirqsoff_tracer_init(struct trace_array *tr)
750 751 752
{
	trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF;

753
	return __irqsoff_tracer_init(tr);
754 755 756 757 758 759 760
}

static struct tracer preemptirqsoff_tracer __read_mostly =
{
	.name		= "preemptirqsoff",
	.init		= preemptirqsoff_tracer_init,
	.reset		= irqsoff_tracer_reset,
761 762
	.start		= irqsoff_tracer_start,
	.stop		= irqsoff_tracer_stop,
763
	.print_max	= true,
764 765
	.print_header   = irqsoff_print_header,
	.print_line     = irqsoff_print_line,
766
	.flag_changed	= irqsoff_flag_changed,
Steven Rostedt's avatar
Steven Rostedt committed
767 768 769
#ifdef CONFIG_FTRACE_SELFTEST
	.selftest    = trace_selftest_startup_preemptirqsoff,
#endif
770 771
	.open		= irqsoff_trace_open,
	.close		= irqsoff_trace_close,
772
	.allow_instances = true,
773
	.use_max_tr	= true,
774 775 776 777 778 779
};

# define register_preemptirqsoff(trace) register_tracer(&trace)
#else
# define register_preemptirqsoff(trace) do { } while (0)
#endif
780 781 782

__init static int init_irqsoff_tracer(void)
{
783 784 785
	register_irqsoff(irqsoff_tracer);
	register_preemptoff(preemptoff_tracer);
	register_preemptirqsoff(preemptirqsoff_tracer);
786 787 788

	return 0;
}
789
core_initcall(init_irqsoff_tracer);