[PATCH v3 -tip 3/4] 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. 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
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 |=