aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHiraku Toyooka <hiraku.toyooka.gu@hitachi.com>2012-12-25 21:53:00 -0500
committerSteven Rostedt <rostedt@goodmis.org>2013-01-30 11:02:06 -0500
commitdebdd57f5145f3c6a4b3f8d0126abd1a2def7fc6 (patch)
tree8dca457fbccaf115c48fdb9fb6ee6a9469b8b6de
parent2fd196ec1eab2623096e7fc7e6f3976160392bce (diff)
tracing: Make a snapshot feature available from userspace
Ftrace has a snapshot feature available from kernel space and latency tracers (e.g. irqsoff) are using it. This patch enables user applictions to take a snapshot via debugfs. Add "snapshot" debugfs file in "tracing" directory. snapshot: This is used to take a snapshot and to read the output of the snapshot. # echo 1 > snapshot This will allocate the spare buffer for snapshot (if it is not allocated), and take a snapshot. # cat snapshot This will show contents of the snapshot. # echo 0 > snapshot This will free the snapshot if it is allocated. Any other positive values will clear the snapshot contents if the snapshot is allocated, or return EINVAL if it is not allocated. Link: http://lkml.kernel.org/r/20121226025300.3252.86850.stgit@liselsia Cc: Jiri Olsa <jolsa@redhat.com> Cc: David Sharp <dhsharp@google.com> Signed-off-by: Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com> [ Fixed irqsoff selftest and also a conflict with a change that fixes the update_max_tr. ] Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--include/linux/ftrace_event.h3
-rw-r--r--kernel/trace/Kconfig10
-rw-r--r--kernel/trace/trace.c166
-rw-r--r--kernel/trace/trace.h1
4 files changed, 154 insertions, 26 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 6f8d0b77006b..13a54d0bdfa8 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -83,6 +83,9 @@ struct trace_iterator {
83 long idx; 83 long idx;
84 84
85 cpumask_var_t started; 85 cpumask_var_t started;
86
87 /* it's true when current open file is snapshot */
88 bool snapshot;
86}; 89};
87 90
88enum trace_iter_flags { 91enum trace_iter_flags {
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index cdc9d284d24e..36567564e221 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -253,6 +253,16 @@ config FTRACE_SYSCALLS
253 help 253 help
254 Basic tracer to catch the syscall entry and exit events. 254 Basic tracer to catch the syscall entry and exit events.
255 255
256config TRACER_SNAPSHOT
257 bool "Create a snapshot trace buffer"
258 select TRACER_MAX_TRACE
259 help
260 Allow tracing users to take snapshot of the current buffer using the
261 ftrace interface, e.g.:
262
263 echo 1 > /sys/kernel/debug/tracing/snapshot
264 cat snapshot
265
256config TRACE_BRANCH_PROFILING 266config TRACE_BRANCH_PROFILING
257 bool 267 bool
258 select GENERIC_TRACER 268 select GENERIC_TRACER
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 2c724662a3e8..70dce64b9ecf 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -710,12 +710,11 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
710 710
711 WARN_ON_ONCE(!irqs_disabled()); 711 WARN_ON_ONCE(!irqs_disabled());
712 712
713 /* If we disabled the tracer, stop now */ 713 if (!current_trace->allocated_snapshot) {
714 if (current_trace == &nop_trace) 714 /* Only the nop tracer should hit this when disabling */
715 return; 715 WARN_ON_ONCE(current_trace != &nop_trace);
716
717 if (WARN_ON_ONCE(!current_trace->use_max_tr))
718 return; 716 return;
717 }
719 718
720 arch_spin_lock(&ftrace_max_lock); 719 arch_spin_lock(&ftrace_max_lock);
721 720
@@ -743,10 +742,8 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
743 return; 742 return;
744 743
745 WARN_ON_ONCE(!irqs_disabled()); 744 WARN_ON_ONCE(!irqs_disabled());
746 if (!current_trace->use_max_tr) { 745 if (WARN_ON_ONCE(!current_trace->allocated_snapshot))
747 WARN_ON_ONCE(1);
748 return; 746 return;
749 }
750 747
751 arch_spin_lock(&ftrace_max_lock); 748 arch_spin_lock(&ftrace_max_lock);
752 749
@@ -866,10 +863,13 @@ int register_tracer(struct tracer *type)
866 863
867 current_trace = type; 864 current_trace = type;
868 865
869 /* If we expanded the buffers, make sure the max is expanded too */ 866 if (type->use_max_tr) {
870 if (ring_buffer_expanded && type->use_max_tr) 867 /* If we expanded the buffers, make sure the max is expanded too */
871 ring_buffer_resize(max_tr.buffer, trace_buf_size, 868 if (ring_buffer_expanded)
872 RING_BUFFER_ALL_CPUS); 869 ring_buffer_resize(max_tr.buffer, trace_buf_size,
870 RING_BUFFER_ALL_CPUS);
871 type->allocated_snapshot = true;
872 }
873 873
874 /* the test is responsible for initializing and enabling */ 874 /* the test is responsible for initializing and enabling */
875 pr_info("Testing tracer %s: ", type->name); 875 pr_info("Testing tracer %s: ", type->name);
@@ -885,10 +885,14 @@ int register_tracer(struct tracer *type)
885 /* Only reset on passing, to avoid touching corrupted buffers */ 885 /* Only reset on passing, to avoid touching corrupted buffers */
886 tracing_reset_online_cpus(tr); 886 tracing_reset_online_cpus(tr);
887 887
888 /* Shrink the max buffer again */ 888 if (type->use_max_tr) {
889 if (ring_buffer_expanded && type->use_max_tr) 889 type->allocated_snapshot = false;
890 ring_buffer_resize(max_tr.buffer, 1, 890
891 RING_BUFFER_ALL_CPUS); 891 /* Shrink the max buffer again */
892 if (ring_buffer_expanded)
893 ring_buffer_resize(max_tr.buffer, 1,
894 RING_BUFFER_ALL_CPUS);
895 }
892 896
893 printk(KERN_CONT "PASSED\n"); 897 printk(KERN_CONT "PASSED\n");
894 } 898 }
@@ -1964,7 +1968,11 @@ static void *s_start(struct seq_file *m, loff_t *pos)
1964 *iter->trace = *current_trace; 1968 *iter->trace = *current_trace;
1965 mutex_unlock(&trace_types_lock); 1969 mutex_unlock(&trace_types_lock);
1966 1970
1967 atomic_inc(&trace_record_cmdline_disabled); 1971 if (iter->snapshot && iter->trace->use_max_tr)
1972 return ERR_PTR(-EBUSY);
1973
1974 if (!iter->snapshot)
1975 atomic_inc(&trace_record_cmdline_disabled);
1968 1976
1969 if (*pos != iter->pos) { 1977 if (*pos != iter->pos) {
1970 iter->ent = NULL; 1978 iter->ent = NULL;
@@ -2003,7 +2011,11 @@ static void s_stop(struct seq_file *m, void *p)
2003{ 2011{
2004 struct trace_iterator *iter = m->private; 2012 struct trace_iterator *iter = m->private;
2005 2013
2006 atomic_dec(&trace_record_cmdline_disabled); 2014 if (iter->snapshot && iter->trace->use_max_tr)
2015 return;
2016
2017 if (!iter->snapshot)
2018 atomic_dec(&trace_record_cmdline_disabled);
2007 trace_access_unlock(iter->cpu_file); 2019 trace_access_unlock(iter->cpu_file);
2008 trace_event_read_unlock(); 2020 trace_event_read_unlock();
2009} 2021}
@@ -2438,7 +2450,7 @@ static const struct seq_operations tracer_seq_ops = {
2438}; 2450};
2439 2451
2440static struct trace_iterator * 2452static struct trace_iterator *
2441__tracing_open(struct inode *inode, struct file *file) 2453__tracing_open(struct inode *inode, struct file *file, bool snapshot)
2442{ 2454{
2443 long cpu_file = (long) inode->i_private; 2455 long cpu_file = (long) inode->i_private;
2444 struct trace_iterator *iter; 2456 struct trace_iterator *iter;
@@ -2471,10 +2483,11 @@ __tracing_open(struct inode *inode, struct file *file)
2471 if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL)) 2483 if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL))
2472 goto fail; 2484 goto fail;
2473 2485
2474 if (current_trace && current_trace->print_max) 2486 if ((current_trace && current_trace->print_max) || snapshot)
2475 iter->tr = &max_tr; 2487 iter->tr = &max_tr;
2476 else 2488 else
2477 iter->tr = &global_trace; 2489 iter->tr = &global_trace;
2490 iter->snapshot = snapshot;
2478 iter->pos = -1; 2491 iter->pos = -1;
2479 mutex_init(&iter->mutex); 2492 mutex_init(&iter->mutex);
2480 iter->cpu_file = cpu_file; 2493 iter->cpu_file = cpu_file;
@@ -2491,8 +2504,9 @@ __tracing_open(struct inode *inode, struct file *file)
2491 if (trace_clocks[trace_clock_id].in_ns) 2504 if (trace_clocks[trace_clock_id].in_ns)
2492 iter->iter_flags |= TRACE_FILE_TIME_IN_NS; 2505 iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
2493 2506
2494 /* stop the trace while dumping */ 2507 /* stop the trace while dumping if we are not opening "snapshot" */
2495 tracing_stop(); 2508 if (!iter->snapshot)
2509 tracing_stop();
2496 2510
2497 if (iter->cpu_file == TRACE_PIPE_ALL_CPU) { 2511 if (iter->cpu_file == TRACE_PIPE_ALL_CPU) {
2498 for_each_tracing_cpu(cpu) { 2512 for_each_tracing_cpu(cpu) {
@@ -2555,8 +2569,9 @@ static int tracing_release(struct inode *inode, struct file *file)
2555 if (iter->trace && iter->trace->close) 2569 if (iter->trace && iter->trace->close)
2556 iter->trace->close(iter); 2570 iter->trace->close(iter);
2557 2571
2558 /* reenable tracing if it was previously enabled */ 2572 if (!iter