Skip to content

Commit

Permalink
tracing/ftrace: add the boot tracer
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Frédéric Weisbecker authored and Ingo Molnar committed Oct 14, 2008
1 parent aa5d915 commit d13744c
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 0 deletions.
19 changes: 19 additions & 0 deletions include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#include <linux/linkage.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/types.h>

extern int ftrace_enabled;
extern int
Expand Down Expand Up @@ -209,4 +211,21 @@ ftrace_init_module(unsigned long *start, unsigned long *end) { }
#endif


struct boot_trace {
pid_t caller;
initcall_t func;
int result;
unsigned long long duration;
};

#ifdef CONFIG_BOOT_TRACER
extern void trace_boot(struct boot_trace *it);
extern void start_boot_trace(void);
#else
static inline void trace_boot(struct boot_trace *it) { }
static inline void start_boot_trace(void) { }
#endif



#endif /* _LINUX_FTRACE_H */
4 changes: 4 additions & 0 deletions kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <linux/sched.h>
#include <linux/clocksource.h>
#include <linux/mmiotrace.h>
#include <linux/ftrace.h>

enum trace_type {
__TRACE_FIRST_TYPE = 0,
Expand All @@ -19,6 +20,7 @@ enum trace_type {
TRACE_SPECIAL,
TRACE_MMIO_RW,
TRACE_MMIO_MAP,
TRACE_BOOT,

__TRACE_LAST_TYPE
};
Expand All @@ -30,6 +32,7 @@ struct ftrace_entry {
unsigned long ip;
unsigned long parent_ip;
};
extern struct tracer boot_tracer;

/*
* Context switch trace entry - which task (and prio) we switched from/to:
Expand Down Expand Up @@ -108,6 +111,7 @@ struct trace_field {
struct print_entry print;
struct mmiotrace_rw mmiorw;
struct mmiotrace_map mmiomap;
struct boot_trace initcall;
};
};

Expand Down
101 changes: 101 additions & 0 deletions kernel/trace/trace_boot.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* ring buffer based initcalls tracer
*
* Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
*
*/

#include <linux/init.h>
#include <linux/debugfs.h>
#include <linux/ftrace.h>

#include "trace.h"

static struct trace_array *boot_trace;
static int trace_boot_enabled;


/* Should be started after do_pre_smp_initcalls() in init/main.c */
void start_boot_trace(void)
{
trace_boot_enabled = 1;
}

void stop_boot_trace(struct trace_array *tr)
{
trace_boot_enabled = 0;
}

static void boot_trace_init(struct trace_array *tr)
{
int cpu;
boot_trace = tr;

trace_boot_enabled = 0;

for_each_cpu_mask(cpu, cpu_possible_map)
tracing_reset(tr->data[cpu]);
}

static void boot_trace_ctrl_update(struct trace_array *tr)
{
if (tr->ctrl)
start_boot_trace();
else
stop_boot_trace(tr);
}

static int initcall_print_line(struct trace_iterator *iter)
{
int ret = 1;
struct trace_entry *entry = iter->ent;
struct boot_trace *it = &entry->field.initcall;
struct trace_seq *s = &iter->seq;

if (iter->ent->type == TRACE_BOOT)
ret = trace_seq_printf(s, "%pF called from %i "
"returned %d after %lld msecs\n",
it->func, it->caller, it->result,
it->duration);
if (ret)
return 1;
return 0;
}

struct tracer boot_tracer __read_mostly =
{
.name = "initcall",
.init = boot_trace_init,
.reset = stop_boot_trace,
.ctrl_update = boot_trace_ctrl_update,
.print_line = initcall_print_line,
};


void trace_boot(struct boot_trace *it)
{
struct trace_entry *entry;
struct trace_array_cpu *data;
unsigned long irq_flags;
struct trace_array *tr = boot_trace;

if (!trace_boot_enabled)
return;

preempt_disable();
data = tr->data[smp_processor_id()];

raw_local_irq_save(irq_flags);
__raw_spin_lock(&data->lock);

entry = tracing_get_trace_entry(tr, data);
tracing_generic_entry_update(entry, 0);
entry->type = TRACE_BOOT;
entry->field.initcall = *it;

__raw_spin_unlock(&data->lock);
raw_local_irq_restore(irq_flags);
trace_wake_up();

preempt_enable();
}

0 comments on commit d13744c

Please sign in to comment.