aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2008-11-11 17:24:42 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-12 04:17:19 -0500
commit74239072830ef3f1398edeb1bc1076fc330fd4a2 (patch)
tree60a244c6c88d9943760ded98a1a29ce018292107
parent3f5ec13696fd4a33bde42f385406cbb1d3cc96fd (diff)
tracing/fastboot: Use the ring-buffer timestamp for initcall entries
Impact: Split the boot tracer entries in two parts: call and return Now that we are using the sched tracer from the boot tracer, we want to use the same timestamp than the ring-buffer to have consistent time captures between sched events and initcall events. So we get rid of the old time capture by the boot tracer and split the initcall events in two parts: call and return. This way we have the ring buffer timestamp of both. An example trace: [ 27.904149584] calling net_ns_init+0x0/0x1c0 @ 1 [ 27.904429624] initcall net_ns_init+0x0/0x1c0 returned 0 after 0 msecs [ 27.904575926] calling reboot_init+0x0/0x20 @ 1 [ 27.904655399] initcall reboot_init+0x0/0x20 returned 0 after 0 msecs [ 27.904800228] calling sysctl_init+0x0/0x30 @ 1 [ 27.905142914] initcall sysctl_init+0x0/0x30 returned 0 after 0 msecs [ 27.905287211] calling ksysfs_init+0x0/0xb0 @ 1 ##### CPU 0 buffer started #### init-1 [000] 27.905395: 1:120:R + [001] 11:115:S ##### CPU 1 buffer started #### <idle>-0 [001] 27.905425: 0:140:R ==> [001] 11:115:R init-1 [000] 27.905426: 1:120:D ==> [000] 0:140:R <idle>-0 [000] 27.905431: 0:140:R + [000] 4:115:S <idle>-0 [000] 27.905451: 0:140:R ==> [000] 4:115:R ksoftirqd/0-4 [000] 27.905456: 4:115:S ==> [000] 0:140:R udevd-11 [001] 27.905458: 11:115:R + [001] 14:115:R <idle>-0 [000] 27.905459: 0:140:R + [000] 4:115:S <idle>-0 [000] 27.905462: 0:140:R ==> [000] 4:115:R udevd-11 [001] 27.905462: 11:115:R ==> [001] 14:115:R ksoftirqd/0-4 [000] 27.905467: 4:115:S ==> [000] 0:140:R <idle>-0 [000] 27.905470: 0:140:R + [000] 4:115:S <idle>-0 [000] 27.905473: 0:140:R ==> [000] 4:115:R ksoftirqd/0-4 [000] 27.905476: 4:115:S ==> [000] 0:140:R <idle>-0 [000] 27.905479: 0:140:R + [000] 4:115:S <idle>-0 [000] 27.905482: 0:140:R ==> [000] 4:115:R ksoftirqd/0-4 [000] 27.905486: 4:115:S ==> [000] 0:140:R udevd-14 [001] 27.905499: 14:120:X ==> [001] 11:115:R udevd-11 [001] 27.905506: 11:115:R + [000] 1:120:D <idle>-0 [000] 27.905515: 0:140:R ==> [000] 1:120:R udevd-11 [001] 27.905517: 11:115:S ==> [001] 0:140:R [ 27.905557107] initcall ksysfs_init+0x0/0xb0 returned 0 after 3906 msecs [ 27.905705736] calling init_jiffies_clocksource+0x0/0x10 @ 1 [ 27.905779239] initcall init_jiffies_clocksource+0x0/0x10 returned 0 after 0 msecs [ 27.906769814] calling pm_init+0x0/0x30 @ 1 [ 27.906853627] initcall pm_init+0x0/0x30 returned 0 after 0 msecs [ 27.906997803] calling pm_disk_init+0x0/0x20 @ 1 [ 27.907076946] initcall pm_disk_init+0x0/0x20 returned 0 after 0 msecs [ 27.907222556] calling swsusp_header_init+0x0/0x30 @ 1 [ 27.907294325] initcall swsusp_header_init+0x0/0x30 returned 0 after 0 msecs [ 27.907439620] calling stop_machine_init+0x0/0x50 @ 1 init-1 [000] 27.907485: 1:120:R + [000] 2:115:S init-1 [000] 27.907490: 1:120:D ==> [000] 2:115:R kthreadd-2 [000] 27.907507: 2:115:R + [001] 15:115:R <idle>-0 [001] 27.907517: 0:140:R ==> [001] 15:115:R kthreadd-2 [000] 27.907517: 2:115:D ==> [000] 0:140:R <idle>-0 [000] 27.907521: 0:140:R + [000] 4:115:S <idle>-0 [000] 27.907524: 0:140:R ==> [000] 4:115:R udevd-15 [001] 27.907527: 15:115:D + [000] 2:115:D ksoftirqd/0-4 [000] 27.907537: 4:115:S ==> [000] 2:115:R udevd-15 [001] 27.907537: 15:115:D ==> [001] 0:140:R kthreadd-2 [000] 27.907546: 2:115:R + [000] 1:120:D kthreadd-2 [000] 27.907550: 2:115:S ==> [000] 1:120:R init-1 [000] 27.907584: 1:120:R + [000] 15: 0:D init-1 [000] 27.907589: 1:120:R + [000] 2:115:S init-1 [000] 27.907593: 1:120:D ==> [000] 15: 0:R udevd-15 [000] 27.907601: 15: 0:S ==> [000] 2:115:R ##### CPU 0 buffer started #### kthreadd-2 [000] 27.907616: 2:115:R + [001] 16:115:R ##### CPU 1 buffer started #### <idle>-0 [001] 27.907620: 0:140:R ==> [001] 16:115:R kthreadd-2 [000] 27.907621: 2:115:D ==> [000] 0:140:R udevd-16 [001] 27.907625: 16:115:D + [000] 2:115:D <idle>-0 [000] 27.907628: 0:140:R + [000] 4:115:S udevd-16 [001] 27.907629: 16:115:D ==> [001] 0:140:R <idle>-0 [000] 27.907631: 0:140:R ==> [000] 4:115:R ksoftirqd/0-4 [000] 27.907636: 4:115:S ==> [000] 2:115:R kthreadd-2 [000] 27.907644: 2:115:R + [000] 1:120:D kthreadd-2 [000] 27.907647: 2:115:S ==> [000] 1:120:R init-1 [000] 27.907657: 1:120:R + [001] 16: 0:D <idle>-0 [001] 27.907666: 0:140:R ==> [001] 16: 0:R [ 27.907703862] initcall stop_machine_init+0x0/0x50 returned 0 after 0 msecs [ 27.907850704] calling filelock_init+0x0/0x30 @ 1 [ 27.907926573] initcall filelock_init+0x0/0x30 returned 0 after 0 msecs [ 27.908071327] calling init_script_binfmt+0x0/0x10 @ 1 [ 27.908165195] initcall init_script_binfmt+0x0/0x10 returned 0 after 0 msecs [ 27.908309461] calling init_elf_binfmt+0x0/0x10 @ 1 Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--include/trace/boot.h31
-rw-r--r--init/main.c32
-rw-r--r--kernel/trace/trace.h17
-rw-r--r--kernel/trace/trace_boot.c123
4 files changed, 144 insertions, 59 deletions
diff --git a/include/trace/boot.h b/include/trace/boot.h
index 4cbe64e46cdc..6b54537eab02 100644
--- a/include/trace/boot.h
+++ b/include/trace/boot.h
@@ -2,22 +2,30 @@
2#define _LINUX_TRACE_BOOT_H 2#define _LINUX_TRACE_BOOT_H
3 3
4/* 4/*
5 * Structure which defines the trace of an initcall. 5 * Structure which defines the trace of an initcall
6 * while it is called.
6 * You don't have to fill the func field since it is 7 * You don't have to fill the func field since it is
7 * only used internally by the tracer. 8 * only used internally by the tracer.
8 */ 9 */
9struct boot_trace { 10struct boot_trace_call {
10 pid_t caller; 11 pid_t caller;
11 char func[KSYM_NAME_LEN]; 12 char func[KSYM_NAME_LEN];
12 int result; 13};
13 unsigned long long duration; /* usecs */ 14
14 ktime_t calltime; 15/*
15 ktime_t rettime; 16 * Structure which defines the trace of an initcall
17 * while it returns.
18 */
19struct boot_trace_ret {
20 char func[KSYM_NAME_LEN];
21 int result;
22 unsigned long long duration; /* nsecs */
16}; 23};
17 24
18#ifdef CONFIG_BOOT_TRACER 25#ifdef CONFIG_BOOT_TRACER
19/* Append the trace on the ring-buffer */ 26/* Append the traces on the ring-buffer */
20extern void trace_boot(struct boot_trace *it, initcall_t fn); 27extern void trace_boot_call(struct boot_trace_call *bt, initcall_t fn);
28extern void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn);
21 29
22/* Tells the tracer that smp_pre_initcall is finished. 30/* Tells the tracer that smp_pre_initcall is finished.
23 * So we can start the tracing 31 * So we can start the tracing
@@ -34,7 +42,12 @@ extern void enable_boot_trace(void);
34 */ 42 */
35extern void disable_boot_trace(void); 43extern void disable_boot_trace(void);
36#else 44#else
37static inline void trace_boot(struct boot_trace *it, initcall_t fn) { } 45static inline
46void trace_boot_call(struct boot_trace_call *bt, initcall_t fn) { }
47
48static inline
49void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn) { }
50
38static inline void start_boot_trace(void) { } 51static inline void start_boot_trace(void) { }
39static inline void enable_boot_trace(void) { } 52static inline void enable_boot_trace(void) { }
40static inline void disable_boot_trace(void) { } 53static inline void disable_boot_trace(void) { }
diff --git a/init/main.c b/init/main.c
index 16ca1ee071c4..e810196bf2f2 100644
--- a/init/main.c
+++ b/init/main.c
@@ -704,33 +704,35 @@ core_param(initcall_debug, initcall_debug, bool, 0644);
704int do_one_initcall(initcall_t fn) 704int do_one_initcall(initcall_t fn)
705{ 705{
706 int count = preempt_count(); 706 int count = preempt_count();
707 ktime_t delta; 707 ktime_t calltime, delta, rettime;
708 char msgbuf[64]; 708 char msgbuf[64];
709 struct boot_trace it; 709 struct boot_trace_call call;
710 struct boot_trace_ret ret;
710 711
711 if (initcall_debug) { 712 if (initcall_debug) {
712 it.caller = task_pid_nr(current); 713 call.caller = task_pid_nr(current);
713 printk("calling %pF @ %i\n", fn, it.caller); 714 printk("calling %pF @ %i\n", fn, call.caller);
714 it.calltime = ktime_get(); 715 calltime = ktime_get();
716 trace_boot_call(&call, fn);
715 enable_boot_trace(); 717 enable_boot_trace();
716 } 718 }
717 719
718 it.result = fn(); 720 ret.result = fn();
719 721
720 if (initcall_debug) { 722 if (initcall_debug) {
721 it.rettime = ktime_get();
722 delta = ktime_sub(it.rettime, it.calltime);
723 it.duration = (unsigned long long) delta.tv64 >> 10;
724 printk("initcall %pF returned %d after %Ld usecs\n", fn,
725 it.result, it.duration);
726 trace_boot(&it, fn);
727 disable_boot_trace(); 723 disable_boot_trace();
724 rettime = ktime_get();
725 delta = ktime_sub(rettime, calltime);
726 ret.duration = (unsigned long long) delta.tv64 >> 10;
727 trace_boot_ret(&ret, fn);
728 printk("initcall %pF returned %d after %Ld usecs\n", fn,
729 ret.result, ret.duration);
728 } 730 }
729 731
730 msgbuf[0] = 0; 732 msgbuf[0] = 0;
731 733
732 if (it.result && it.result != -ENODEV && initcall_debug) 734 if (ret.result && ret.result != -ENODEV && initcall_debug)
733 sprintf(msgbuf, "error code %d ", it.result); 735 sprintf(msgbuf, "error code %d ", ret.result);
734 736
735 if (preempt_count() != count) { 737 if (preempt_count() != count) {
736 strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf)); 738 strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
@@ -744,7 +746,7 @@ int do_one_initcall(initcall_t fn)
744 printk("initcall %pF returned with %s\n", fn, msgbuf); 746 printk("initcall %pF returned with %s\n", fn, msgbuf);
745 } 747 }
746 748
747 return it.result; 749 return ret.result;
748} 750}
749 751
750 752
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index f69a5199596b..b5f91f198fd4 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -22,7 +22,8 @@ enum trace_type {
22 TRACE_SPECIAL, 22 TRACE_SPECIAL,
23 TRACE_MMIO_RW, 23 TRACE_MMIO_RW,
24 TRACE_MMIO_MAP, 24 TRACE_MMIO_MAP,
25 TRACE_BOOT, 25 TRACE_BOOT_CALL,
26 TRACE_BOOT_RET,
26 TRACE_FN_RET, 27 TRACE_FN_RET,
27 28
28 __TRACE_LAST_TYPE 29 __TRACE_LAST_TYPE
@@ -123,9 +124,14 @@ struct trace_mmiotrace_map {
123 struct mmiotrace_map map; 124 struct mmiotrace_map map;
124}; 125};
125 126
126struct trace_boot { 127struct trace_boot_call {
127 struct trace_entry ent; 128 struct trace_entry ent;
128 struct boot_trace initcall; 129 struct boot_trace_call boot_call;
130};
131
132struct trace_boot_ret {
133 struct trace_entry ent;
134 struct boot_trace_ret boot_ret;
129}; 135};
130 136
131/* 137/*
@@ -228,8 +234,9 @@ extern void __ftrace_bad_type(void);
228 TRACE_MMIO_RW); \ 234 TRACE_MMIO_RW); \
229 IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \ 235 IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \
230 TRACE_MMIO_MAP); \ 236 TRACE_MMIO_MAP); \
231 IF_ASSIGN(var, ent, struct trace_boot, TRACE_BOOT); \ 237 IF_ASSIGN(var, ent, struct trace_boot_call, TRACE_BOOT_CALL);\
232 IF_ASSIGN(var, ent, struct ftrace_ret_entry, TRACE_FN_RET); \ 238 IF_ASSIGN(var, ent, struct trace_boot_ret, TRACE_BOOT_RET);\
239 IF_ASSIGN(var, ent, struct ftrace_ret_entry, TRACE_FN_RET);\
233 __ftrace_bad_type(); \ 240 __ftrace_bad_type(); \
234 } while (0) 241 } while (0)
235 242
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
index 8f71915e8bb4..cb333b7fd113 100644
--- a/kernel/trace/trace_boot.c
+++ b/kernel/trace/trace_boot.c
@@ -58,35 +58,71 @@ static void boot_trace_init(struct trace_array *tr)
58 tracing_sched_switch_assign_trace(tr); 58 tracing_sched_switch_assign_trace(tr);
59} 59}
60 60
61static enum print_line_t initcall_print_line(struct trace_iterator *iter) 61static enum print_line_t
62initcall_call_print_line(struct trace_iterator *iter)
62{ 63{
64 struct trace_entry *entry = iter->ent;
65 struct trace_seq *s = &iter->seq;
66 struct trace_boot_call *field;
67 struct boot_trace_call *call;
68 u64 ts;
69 unsigned long nsec_rem;
63 int ret; 70 int ret;
71
72 trace_assign_type(field, entry);
73 call = &field->boot_call;
74 ts = iter->ts;
75 nsec_rem = do_div(ts, 1000000000);
76
77 ret = trace_seq_printf(s, "[%5ld.%09ld] calling %s @ %i\n",
78 (unsigned long)ts, nsec_rem, call->func, call->caller);
79
80 if (!ret)
81 return TRACE_TYPE_PARTIAL_LINE;
82 else
83 return TRACE_TYPE_HANDLED;
84}
85
86static enum print_line_t
87initcall_ret_print_line(struct trace_iterator *iter)
88{
64 struct trace_entry *entry = iter->ent; 89 struct trace_entry *entry = iter->ent;
65 struct trace_boot *field = (struct trace_boot *)entry;
66 struct boot_trace *it = &field->initcall;
67 struct trace_seq *s = &iter->seq; 90 struct trace_seq *s = &iter->seq;
68 struct timespec calltime = ktime_to_timespec(it->calltime); 91 struct trace_boot_ret *field;
69 struct timespec rettime = ktime_to_timespec(it->rettime); 92 struct boot_trace_ret *init_ret;
70 93 u64 ts;
71 if (entry->type == TRACE_BOOT) { 94 unsigned long nsec_rem;
72 ret = trace_seq_printf(s, "[%5ld.%09ld] calling %s @ %i\n", 95 int ret;
73 calltime.tv_sec, 96
74 calltime.tv_nsec, 97 trace_assign_type(field, entry);
75 it->func, it->caller); 98 init_ret = &field->boot_ret;
76 if (!ret) 99 ts = iter->ts;
77 return TRACE_TYPE_PARTIAL_LINE; 100 nsec_rem = do_div(ts, 1000000000);
78 101
79 ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s " 102 ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s "
80 "returned %d after %lld msecs\n", 103 "returned %d after %llu msecs\n",
81 rettime.tv_sec, 104 (unsigned long) ts,
82 rettime.tv_nsec, 105 nsec_rem,
83 it->func, it->result, it->duration); 106 init_ret->func, init_ret->result, init_ret->duration);
84 107
85 if (!ret) 108 if (!ret)
86 return TRACE_TYPE_PARTIAL_LINE; 109 return TRACE_TYPE_PARTIAL_LINE;
110 else
87 return TRACE_TYPE_HANDLED; 111 return TRACE_TYPE_HANDLED;
112}
113
114static enum print_line_t initcall_print_line(struct trace_iterator *iter)
115{
116 struct trace_entry *entry = iter->ent;
117
118 switch (entry->type) {
119 case TRACE_BOOT_CALL:
120 return initcall_call_print_line(iter);
121 case TRACE_BOOT_RET:
122 return initcall_ret_print_line(iter);
123 default:
124 return TRACE_TYPE_UNHANDLED;
88 } 125 }
89 return TRACE_TYPE_UNHANDLED;
90} 126}
91 127
92struct tracer boot_tracer __read_mostly = 128struct tracer boot_tracer __read_mostly =
@@ -97,11 +133,10 @@ struct tracer boot_tracer __read_mostly =
97 .print_line = initcall_print_line, 133 .print_line = initcall_print_line,
98}; 134};
99 135
100void trace_boot(struct boot_trace *it, initcall_t fn) 136void trace_boot_call(struct boot_trace_call *bt, initcall_t fn)
101{ 137{
102 struct ring_buffer_event *event; 138 struct ring_buffer_event *event;
103 struct trace_boot *entry; 139 struct trace_boot_call *entry;
104 struct trace_array_cpu *data;
105 unsigned long irq_flags; 140 unsigned long irq_flags;
106 struct trace_array *tr = boot_trace; 141 struct trace_array *tr = boot_trace;
107 142
@@ -111,9 +146,37 @@ void trace_boot(struct boot_trace *it, initcall_t fn)
111 /* Get its name now since this function could 146 /* Get its name now since this function could
112 * disappear because it is in the .init section. 147 * disappear because it is in the .init section.
113 */ 148 */
114 sprint_symbol(it->func, (unsigned long)fn); 149 sprint_symbol(bt->func, (unsigned long)fn);
150 preempt_disable();
151
152 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
153 &irq_flags);
154 if (!event)
155 goto out;
156 entry = ring_buffer_event_data(event);
157 tracing_generic_entry_update(&entry->ent, 0, 0);
158 entry->ent.type = TRACE_BOOT_CALL;
159 entry->boot_call = *bt;
160 ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
161
162 trace_wake_up();
163
164 out:
165 preempt_enable();
166}
167
168void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn)
169{
170 struct ring_buffer_event *event;
171 struct trace_boot_ret *entry;
172 unsigned long irq_flags;
173 struct trace_array *tr = boot_trace;
174
175 if (!pre_initcalls_finished)
176 return;
177
178 sprint_symbol(bt->func, (unsigned long)fn);
115 preempt_disable(); 179 preempt_disable();
116 data = tr->data[smp_processor_id()];
117 180
118 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), 181 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
119 &irq_flags); 182 &irq_flags);
@@ -121,8 +184,8 @@ void trace_boot(struct boot_trace *it, initcall_t fn)
121 goto out; 184 goto out;
122 entry = ring_buffer_event_data(event); 185 entry = ring_buffer_event_data(event);
123 tracing_generic_entry_update(&entry->ent, 0, 0); 186 tracing_generic_entry_update(&entry->ent, 0, 0);
124 entry->ent.type = TRACE_BOOT; 187 entry->ent.type = TRACE_BOOT_RET;
125 entry->initcall = *it; 188 entry->boot_ret = *bt;
126 ring_buffer_unlock_commit(tr->buffer, event, irq_flags); 189 ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
127 190
128 trace_wake_up(); 191 trace_wake_up();