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>
12 #include <linux/time.h>
15 #include "trace_output.h"
17 static struct trace_array
*boot_trace
;
18 static bool pre_initcalls_finished
;
20 /* Tells the boot tracer that the pre_smp_initcalls are finished.
22 * It doesn't enable sched events tracing however.
23 * You have to call enable_boot_trace to do so.
25 void start_boot_trace(void)
27 pre_initcalls_finished
= true;
30 void enable_boot_trace(void)
32 if (boot_trace
&& pre_initcalls_finished
)
33 tracing_start_sched_switch_record();
36 void disable_boot_trace(void)
38 if (boot_trace
&& pre_initcalls_finished
)
39 tracing_stop_sched_switch_record();
42 static int boot_trace_init(struct trace_array
*tr
)
50 for_each_cpu(cpu
, cpu_possible_mask
)
51 tracing_reset(tr
, cpu
);
53 tracing_sched_switch_assign_trace(tr
);
57 static enum print_line_t
58 initcall_call_print_line(struct trace_iterator
*iter
)
60 struct trace_entry
*entry
= iter
->ent
;
61 struct trace_seq
*s
= &iter
->seq
;
62 struct trace_boot_call
*field
;
63 struct boot_trace_call
*call
;
65 unsigned long nsec_rem
;
68 trace_assign_type(field
, entry
);
69 call
= &field
->boot_call
;
71 nsec_rem
= do_div(ts
, NSEC_PER_SEC
);
73 ret
= trace_seq_printf(s
, "[%5ld.%09ld] calling %s @ %i\n",
74 (unsigned long)ts
, nsec_rem
, call
->func
, call
->caller
);
77 return TRACE_TYPE_PARTIAL_LINE
;
79 return TRACE_TYPE_HANDLED
;
82 static enum print_line_t
83 initcall_ret_print_line(struct trace_iterator
*iter
)
85 struct trace_entry
*entry
= iter
->ent
;
86 struct trace_seq
*s
= &iter
->seq
;
87 struct trace_boot_ret
*field
;
88 struct boot_trace_ret
*init_ret
;
90 unsigned long nsec_rem
;
93 trace_assign_type(field
, entry
);
94 init_ret
= &field
->boot_ret
;
96 nsec_rem
= do_div(ts
, NSEC_PER_SEC
);
98 ret
= trace_seq_printf(s
, "[%5ld.%09ld] initcall %s "
99 "returned %d after %llu msecs\n",
102 init_ret
->func
, init_ret
->result
, init_ret
->duration
);
105 return TRACE_TYPE_PARTIAL_LINE
;
107 return TRACE_TYPE_HANDLED
;
110 static enum print_line_t
initcall_print_line(struct trace_iterator
*iter
)
112 struct trace_entry
*entry
= iter
->ent
;
114 switch (entry
->type
) {
115 case TRACE_BOOT_CALL
:
116 return initcall_call_print_line(iter
);
118 return initcall_ret_print_line(iter
);
120 return TRACE_TYPE_UNHANDLED
;
124 struct tracer boot_tracer __read_mostly
=
127 .init
= boot_trace_init
,
128 .reset
= tracing_reset_online_cpus
,
129 .print_line
= initcall_print_line
,
132 void trace_boot_call(struct boot_trace_call
*bt
, initcall_t fn
)
134 struct ring_buffer_event
*event
;
135 struct trace_boot_call
*entry
;
136 struct trace_array
*tr
= boot_trace
;
138 if (!tr
|| !pre_initcalls_finished
)
141 /* Get its name now since this function could
142 * disappear because it is in the .init section.
144 sprint_symbol(bt
->func
, (unsigned long)fn
);
147 event
= trace_buffer_lock_reserve(tr
, TRACE_BOOT_CALL
,
148 sizeof(*entry
), 0, 0);
151 entry
= ring_buffer_event_data(event
);
152 entry
->boot_call
= *bt
;
153 trace_buffer_unlock_commit(tr
, event
, 0, 0);
158 void trace_boot_ret(struct boot_trace_ret
*bt
, initcall_t fn
)
160 struct ring_buffer_event
*event
;
161 struct trace_boot_ret
*entry
;
162 struct trace_array
*tr
= boot_trace
;
164 if (!tr
|| !pre_initcalls_finished
)
167 sprint_symbol(bt
->func
, (unsigned long)fn
);
170 event
= trace_buffer_lock_reserve(tr
, TRACE_BOOT_RET
,
171 sizeof(*entry
), 0, 0);
174 entry
= ring_buffer_event_data(event
);
175 entry
->boot_ret
= *bt
;
176 trace_buffer_unlock_commit(tr
, event
, 0, 0);