Ping!
On Tue, 3 Sep 2013 14:05:08 +0900, Namhyung Kim wrote: > From: Namhyung Kim <namhyung....@lge.com> > > The set_graph_notrace filter is analogous to set_ftrace_notrace and > can be used for eliminating uninteresting part of function graph trace > output. It also works with set_graph_function nicely. > > # cd /sys/kernel/debug/tracing/ > # echo do_page_fault > set_graph_function > # perf ftrace live true > 2) | do_page_fault() { > 2) | __do_page_fault() { > 2) 0.381 us | down_read_trylock(); > 2) 0.055 us | __might_sleep(); > 2) 0.696 us | find_vma(); > 2) | handle_mm_fault() { > 2) | handle_pte_fault() { > 2) | __do_fault() { > 2) | filemap_fault() { > 2) | find_get_page() { > 2) 0.033 us | __rcu_read_lock(); > 2) 0.035 us | __rcu_read_unlock(); > 2) 1.696 us | } > 2) 0.031 us | __might_sleep(); > 2) 2.831 us | } > 2) | _raw_spin_lock() { > 2) 0.046 us | add_preempt_count(); > 2) 0.841 us | } > 2) 0.033 us | page_add_file_rmap(); > 2) | _raw_spin_unlock() { > 2) 0.057 us | sub_preempt_count(); > 2) 0.568 us | } > 2) | unlock_page() { > 2) 0.084 us | page_waitqueue(); > 2) 0.126 us | __wake_up_bit(); > 2) 1.117 us | } > 2) 7.729 us | } > 2) 8.397 us | } > 2) 8.956 us | } > 2) 0.085 us | up_read(); > 2) + 12.745 us | } > 2) + 13.401 us | } > ... > > # echo handle_mm_fault > set_graph_notrace > # perf ftrace live true > 1) | do_page_fault() { > 1) | __do_page_fault() { > 1) 0.205 us | down_read_trylock(); > 1) 0.041 us | __might_sleep(); > 1) 0.344 us | find_vma(); > 1) 0.069 us | up_read(); > 1) 4.692 us | } > 1) 5.311 us | } > ... > > Signed-off-by: Namhyung Kim <namhy...@kernel.org> > --- > include/linux/ftrace.h | 1 + > kernel/trace/ftrace.c | 118 > ++++++++++++++++++++++++++++++++++- > kernel/trace/trace.h | 23 +++++++ > kernel/trace/trace_functions_graph.c | 21 ++++++- > 4 files changed, 159 insertions(+), 4 deletions(-) > > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h > index 9f15c0064c50..ec85d48619e1 100644 > --- a/include/linux/ftrace.h > +++ b/include/linux/ftrace.h > @@ -721,6 +721,7 @@ ftrace_push_return_trace(unsigned long ret, unsigned long > func, int *depth, > extern char __irqentry_text_start[]; > extern char __irqentry_text_end[]; > > +#define FTRACE_NOTRACE_DEPTH 65536 > #define FTRACE_RETFUNC_DEPTH 50 > #define FTRACE_RETSTACK_ALLOC_SIZE 32 > extern int register_ftrace_graph(trace_func_graph_ret_t retfunc, > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c > index a6d098c6df3f..1b1f3409f788 100644 > --- a/kernel/trace/ftrace.c > +++ b/kernel/trace/ftrace.c > @@ -3819,6 +3819,43 @@ static const struct seq_operations > ftrace_graph_seq_ops = { > .show = g_show, > }; > > +int ftrace_graph_notrace_count; > +int ftrace_graph_notrace_enabled; > +unsigned long ftrace_graph_notrace_funcs[FTRACE_GRAPH_MAX_FUNCS] > __read_mostly; > + > +static void * > +__n_next(struct seq_file *m, loff_t *pos) > +{ > + if (*pos >= ftrace_graph_notrace_count) > + return NULL; > + return &ftrace_graph_notrace_funcs[*pos]; > +} > + > +static void * > +n_next(struct seq_file *m, void *v, loff_t *pos) > +{ > + (*pos)++; > + return __n_next(m, pos); > +} > + > +static void *n_start(struct seq_file *m, loff_t *pos) > +{ > + mutex_lock(&graph_lock); > + > + /* Nothing, tell g_show to print all functions are enabled */ > + if (!ftrace_graph_notrace_enabled && !*pos) > + return (void *)1; > + > + return __n_next(m, pos); > +} > + > +static const struct seq_operations ftrace_graph_notrace_seq_ops = { > + .start = n_start, > + .next = n_next, > + .stop = g_stop, > + .show = g_show, > +}; > + > static int > ftrace_graph_open(struct inode *inode, struct file *file) > { > @@ -3843,6 +3880,30 @@ ftrace_graph_open(struct inode *inode, struct file > *file) > } > > static int > +ftrace_graph_notrace_open(struct inode *inode, struct file *file) > +{ > + int ret = 0; > + > + if (unlikely(ftrace_disabled)) > + return -ENODEV; > + > + mutex_lock(&graph_lock); > + if ((file->f_mode & FMODE_WRITE) && > + (file->f_flags & O_TRUNC)) { > + ftrace_graph_notrace_enabled = 0; > + ftrace_graph_notrace_count = 0; > + memset(ftrace_graph_notrace_funcs, 0, > + sizeof(ftrace_graph_notrace_funcs)); > + } > + mutex_unlock(&graph_lock); > + > + if (file->f_mode & FMODE_READ) > + ret = seq_open(file, &ftrace_graph_notrace_seq_ops); > + > + return ret; > +} > + > +static int > ftrace_graph_release(struct inode *inode, struct file *file) > { > if (file->f_mode & FMODE_READ) > @@ -3910,8 +3971,6 @@ out: > if (fail) > return -EINVAL; > > - ftrace_graph_filter_enabled = !!(*idx); > - > return 0; > } > > @@ -3946,6 +4005,50 @@ ftrace_graph_write(struct file *file, const char > __user *ubuf, > > ret = read; > > + ftrace_graph_filter_enabled = ftrace_graph_count > 0; > + > +out_free: > + trace_parser_put(&parser); > +out_unlock: > + mutex_unlock(&graph_lock); > + > + return ret; > +} > + > +static ssize_t > +ftrace_graph_notrace_write(struct file *file, const char __user *ubuf, > + size_t cnt, loff_t *ppos) > +{ > + struct trace_parser parser; > + ssize_t read, ret; > + > + if (!cnt) > + return 0; > + > + mutex_lock(&graph_lock); > + > + if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { > + ret = -ENOMEM; > + goto out_unlock; > + } > + > + read = trace_get_user(&parser, ubuf, cnt, ppos); > + > + if (read >= 0 && trace_parser_loaded((&parser))) { > + parser.buffer[parser.idx] = 0; > + > + /* we allow only one expression at a time */ > + ret = ftrace_set_func(ftrace_graph_notrace_funcs, > + &ftrace_graph_notrace_count, > + parser.buffer); > + if (ret) > + goto out_free; > + } > + > + ret = read; > + > + ftrace_graph_notrace_enabled = ftrace_graph_notrace_count > 0; > + > out_free: > trace_parser_put(&parser); > out_unlock: > @@ -3961,6 +4064,14 @@ static const struct file_operations ftrace_graph_fops > = { > .llseek = ftrace_filter_lseek, > .release = ftrace_graph_release, > }; > + > +static const struct file_operations ftrace_graph_notrace_fops = { > + .open = ftrace_graph_notrace_open, > + .read = seq_read, > + .write = ftrace_graph_notrace_write, > + .llseek = ftrace_filter_lseek, > + .release = ftrace_graph_release, > +}; > #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ > > static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) > @@ -3982,6 +4093,9 @@ static __init int ftrace_init_dyn_debugfs(struct dentry > *d_tracer) > trace_create_file("set_graph_function", 0444, d_tracer, > NULL, > &ftrace_graph_fops); > + trace_create_file("set_graph_notrace", 0444, d_tracer, > + NULL, > + &ftrace_graph_notrace_fops); > #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ > > return 0; > diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h > index fe39acd4c1aa..797f6f7f3f56 100644 > --- a/kernel/trace/trace.h > +++ b/kernel/trace/trace.h > @@ -732,6 +732,9 @@ extern void __trace_graph_return(struct trace_array *tr, > extern int ftrace_graph_filter_enabled; > extern int ftrace_graph_count; > extern unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS]; > +extern int ftrace_graph_notrace_enabled; > +extern int ftrace_graph_notrace_count; > +extern unsigned long ftrace_graph_notrace_funcs[FTRACE_GRAPH_MAX_FUNCS]; > > static inline int ftrace_graph_addr(unsigned long addr) > { > @@ -757,11 +760,31 @@ static inline int ftrace_graph_addr(unsigned long addr) > > return 0; > } > + > +static inline int ftrace_graph_notrace_addr(unsigned long addr) > +{ > + int i; > + > + if (!ftrace_graph_notrace_enabled) > + return 0; > + > + for (i = 0; i < ftrace_graph_notrace_count; i++) { > + if (addr == ftrace_graph_notrace_funcs[i]) > + return 1; > + } > + > + return 0; > +} > #else > static inline int ftrace_graph_addr(unsigned long addr) > { > return 1; > } > + > +static inline int ftrace_graph_notrace_addr(unsigned long addr) > +{ > + return 0; > +} > #endif /* CONFIG_DYNAMIC_FTRACE */ > #else /* CONFIG_FUNCTION_GRAPH_TRACER */ > static inline enum print_line_t > diff --git a/kernel/trace/trace_functions_graph.c > b/kernel/trace/trace_functions_graph.c > index b5c09242683d..3ba240daa5e0 100644 > --- a/kernel/trace/trace_functions_graph.c > +++ b/kernel/trace/trace_functions_graph.c > @@ -114,16 +114,22 @@ ftrace_push_return_trace(unsigned long ret, unsigned > long func, int *depth, > return -EBUSY; > } > > + /* The function was filtered out */ > + if (current->curr_ret_stack < -1) > + return -EBUSY; > + > calltime = trace_clock_local(); > > index = ++current->curr_ret_stack; > + if (ftrace_graph_notrace_addr(func)) > + current->curr_ret_stack -= FTRACE_NOTRACE_DEPTH; > barrier(); > current->ret_stack[index].ret = ret; > current->ret_stack[index].func = func; > current->ret_stack[index].calltime = calltime; > current->ret_stack[index].subtime = 0; > current->ret_stack[index].fp = frame_pointer; > - *depth = index; > + *depth = current->curr_ret_stack; > > return 0; > } > @@ -137,6 +143,9 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, > unsigned long *ret, > > index = current->curr_ret_stack; > > + if (index < 0) > + index += FTRACE_NOTRACE_DEPTH; > + > if (unlikely(index < 0)) { > ftrace_graph_stop(); > WARN_ON(1); > @@ -193,6 +202,10 @@ unsigned long ftrace_return_to_handler(unsigned long > frame_pointer) > trace.rettime = trace_clock_local(); > barrier(); > current->curr_ret_stack--; > + if (current->curr_ret_stack < -1) { > + current->curr_ret_stack += FTRACE_NOTRACE_DEPTH; > + return ret; > + } > > /* > * The trace should run after decrementing the ret counter > @@ -259,10 +272,14 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) > > /* trace it when it is-nested-in or is a function enabled. */ > if ((!(trace->depth || ftrace_graph_addr(trace->func)) || > - ftrace_graph_ignore_irqs()) || > + ftrace_graph_ignore_irqs()) || (trace->depth < 0) || > (max_depth && trace->depth >= max_depth)) > return 0; > > + /* need to reserve a ret_stack entry to recover the depth */ > + if (ftrace_graph_notrace_addr(trace->func)) > + return 1; > + > local_irq_save(flags); > cpu = raw_smp_processor_id(); > data = per_cpu_ptr(tr->trace_buffer.data, cpu); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/