]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
tracing/ftrace: add the boot tracer
authorFrédéric Weisbecker <fweisbec@gmail.com>
Tue, 23 Sep 2008 10:32:08 +0000 (11:32 +0100)
committerIngo Molnar <mingo@elte.hu>
Tue, 14 Oct 2008 08:38:47 +0000 (10:38 +0200)
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>
include/linux/ftrace.h
kernel/trace/trace.h
kernel/trace/trace_boot.c [new file with mode: 0644]

index 5de9903645d57b17aadc17646519d35a755402ae..91954eb6460f9a601fa3a5030286ff6100e377c7 100644 (file)
@@ -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
@@ -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 */
index cb2c3fb7dd54cf2894cd854324fd93bb5638bc45..b28bf8812efcaeef63e7339789b70f6f1440973e 100644 (file)
@@ -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,
@@ -19,6 +20,7 @@ enum trace_type {
        TRACE_SPECIAL,
        TRACE_MMIO_RW,
        TRACE_MMIO_MAP,
+       TRACE_BOOT,
 
        __TRACE_LAST_TYPE
 };
@@ -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:
@@ -108,6 +111,7 @@ struct trace_field {
                struct print_entry              print;
                struct mmiotrace_rw             mmiorw;
                struct mmiotrace_map            mmiomap;
+               struct boot_trace               initcall;
        };
 };
 
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
new file mode 100644 (file)
index 0000000..c65ef8f
--- /dev/null
@@ -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();
+}