[RFC PATCH 08/30 v3] mcount tracer output file

From: Steven Rostedt
Date: Tue Jan 15 2008 - 15:51:09 EST


Add /debugfs/tracing/trace to output trace output.

Here's an example of the content.

CPU 0: [<ffffffff80494691>] notifier_call_chain+0x16/0x60 <-- [<ffffffff80494701>] __atomic_notifier_call_chain+0x26/0x56
CPU 0: [<ffffffff802161c8>] mce_idle_callback+0x9/0x2f <-- [<ffffffff804946b3>] notifier_call_chain+0x38/0x60
CPU 0: [<ffffffff8037fb7a>] acpi_processor_idle+0x16/0x518 <-- [<ffffffff8020aee8>] cpu_idle+0xa1/0xe7
CPU 0: [<ffffffff8037fa98>] acpi_safe_halt+0x9/0x43 <-- [<ffffffff8037fd3a>] acpi_processor_idle+0x1d6/0x518
CPU 1: [<ffffffff80221db8>] smp_apic_timer_interrupt+0xc/0x58 <-- [<ffffffff8020cf06>] apic_timer_interrupt+0x66/0x70
CPU 1: [<ffffffff8020ac22>] exit_idle+0x9/0x22 <-- [<ffffffff80221de1>] smp_apic_timer_interrupt+0x35/0x58
CPU 1: [<ffffffff8020ab97>] __exit_idle+0x9/0x2e <-- [<ffffffff8020ac39>] exit_idle+0x20/0x22
CPU 1: [<ffffffff8049473a>] atomic_notifier_call_chain+0x9/0x16 <-- [<ffffffff8020abba>] __exit_idle+0x2c/0x2e
CPU 1: [<ffffffff804946e9>] __atomic_notifier_call_chain+0xe/0x56 <-- [<ffffffff80494745>] atomic_notifier_call_chain+0x14/0x16
CPU 1: [<ffffffff80494691>] notifier_call_chain+0x16/0x60 <-- [<ffffffff80494701>] __atomic_notifier_call_chain+0x26/0x56
CPU 1: [<ffffffff802161c8>] mce_idle_callback+0x9/0x2f <-- [<ffffffff804946b3>] notifier_call_chain+0x38/0x60

This is in the format of the output when KALLSYMS is defined.

CPU <CPU#>: [<IP>] <func> <-- [<Parent-IP>] <parent-func>

Signed-off-by: Steven Rostedt <srostedt@xxxxxxxxxx>
---
lib/tracing/tracer.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 215 insertions(+), 2 deletions(-)

Index: linux-compile.git/lib/tracing/tracer.c
===================================================================
--- linux-compile.git.orig/lib/tracing/tracer.c 2008-01-14 13:14:13.000000000 -0500
+++ linux-compile.git/lib/tracing/tracer.c 2008-01-14 14:57:58.000000000 -0500
@@ -13,9 +13,11 @@
#include <linux/fs.h>
#include <linux/gfp.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/linkage.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <linux/kallsyms.h>
#include <linux/uaccess.h>
#include <linux/mcount.h>

@@ -23,6 +25,7 @@
#include "tracer_interface.h"

static struct mctracer_trace mctracer_trace;
+static int trace_enabled __read_mostly;

static inline notrace void
mctracer_add_trace_entry(struct mctracer_trace *tr,
@@ -62,7 +65,7 @@ static notrace void trace_function(const
raw_local_irq_save(flags);

tr = &mctracer_trace;
- if (!tr->ctrl)
+ if (!trace_enabled)
goto out;

cpu = raw_smp_processor_id();
@@ -83,6 +86,205 @@ static struct mcount_ops trace_ops __rea
};

#ifdef CONFIG_DEBUG_FS
+struct mctracer_iterator {
+ struct mctracer_trace *tr;
+ struct mctracer_entry *ent;
+ unsigned long next_idx[NR_CPUS];
+ int cpu;
+ int idx;
+};
+
+static struct mctracer_entry *mctracer_entry_idx(struct mctracer_trace *tr,
+ unsigned long idx,
+ int cpu)
+{
+ struct mctracer_entry *array = tr->trace[cpu];
+ unsigned long underrun;
+
+ if (idx >= tr->entries)
+ return NULL;
+
+ underrun = atomic_read(&tr->underrun[cpu]);
+ if (underrun)
+ idx = ((underrun - 1) + idx) % tr->entries;
+ else if (idx >= tr->trace_idx[cpu])
+ return NULL;
+
+ return &array[idx];
+}
+
+static void *find_next_entry(struct mctracer_iterator *iter)
+{
+ struct mctracer_trace *tr = iter->tr;
+ struct mctracer_entry *ent;
+ struct mctracer_entry *next = NULL;
+ int next_i = -1;
+ int i;
+
+ for_each_possible_cpu(i) {
+ if (!tr->trace[i])
+ continue;
+ ent = mctracer_entry_idx(tr, iter->next_idx[i], i);
+ if (ent && (!next || next->idx > ent->idx)) {
+ next = ent;
+ next_i = i;
+ }
+ }
+ if (next) {
+ iter->next_idx[next_i]++;
+ iter->idx++;
+ }
+ iter->ent = next;
+ iter->cpu = next_i;
+
+ return next ? iter : NULL;
+}
+
+static void *s_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct mctracer_iterator *iter = m->private;
+ void *ent;
+ int i = (int)*pos;
+
+ (*pos)++;
+
+ /* can't go backwards */
+ if (iter->idx > i)
+ return NULL;
+
+ if (iter->idx < 0)
+ ent = find_next_entry(iter);
+ else
+ ent = iter;
+
+ while (ent && iter->idx < i)
+ ent = find_next_entry(iter);
+
+ return ent;
+}
+
+static void *s_start(struct seq_file *m, loff_t *pos)
+{
+ struct mctracer_iterator *iter = m->private;
+ void *p = NULL;
+ loff_t l = 0;
+ int i;
+
+ iter->ent = NULL;
+ iter->cpu = 0;
+ iter->idx = -1;
+
+ for (i = 0; i < NR_CPUS; i++)
+ iter->next_idx[i] = 0;
+
+ /* stop the trace while dumping */
+ if (iter->tr->ctrl)
+ trace_enabled = 0;
+
+ for (p = iter; p && l < *pos; p = s_next(m, p, &l))
+ ;
+
+ return p;
+}
+
+static void s_stop(struct seq_file *m, void *p)
+{
+ struct mctracer_iterator *iter = m->private;
+ if (iter->tr->ctrl)
+ trace_enabled = 1;
+}
+
+#ifdef CONFIG_KALLSYMS
+static void seq_print_symbol(struct seq_file *m,
+ const char *fmt, unsigned long address)
+{
+ char buffer[KSYM_SYMBOL_LEN];
+
+ sprint_symbol(buffer, address);
+ seq_printf(m, fmt, buffer);
+}
+#else
+# define seq_print_symbol(m, fmt, address) do { } while (0)
+#endif
+
+#ifndef CONFIG_64BIT
+# define IP_FMT "%08lx"
+#else
+# define IP_FMT "%016lx"
+#endif
+
+static void notrace seq_print_ip_sym(struct seq_file *m,
+ unsigned long ip)
+{
+ seq_print_symbol(m, "%s", ip);
+ seq_printf(m, " <" IP_FMT ">", ip);
+}
+
+static int s_show(struct seq_file *m, void *v)
+{
+ struct mctracer_iterator *iter = v;
+
+ if (iter->ent == NULL) {
+ seq_printf(m, "mctracer:\n");
+ } else {
+ seq_printf(m, " CPU %d: ", iter->cpu);
+ seq_print_ip_sym(m, iter->ent->ip);
+ if (iter->ent->parent_ip) {
+ seq_printf(m, " <-- ");
+ seq_print_ip_sym(m, iter->ent->parent_ip);
+ }
+ seq_printf(m, "\n");
+ }
+
+ return 0;
+}
+
+static struct seq_operations mctrace_seq_ops = {
+ .start = s_start,
+ .next = s_next,
+ .stop = s_stop,
+ .show = s_show,
+};
+
+static int mctrace_open(struct inode *inode, struct file *file)
+{
+ struct mctracer_iterator *iter;
+ int ret;
+
+ iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+ if (!iter)
+ return -ENOMEM;
+
+ iter->tr = &mctracer_trace;
+
+ /* TODO stop tracer */
+ ret = seq_open(file, &mctrace_seq_ops);
+ if (!ret) {
+ struct seq_file *m = file->private_data;
+ m->private = iter;
+ } else
+ kfree(iter);
+
+ return ret;
+}
+
+int mctrace_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct mctracer_iterator *iter = m->private;
+
+ seq_release(inode, file);
+ kfree(iter);
+ return 0;
+}
+
+static struct file_operations mctrace_fops = {
+ .open = mctrace_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = mctrace_release,
+};
+
static int mctracer_open_generic(struct inode *inode, struct file *filp)
{
filp->private_data = inode->i_private;
@@ -120,7 +322,13 @@ static ssize_t mctracer_ctrl_write(struc

val = !!simple_strtoul(buf, NULL, 10);

- tr->ctrl = val;
+ if (tr->ctrl ^ val) {
+ if (val)
+ trace_enabled = 1;
+ else
+ trace_enabled = 0;
+ tr->ctrl = val;
+ }

filp->f_pos += cnt;

@@ -148,6 +356,11 @@ static void mctrace_init_debugfs(void)
&mctracer_trace, &mctracer_ctrl_fops);
if (!entry)
pr_warning("Could not create debugfs 'ctrl' entry\n");
+
+ entry = debugfs_create_file("trace", 0444, d_mctracer,
+ &mctracer_trace, &mctrace_fops);
+ if (!entry)
+ pr_warning("Could not create debugfs 'trace' entry\n");
}
#else /* CONFIG_DEBUG_FS */
static void mctrace_init_debugfs(void)

--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/