[PATCH v3 -tip 3/4] tracing: make a snapshot feature available from userspace

2012-12-18 Thread Hiraku Toyooka
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.

Signed-off-by: Hiraku Toyooka 
Cc: Steven Rostedt 
Cc: Frederic Weisbecker 
Cc: Ingo Molnar 
Cc: Jiri Olsa 
Cc: David Sharp 
Cc: linux-kernel@vger.kernel.org
---
 include/linux/ftrace_event.h |3 +
 kernel/trace/Kconfig |   10 +++
 kernel/trace/trace.c |  134 ++
 kernel/trace/trace.h |1 
 4 files changed, 136 insertions(+), 12 deletions(-)

diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index a3d4895..9bebadd 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -84,6 +84,9 @@ struct trace_iterator {
longidx;
 
cpumask_var_t   started;
+
+   /* it's true when current open file is snapshot */
+   boolsnapshot;
 };
 
 enum trace_iter_flags {
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 5d89335..82a8ff5 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -250,6 +250,16 @@ config FTRACE_SYSCALLS
help
  Basic tracer to catch the syscall entry and exit events.
 
+config TRACER_SNAPSHOT
+   bool "Create a snapshot trace buffer"
+   select TRACER_MAX_TRACE
+   help
+ Allow tracing users to take snapshot of the current buffer using the
+ ftrace interface, e.g.:
+
+ echo 1 > /sys/kernel/debug/tracing/snapshot
+ cat snapshot
+
 config TRACE_BRANCH_PROFILING
bool
select GENERIC_TRACER
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8d05a44..0e5abce 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -709,7 +709,7 @@ update_max_tr(struct trace_array *tr, struct task_struct 
*tsk, int cpu)
return;
 
WARN_ON_ONCE(!irqs_disabled());
-   if (!current_trace->use_max_tr) {
+   if (!current_trace->allocated_snapshot) {
WARN_ON_ONCE(1);
return;
}
@@ -739,7 +739,7 @@ update_max_tr_single(struct trace_array *tr, struct 
task_struct *tsk, int cpu)
return;
 
WARN_ON_ONCE(!irqs_disabled());
-   if (!current_trace->use_max_tr) {
+   if (!current_trace->allocated_snapshot) {
WARN_ON_ONCE(1);
return;
}
@@ -1960,7 +1960,11 @@ static void *s_start(struct seq_file *m, loff_t *pos)
*iter->trace = *current_trace;
mutex_unlock(_types_lock);
 
-   atomic_inc(_record_cmdline_disabled);
+   if (iter->snapshot && iter->trace->use_max_tr)
+   return ERR_PTR(-EBUSY);
+
+   if (!iter->snapshot)
+   atomic_inc(_record_cmdline_disabled);
 
if (*pos != iter->pos) {
iter->ent = NULL;
@@ -1999,7 +2003,11 @@ static void s_stop(struct seq_file *m, void *p)
 {
struct trace_iterator *iter = m->private;
 
-   atomic_dec(_record_cmdline_disabled);
+   if (iter->snapshot && iter->trace->use_max_tr)
+   return;
+
+   if (!iter->snapshot)
+   atomic_dec(_record_cmdline_disabled);
trace_access_unlock(iter->cpu_file);
trace_event_read_unlock();
 }
@@ -2434,7 +2442,7 @@ static const struct seq_operations tracer_seq_ops = {
 };
 
 static struct trace_iterator *
-__tracing_open(struct inode *inode, struct file *file)
+__tracing_open(struct inode *inode, struct file *file, bool snapshot)
 {
long cpu_file = (long) inode->i_private;
struct trace_iterator *iter;
@@ -2467,10 +2475,11 @@ __tracing_open(struct inode *inode, struct file *file)
if (!zalloc_cpumask_var(>started, GFP_KERNEL))
goto fail;
 
-   if (current_trace && current_trace->print_max)
+   if ((current_trace && current_trace->print_max) || snapshot)
iter->tr = _tr;
else
iter->tr = _trace;
+   iter->snapshot = snapshot;
iter->pos = -1;
mutex_init(>mutex);
iter->cpu_file = cpu_file;
@@ -2487,8 +2496,9 @@ __tracing_open(struct inode *inode, struct file *file)
if (trace_clocks[trace_clock_id].in_ns)
iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
 
-   /* stop the trace while dumping */
-   tracing_stop();
+   /* stop the trace 

[PATCH v3 -tip 3/4] tracing: make a snapshot feature available from userspace

2012-12-18 Thread Hiraku Toyooka
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.

Signed-off-by: Hiraku Toyooka hiraku.toyooka...@hitachi.com
Cc: Steven Rostedt rost...@goodmis.org
Cc: Frederic Weisbecker fweis...@gmail.com
Cc: Ingo Molnar mi...@redhat.com
Cc: Jiri Olsa jo...@redhat.com
Cc: David Sharp dhsh...@google.com
Cc: linux-kernel@vger.kernel.org
---
 include/linux/ftrace_event.h |3 +
 kernel/trace/Kconfig |   10 +++
 kernel/trace/trace.c |  134 ++
 kernel/trace/trace.h |1 
 4 files changed, 136 insertions(+), 12 deletions(-)

diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index a3d4895..9bebadd 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -84,6 +84,9 @@ struct trace_iterator {
longidx;
 
cpumask_var_t   started;
+
+   /* it's true when current open file is snapshot */
+   boolsnapshot;
 };
 
 enum trace_iter_flags {
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 5d89335..82a8ff5 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -250,6 +250,16 @@ config FTRACE_SYSCALLS
help
  Basic tracer to catch the syscall entry and exit events.
 
+config TRACER_SNAPSHOT
+   bool Create a snapshot trace buffer
+   select TRACER_MAX_TRACE
+   help
+ Allow tracing users to take snapshot of the current buffer using the
+ ftrace interface, e.g.:
+
+ echo 1  /sys/kernel/debug/tracing/snapshot
+ cat snapshot
+
 config TRACE_BRANCH_PROFILING
bool
select GENERIC_TRACER
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8d05a44..0e5abce 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -709,7 +709,7 @@ update_max_tr(struct trace_array *tr, struct task_struct 
*tsk, int cpu)
return;
 
WARN_ON_ONCE(!irqs_disabled());
-   if (!current_trace-use_max_tr) {
+   if (!current_trace-allocated_snapshot) {
WARN_ON_ONCE(1);
return;
}
@@ -739,7 +739,7 @@ update_max_tr_single(struct trace_array *tr, struct 
task_struct *tsk, int cpu)
return;
 
WARN_ON_ONCE(!irqs_disabled());
-   if (!current_trace-use_max_tr) {
+   if (!current_trace-allocated_snapshot) {
WARN_ON_ONCE(1);
return;
}
@@ -1960,7 +1960,11 @@ static void *s_start(struct seq_file *m, loff_t *pos)
*iter-trace = *current_trace;
mutex_unlock(trace_types_lock);
 
-   atomic_inc(trace_record_cmdline_disabled);
+   if (iter-snapshot  iter-trace-use_max_tr)
+   return ERR_PTR(-EBUSY);
+
+   if (!iter-snapshot)
+   atomic_inc(trace_record_cmdline_disabled);
 
if (*pos != iter-pos) {
iter-ent = NULL;
@@ -1999,7 +2003,11 @@ static void s_stop(struct seq_file *m, void *p)
 {
struct trace_iterator *iter = m-private;
 
-   atomic_dec(trace_record_cmdline_disabled);
+   if (iter-snapshot  iter-trace-use_max_tr)
+   return;
+
+   if (!iter-snapshot)
+   atomic_dec(trace_record_cmdline_disabled);
trace_access_unlock(iter-cpu_file);
trace_event_read_unlock();
 }
@@ -2434,7 +2442,7 @@ static const struct seq_operations tracer_seq_ops = {
 };
 
 static struct trace_iterator *
-__tracing_open(struct inode *inode, struct file *file)
+__tracing_open(struct inode *inode, struct file *file, bool snapshot)
 {
long cpu_file = (long) inode-i_private;
struct trace_iterator *iter;
@@ -2467,10 +2475,11 @@ __tracing_open(struct inode *inode, struct file *file)
if (!zalloc_cpumask_var(iter-started, GFP_KERNEL))
goto fail;
 
-   if (current_trace  current_trace-print_max)
+   if ((current_trace  current_trace-print_max) || snapshot)
iter-tr = max_tr;
else
iter-tr = global_trace;
+   iter-snapshot = snapshot;
iter-pos = -1;
mutex_init(iter-mutex);
iter-cpu_file = cpu_file;
@@ -2487,8 +2496,9 @@ __tracing_open(struct inode *inode, struct file *file)
if (trace_clocks[trace_clock_id].in_ns)
iter-iter_flags |=