summaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_boot.c
diff options
context:
space:
mode:
authorFrédéric Weisbecker <fweisbec@gmail.com>2008-09-23 11:32:08 +0100
committerIngo Molnar <mingo@elte.hu>2008-10-14 10:38:47 +0200
commitd13744cd6e3fef373a3fe656ac349b4e7c49ff79 (patch)
tree7315ec5390bd4977ecf5d0b25d7ec5cf0440236a /kernel/trace/trace_boot.c
parentaa5d9151f745b6ee6a236a1f109118034277eb92 (diff)
tracing/ftrace: add the boot tracer
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>
Diffstat (limited to 'kernel/trace/trace_boot.c')
-rw-r--r--kernel/trace/trace_boot.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
new file mode 100644
index 00000000000..c65ef8ffd6b
--- /dev/null
+++ b/kernel/trace/trace_boot.c
@@ -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();
+}