Add /debugfs/tracing/trace to output trace output. Here's an example of the content. CPU 0: [] notifier_call_chain+0x16/0x60 <-- [] __atomic_notifier_call_chain+0x26/0x56 CPU 0: [] mce_idle_callback+0x9/0x2f <-- [] notifier_call_chain+0x38/0x60 CPU 0: [] acpi_processor_idle+0x16/0x518 <-- [] cpu_idle+0xa1/0xe7 CPU 0: [] acpi_safe_halt+0x9/0x43 <-- [] acpi_processor_idle+0x1d6/0x518 CPU 1: [] smp_apic_timer_interrupt+0xc/0x58 <-- [] apic_timer_interrupt+0x66/0x70 CPU 1: [] exit_idle+0x9/0x22 <-- [] smp_apic_timer_interrupt+0x35/0x58 CPU 1: [] __exit_idle+0x9/0x2e <-- [] exit_idle+0x20/0x22 CPU 1: [] atomic_notifier_call_chain+0x9/0x16 <-- [] __exit_idle+0x2c/0x2e CPU 1: [] __atomic_notifier_call_chain+0xe/0x56 <-- [] atomic_notifier_call_chain+0x14/0x16 CPU 1: [] notifier_call_chain+0x16/0x60 <-- [] __atomic_notifier_call_chain+0x26/0x56 CPU 1: [] mce_idle_callback+0x9/0x2f <-- [] notifier_call_chain+0x38/0x60 This is in the format of the output when KALLSYMS is defined. CPU : [] <-- [] Signed-off-by: Steven Rostedt --- 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 #include #include +#include #include #include #include +#include #include #include @@ -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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/