2 * ring buffer based initcalls tracer
4 * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
8 #include <linux/init.h>
9 #include <linux/debugfs.h>
10 #include <linux/ftrace.h>
11 #include <linux/kallsyms.h>
15 static struct trace_array
*boot_trace
;
16 static bool pre_initcalls_finished
;
18 /* Tells the boot tracer that the pre_smp_initcalls are finished.
20 * It doesn't enable sched events tracing however.
21 * You have to call enable_boot_trace to do so.
23 void start_boot_trace(void)
25 pre_initcalls_finished
= true;
28 void enable_boot_trace(void)
30 if (pre_initcalls_finished
)
31 tracing_start_sched_switch_record();
34 void disable_boot_trace(void)
36 if (pre_initcalls_finished
)
37 tracing_stop_sched_switch_record();
40 static int boot_trace_init(struct trace_array
*tr
)
45 for_each_cpu(cpu
, cpu_possible_mask
)
46 tracing_reset(tr
, cpu
);
48 tracing_sched_switch_assign_trace(tr
);
52 static enum print_line_t
53 initcall_call_print_line(struct trace_iterator
*iter
)
55 struct trace_entry
*entry
= iter
->ent
;
56 struct trace_seq
*s
= &iter
->seq
;
57 struct trace_boot_call
*field
;
58 struct boot_trace_call
*call
;
60 unsigned long nsec_rem
;
63 trace_assign_type(field
, entry
);
64 call
= &field
->boot_call
;
66 nsec_rem
= do_div(ts
, 1000000000);
68 ret
= trace_seq_printf(s
, "[%5ld.%09ld] calling %s @ %i\n",
69 (unsigned long)ts
, nsec_rem
, call
->func
, call
->caller
);
72 return TRACE_TYPE_PARTIAL_LINE
;
74 return TRACE_TYPE_HANDLED
;
77 static enum print_line_t
78 initcall_ret_print_line(struct trace_iterator
*iter
)
80 struct trace_entry
*entry
= iter
->ent
;
81 struct trace_seq
*s
= &iter
->seq
;
82 struct trace_boot_ret
*field
;
83 struct boot_trace_ret
*init_ret
;
85 unsigned long nsec_rem
;
88 trace_assign_type(field
, entry
);
89 init_ret
= &field
->boot_ret
;
91 nsec_rem
= do_div(ts
, 1000000000);
93 ret
= trace_seq_printf(s
, "[%5ld.%09ld] initcall %s "
94 "returned %d after %llu msecs\n",
97 init_ret
->func
, init_ret
->result
, init_ret
->duration
);
100 return TRACE_TYPE_PARTIAL_LINE
;
102 return TRACE_TYPE_HANDLED
;
105 static enum print_line_t
initcall_print_line(struct trace_iterator
*iter
)
107 struct trace_entry
*entry
= iter
->ent
;
109 switch (entry
->type
) {
110 case TRACE_BOOT_CALL
:
111 return initcall_call_print_line(iter
);
113 return initcall_ret_print_line(iter
);
115 return TRACE_TYPE_UNHANDLED
;
119 struct tracer boot_tracer __read_mostly
=
122 .init
= boot_trace_init
,
123 .reset
= tracing_reset_online_cpus
,
124 .print_line
= initcall_print_line
,
127 void trace_boot_call(struct boot_trace_call
*bt
, initcall_t fn
)
129 struct ring_buffer_event
*event
;
130 struct trace_boot_call
*entry
;
131 unsigned long irq_flags
;
132 struct trace_array
*tr
= boot_trace
;
134 if (!pre_initcalls_finished
)
137 /* Get its name now since this function could
138 * disappear because it is in the .init section.
140 sprint_symbol(bt
->func
, (unsigned long)fn
);
143 event
= ring_buffer_lock_reserve(tr
->buffer
, sizeof(*entry
),
147 entry
= ring_buffer_event_data(event
);
148 tracing_generic_entry_update(&entry
->ent
, 0, 0);
149 entry
->ent
.type
= TRACE_BOOT_CALL
;
150 entry
->boot_call
= *bt
;
151 ring_buffer_unlock_commit(tr
->buffer
, event
, irq_flags
);
159 void trace_boot_ret(struct boot_trace_ret
*bt
, initcall_t fn
)
161 struct ring_buffer_event
*event
;
162 struct trace_boot_ret
*entry
;
163 unsigned long irq_flags
;
164 struct trace_array
*tr
= boot_trace
;
166 if (!pre_initcalls_finished
)
169 sprint_symbol(bt
->func
, (unsigned long)fn
);
172 event
= ring_buffer_lock_reserve(tr
->buffer
, sizeof(*entry
),
176 entry
= ring_buffer_event_data(event
);
177 tracing_generic_entry_update(&entry
->ent
, 0, 0);
178 entry
->ent
.type
= TRACE_BOOT_RET
;
179 entry
->boot_ret
= *bt
;
180 ring_buffer_unlock_commit(tr
->buffer
, event
, irq_flags
);