aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorFrédéric Weisbecker <fweisbec@gmail.com>2008-09-23 06:32:08 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-14 04:38:47 -0400
commitd13744cd6e3fef373a3fe656ac349b4e7c49ff79 (patch)
tree7315ec5390bd4977ecf5d0b25d7ec5cf0440236a /kernel
parentaa5d9151f745b6ee6a236a1f109118034277eb92 (diff)
tracing/ftrace: add the boot tracer
Add the boot/initcall tracer. It's primary purpose is to be able to trace the initcalls. It is intended to be used with scripts/bootgraph.pl after some small improvements. Note that it is not active after its init. To avoid tracing (and so crashing) before the whole tracing engine init, you have to explicitly call start_boot_trace() after do_pre_smp_initcalls() to enable it. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace.h4
-rw-r--r--kernel/trace/trace_boot.c101
2 files changed, 105 insertions, 0 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index cb2c3fb7dd54..b28bf8812efc 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -6,6 +6,7 @@
6#include <linux/sched.h> 6#include <linux/sched.h>
7#include <linux/clocksource.h> 7#include <linux/clocksource.h>
8#include <linux/mmiotrace.h> 8#include <linux/mmiotrace.h>
9#include <linux/ftrace.h>
9 10
10enum trace_type { 11enum trace_type {
11 __TRACE_FIRST_TYPE = 0, 12 __TRACE_FIRST_TYPE = 0,
@@ -19,6 +20,7 @@ enum trace_type {
19 TRACE_SPECIAL, 20 TRACE_SPECIAL,
20 TRACE_MMIO_RW, 21 TRACE_MMIO_RW,
21 TRACE_MMIO_MAP, 22 TRACE_MMIO_MAP,
23 TRACE_BOOT,
22 24
23 __TRACE_LAST_TYPE 25 __TRACE_LAST_TYPE
24}; 26};
@@ -30,6 +32,7 @@ struct ftrace_entry {
30 unsigned long ip; 32 unsigned long ip;
31 unsigned long parent_ip; 33 unsigned long parent_ip;
32}; 34};
35extern struct tracer boot_tracer;
33 36
34/* 37/*
35 * Context switch trace entry - which task (and prio) we switched from/to: 38 * Context switch trace entry - which task (and prio) we switched from/to:
@@ -108,6 +111,7 @@ struct trace_field {
108 struct print_entry print; 111 struct print_entry print;
109 struct mmiotrace_rw mmiorw; 112 struct mmiotrace_rw mmiorw;
110 struct mmiotrace_map mmiomap; 113 struct mmiotrace_map mmiomap;
114 struct boot_trace initcall;
111 }; 115 };
112}; 116};
113 117
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
new file mode 100644
index 000000000000..c65ef8ffd6b4
--- /dev/null
+++ b/kernel/trace/trace_boot.c
@@ -0,0 +1,101 @@
1/*
2 * ring buffer based initcalls tracer
3 *
4 * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
5 *
6 */
7
8#include <linux/init.h>
9#include <linux/debugfs.h>
10#include <linux/ftrace.h>
11
12#include "trace.h"
13
14static struct trace_array *boot_trace;
15static int trace_boot_enabled;
16
17
18/* Should be started after do_pre_smp_initcalls() in init/main.c */
19void start_boot_trace(void)
20{
21 trace_boot_enabled = 1;
22}
23
24void stop_boot_trace(struct trace_array *tr)
25{
26 trace_boot_enabled = 0;
27}
28
29static void boot_trace_init(struct trace_array *tr)
30{
31 int cpu;
32 boot_trace = tr;
33
34 trace_boot_enabled = 0;
35
36 for_each_cpu_mask(cpu, cpu_possible_map)
37 tracing_reset(tr->data[cpu]);
38}
39
40static void boot_trace_ctrl_update(struct trace_array *tr)
41{
42 if (tr->ctrl)
43 start_boot_trace();
44 else
45 stop_boot_trace(tr);
46}
47
48static int initcall_print_line(struct trace_iterator *iter)
49{
50 int ret = 1;
51 struct trace_entry *entry = iter->ent;
52 struct boot_trace *it = &entry->field.initcall;
53 struct trace_seq *s = &iter->seq;
54
55 if (iter->ent->type == TRACE_BOOT)
56 ret = trace_seq_printf(s, "%pF called from %i "
57 "returned %d after %lld msecs\n",
58 it->func, it->caller, it->result,
59 it->duration);
60 if (ret)
61 return 1;
62 return 0;
63}
64
65struct tracer boot_tracer __read_mostly =
66{
67 .name = "initcall",
68 .init = boot_trace_init,
69 .reset = stop_boot_trace,
70 .ctrl_update = boot_trace_ctrl_update,
71 .print_line = initcall_print_line,
72};
73
74
75void trace_boot(struct boot_trace *it)
76{
77 struct trace_entry *entry;
78 struct trace_array_cpu *data;
79 unsigned long irq_flags;
80 struct trace_array *tr = boot_trace;
81
82 if (!trace_boot_enabled)
83 return;
84
85 preempt_disable();
86 data = tr->data[smp_processor_id()];
87
88 raw_local_irq_save(irq_flags);
89 __raw_spin_lock(&data->lock);
90
91 entry = tracing_get_trace_entry(tr, data);
92 tracing_generic_entry_update(entry, 0);
93 entry->type = TRACE_BOOT;
94 entry->field.initcall = *it;
95
96 __raw_spin_unlock(&data->lock);
97 raw_local_irq_restore(irq_flags);
98 trace_wake_up();
99
100 preempt_enable();
101}