mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
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>
This commit is contained in:
parent
3f5ec13696
commit
7423907283
@ -2,22 +2,30 @@
|
||||
#define _LINUX_TRACE_BOOT_H
|
||||
|
||||
/*
|
||||
* Structure which defines the trace of an initcall.
|
||||
* Structure which defines the trace of an initcall
|
||||
* while it is called.
|
||||
* You don't have to fill the func field since it is
|
||||
* only used internally by the tracer.
|
||||
*/
|
||||
struct boot_trace {
|
||||
struct boot_trace_call {
|
||||
pid_t caller;
|
||||
char func[KSYM_NAME_LEN];
|
||||
int result;
|
||||
unsigned long long duration; /* usecs */
|
||||
ktime_t calltime;
|
||||
ktime_t rettime;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure which defines the trace of an initcall
|
||||
* while it returns.
|
||||
*/
|
||||
struct boot_trace_ret {
|
||||
char func[KSYM_NAME_LEN];
|
||||
int result;
|
||||
unsigned long long duration; /* nsecs */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BOOT_TRACER
|
||||
/* Append the trace on the ring-buffer */
|
||||
extern void trace_boot(struct boot_trace *it, initcall_t fn);
|
||||
/* Append the traces on the ring-buffer */
|
||||
extern void trace_boot_call(struct boot_trace_call *bt, initcall_t fn);
|
||||
extern void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn);
|
||||
|
||||
/* Tells the tracer that smp_pre_initcall is finished.
|
||||
* So we can start the tracing
|
||||
@ -34,7 +42,12 @@ extern void enable_boot_trace(void);
|
||||
*/
|
||||
extern void disable_boot_trace(void);
|
||||
#else
|
||||
static inline void trace_boot(struct boot_trace *it, initcall_t fn) { }
|
||||
static inline
|
||||
void trace_boot_call(struct boot_trace_call *bt, initcall_t fn) { }
|
||||
|
||||
static inline
|
||||
void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn) { }
|
||||
|
||||
static inline void start_boot_trace(void) { }
|
||||
static inline void enable_boot_trace(void) { }
|
||||
static inline void disable_boot_trace(void) { }
|
||||
|
32
init/main.c
32
init/main.c
@ -704,33 +704,35 @@ core_param(initcall_debug, initcall_debug, bool, 0644);
|
||||
int do_one_initcall(initcall_t fn)
|
||||
{
|
||||
int count = preempt_count();
|
||||
ktime_t delta;
|
||||
ktime_t calltime, delta, rettime;
|
||||
char msgbuf[64];
|
||||
struct boot_trace it;
|
||||
struct boot_trace_call call;
|
||||
struct boot_trace_ret ret;
|
||||
|
||||
if (initcall_debug) {
|
||||
it.caller = task_pid_nr(current);
|
||||
printk("calling %pF @ %i\n", fn, it.caller);
|
||||
it.calltime = ktime_get();
|
||||
call.caller = task_pid_nr(current);
|
||||
printk("calling %pF @ %i\n", fn, call.caller);
|
||||
calltime = ktime_get();
|
||||
trace_boot_call(&call, fn);
|
||||
enable_boot_trace();
|
||||
}
|
||||
|
||||
it.result = fn();
|
||||
ret.result = fn();
|
||||
|
||||
if (initcall_debug) {
|
||||
it.rettime = ktime_get();
|
||||
delta = ktime_sub(it.rettime, it.calltime);
|
||||
it.duration = (unsigned long long) delta.tv64 >> 10;
|
||||
printk("initcall %pF returned %d after %Ld usecs\n", fn,
|
||||
it.result, it.duration);
|
||||
trace_boot(&it, fn);
|
||||
disable_boot_trace();
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
ret.duration = (unsigned long long) delta.tv64 >> 10;
|
||||
trace_boot_ret(&ret, fn);
|
||||
printk("initcall %pF returned %d after %Ld usecs\n", fn,
|
||||
ret.result, ret.duration);
|
||||
}
|
||||
|
||||
msgbuf[0] = 0;
|
||||
|
||||
if (it.result && it.result != -ENODEV && initcall_debug)
|
||||
sprintf(msgbuf, "error code %d ", it.result);
|
||||
if (ret.result && ret.result != -ENODEV && initcall_debug)
|
||||
sprintf(msgbuf, "error code %d ", ret.result);
|
||||
|
||||
if (preempt_count() != count) {
|
||||
strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
|
||||
@ -744,7 +746,7 @@ int do_one_initcall(initcall_t fn)
|
||||
printk("initcall %pF returned with %s\n", fn, msgbuf);
|
||||
}
|
||||
|
||||
return it.result;
|
||||
return ret.result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,8 @@ enum trace_type {
|
||||
TRACE_SPECIAL,
|
||||
TRACE_MMIO_RW,
|
||||
TRACE_MMIO_MAP,
|
||||
TRACE_BOOT,
|
||||
TRACE_BOOT_CALL,
|
||||
TRACE_BOOT_RET,
|
||||
TRACE_FN_RET,
|
||||
|
||||
__TRACE_LAST_TYPE
|
||||
@ -123,9 +124,14 @@ struct trace_mmiotrace_map {
|
||||
struct mmiotrace_map map;
|
||||
};
|
||||
|
||||
struct trace_boot {
|
||||
struct trace_boot_call {
|
||||
struct trace_entry ent;
|
||||
struct boot_trace initcall;
|
||||
struct boot_trace_call boot_call;
|
||||
};
|
||||
|
||||
struct trace_boot_ret {
|
||||
struct trace_entry ent;
|
||||
struct boot_trace_ret boot_ret;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -228,8 +234,9 @@ extern void __ftrace_bad_type(void);
|
||||
TRACE_MMIO_RW); \
|
||||
IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \
|
||||
TRACE_MMIO_MAP); \
|
||||
IF_ASSIGN(var, ent, struct trace_boot, TRACE_BOOT); \
|
||||
IF_ASSIGN(var, ent, struct ftrace_ret_entry, TRACE_FN_RET); \
|
||||
IF_ASSIGN(var, ent, struct trace_boot_call, TRACE_BOOT_CALL);\
|
||||
IF_ASSIGN(var, ent, struct trace_boot_ret, TRACE_BOOT_RET);\
|
||||
IF_ASSIGN(var, ent, struct ftrace_ret_entry, TRACE_FN_RET);\
|
||||
__ftrace_bad_type(); \
|
||||
} while (0)
|
||||
|
||||
|
@ -58,35 +58,71 @@ static void boot_trace_init(struct trace_array *tr)
|
||||
tracing_sched_switch_assign_trace(tr);
|
||||
}
|
||||
|
||||
static enum print_line_t
|
||||
initcall_call_print_line(struct trace_iterator *iter)
|
||||
{
|
||||
struct trace_entry *entry = iter->ent;
|
||||
struct trace_seq *s = &iter->seq;
|
||||
struct trace_boot_call *field;
|
||||
struct boot_trace_call *call;
|
||||
u64 ts;
|
||||
unsigned long nsec_rem;
|
||||
int ret;
|
||||
|
||||
trace_assign_type(field, entry);
|
||||
call = &field->boot_call;
|
||||
ts = iter->ts;
|
||||
nsec_rem = do_div(ts, 1000000000);
|
||||
|
||||
ret = trace_seq_printf(s, "[%5ld.%09ld] calling %s @ %i\n",
|
||||
(unsigned long)ts, nsec_rem, call->func, call->caller);
|
||||
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
else
|
||||
return TRACE_TYPE_HANDLED;
|
||||
}
|
||||
|
||||
static enum print_line_t
|
||||
initcall_ret_print_line(struct trace_iterator *iter)
|
||||
{
|
||||
struct trace_entry *entry = iter->ent;
|
||||
struct trace_seq *s = &iter->seq;
|
||||
struct trace_boot_ret *field;
|
||||
struct boot_trace_ret *init_ret;
|
||||
u64 ts;
|
||||
unsigned long nsec_rem;
|
||||
int ret;
|
||||
|
||||
trace_assign_type(field, entry);
|
||||
init_ret = &field->boot_ret;
|
||||
ts = iter->ts;
|
||||
nsec_rem = do_div(ts, 1000000000);
|
||||
|
||||
ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s "
|
||||
"returned %d after %llu msecs\n",
|
||||
(unsigned long) ts,
|
||||
nsec_rem,
|
||||
init_ret->func, init_ret->result, init_ret->duration);
|
||||
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
else
|
||||
return TRACE_TYPE_HANDLED;
|
||||
}
|
||||
|
||||
static enum print_line_t initcall_print_line(struct trace_iterator *iter)
|
||||
{
|
||||
int ret;
|
||||
struct trace_entry *entry = iter->ent;
|
||||
struct trace_boot *field = (struct trace_boot *)entry;
|
||||
struct boot_trace *it = &field->initcall;
|
||||
struct trace_seq *s = &iter->seq;
|
||||
struct timespec calltime = ktime_to_timespec(it->calltime);
|
||||
struct timespec rettime = ktime_to_timespec(it->rettime);
|
||||
|
||||
if (entry->type == TRACE_BOOT) {
|
||||
ret = trace_seq_printf(s, "[%5ld.%09ld] calling %s @ %i\n",
|
||||
calltime.tv_sec,
|
||||
calltime.tv_nsec,
|
||||
it->func, it->caller);
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s "
|
||||
"returned %d after %lld msecs\n",
|
||||
rettime.tv_sec,
|
||||
rettime.tv_nsec,
|
||||
it->func, it->result, it->duration);
|
||||
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
return TRACE_TYPE_HANDLED;
|
||||
switch (entry->type) {
|
||||
case TRACE_BOOT_CALL:
|
||||
return initcall_call_print_line(iter);
|
||||
case TRACE_BOOT_RET:
|
||||
return initcall_ret_print_line(iter);
|
||||
default:
|
||||
return TRACE_TYPE_UNHANDLED;
|
||||
}
|
||||
return TRACE_TYPE_UNHANDLED;
|
||||
}
|
||||
|
||||
struct tracer boot_tracer __read_mostly =
|
||||
@ -97,11 +133,10 @@ struct tracer boot_tracer __read_mostly =
|
||||
.print_line = initcall_print_line,
|
||||
};
|
||||
|
||||
void trace_boot(struct boot_trace *it, initcall_t fn)
|
||||
void trace_boot_call(struct boot_trace_call *bt, initcall_t fn)
|
||||
{
|
||||
struct ring_buffer_event *event;
|
||||
struct trace_boot *entry;
|
||||
struct trace_array_cpu *data;
|
||||
struct trace_boot_call *entry;
|
||||
unsigned long irq_flags;
|
||||
struct trace_array *tr = boot_trace;
|
||||
|
||||
@ -111,9 +146,8 @@ void trace_boot(struct boot_trace *it, initcall_t fn)
|
||||
/* Get its name now since this function could
|
||||
* disappear because it is in the .init section.
|
||||
*/
|
||||
sprint_symbol(it->func, (unsigned long)fn);
|
||||
sprint_symbol(bt->func, (unsigned long)fn);
|
||||
preempt_disable();
|
||||
data = tr->data[smp_processor_id()];
|
||||
|
||||
event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
|
||||
&irq_flags);
|
||||
@ -121,8 +155,37 @@ void trace_boot(struct boot_trace *it, initcall_t fn)
|
||||
goto out;
|
||||
entry = ring_buffer_event_data(event);
|
||||
tracing_generic_entry_update(&entry->ent, 0, 0);
|
||||
entry->ent.type = TRACE_BOOT;
|
||||
entry->initcall = *it;
|
||||
entry->ent.type = TRACE_BOOT_CALL;
|
||||
entry->boot_call = *bt;
|
||||
ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
|
||||
|
||||
trace_wake_up();
|
||||
|
||||
out:
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn)
|
||||
{
|
||||
struct ring_buffer_event *event;
|
||||
struct trace_boot_ret *entry;
|
||||
unsigned long irq_flags;
|
||||
struct trace_array *tr = boot_trace;
|
||||
|
||||
if (!pre_initcalls_finished)
|
||||
return;
|
||||
|
||||
sprint_symbol(bt->func, (unsigned long)fn);
|
||||
preempt_disable();
|
||||
|
||||
event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
|
||||
&irq_flags);
|
||||
if (!event)
|
||||
goto out;
|
||||
entry = ring_buffer_event_data(event);
|
||||
tracing_generic_entry_update(&entry->ent, 0, 0);
|
||||
entry->ent.type = TRACE_BOOT_RET;
|
||||
entry->boot_ret = *bt;
|
||||
ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
|
||||
|
||||
trace_wake_up();
|
||||
|
Loading…
Reference in New Issue
Block a user