mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	ftrace: Add set_graph_notrace filter
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    |  }
  ...
Link: http://lkml.kernel.org/r/1381739066-7531-5-git-send-email-namhyung@kernel.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
			
			
This commit is contained in:
		
							parent
							
								
									6a10108bdb
								
							
						
					
					
						commit
						29ad23b004
					
				
					 4 changed files with 109 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3776,7 +3776,9 @@ static const struct file_operations ftrace_notrace_fops = {
 | 
			
		|||
static DEFINE_MUTEX(graph_lock);
 | 
			
		||||
 | 
			
		||||
int ftrace_graph_count;
 | 
			
		||||
int ftrace_graph_notrace_count;
 | 
			
		||||
unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly;
 | 
			
		||||
unsigned long ftrace_graph_notrace_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly;
 | 
			
		||||
 | 
			
		||||
struct ftrace_graph_data {
 | 
			
		||||
	unsigned long *table;
 | 
			
		||||
| 
						 | 
				
			
			@ -3890,6 +3892,26 @@ ftrace_graph_open(struct inode *inode, struct file *file)
 | 
			
		|||
	return __ftrace_graph_open(inode, file, fgd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
ftrace_graph_notrace_open(struct inode *inode, struct file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct ftrace_graph_data *fgd;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ftrace_disabled))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	fgd = kmalloc(sizeof(*fgd), GFP_KERNEL);
 | 
			
		||||
	if (fgd == NULL)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	fgd->table = ftrace_graph_notrace_funcs;
 | 
			
		||||
	fgd->size = FTRACE_GRAPH_MAX_FUNCS;
 | 
			
		||||
	fgd->count = &ftrace_graph_notrace_count;
 | 
			
		||||
	fgd->seq_ops = &ftrace_graph_seq_ops;
 | 
			
		||||
 | 
			
		||||
	return __ftrace_graph_open(inode, file, fgd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
ftrace_graph_release(struct inode *inode, struct file *file)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -4011,6 +4033,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_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)
 | 
			
		||||
| 
						 | 
				
			
			@ -4032,6 +4062,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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -732,6 +732,8 @@ extern void __trace_graph_return(struct trace_array *tr,
 | 
			
		|||
#define FTRACE_GRAPH_MAX_FUNCS		32
 | 
			
		||||
extern int ftrace_graph_count;
 | 
			
		||||
extern unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS];
 | 
			
		||||
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 +759,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_count)
 | 
			
		||||
		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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,16 +114,37 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
 | 
			
		|||
		return -EBUSY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The curr_ret_stack is an index to ftrace return stack of
 | 
			
		||||
	 * current task.  Its value should be in [0, FTRACE_RETFUNC_
 | 
			
		||||
	 * DEPTH) when the function graph tracer is used.  To support
 | 
			
		||||
	 * filtering out specific functions, it makes the index
 | 
			
		||||
	 * negative by subtracting huge value (FTRACE_NOTRACE_DEPTH)
 | 
			
		||||
	 * so when it sees a negative index the ftrace will ignore
 | 
			
		||||
	 * the record.  And the index gets recovered when returning
 | 
			
		||||
	 * from the filtered function by adding the FTRACE_NOTRACE_
 | 
			
		||||
	 * DEPTH and then it'll continue to record functions normally.
 | 
			
		||||
	 *
 | 
			
		||||
	 * The curr_ret_stack is initialized to -1 and get increased
 | 
			
		||||
	 * in this function.  So it can be less than -1 only if it was
 | 
			
		||||
	 * filtered out via ftrace_graph_notrace_addr() which can be
 | 
			
		||||
	 * set from set_graph_notrace file in debugfs by user.
 | 
			
		||||
	 */
 | 
			
		||||
	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,7 +158,17 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret,
 | 
			
		|||
 | 
			
		||||
	index = current->curr_ret_stack;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(index < 0)) {
 | 
			
		||||
	/*
 | 
			
		||||
	 * A negative index here means that it's just returned from a
 | 
			
		||||
	 * notrace'd function.  Recover index to get an original
 | 
			
		||||
	 * return address.  See ftrace_push_return_trace().
 | 
			
		||||
	 *
 | 
			
		||||
	 * TODO: Need to check whether the stack gets corrupted.
 | 
			
		||||
	 */
 | 
			
		||||
	if (index < 0)
 | 
			
		||||
		index += FTRACE_NOTRACE_DEPTH;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(index < 0 || index >= FTRACE_RETFUNC_DEPTH)) {
 | 
			
		||||
		ftrace_graph_stop();
 | 
			
		||||
		WARN_ON(1);
 | 
			
		||||
		/* Might as well panic, otherwise we have no where to go */
 | 
			
		||||
| 
						 | 
				
			
			@ -193,6 +224,15 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer)
 | 
			
		|||
	trace.rettime = trace_clock_local();
 | 
			
		||||
	barrier();
 | 
			
		||||
	current->curr_ret_stack--;
 | 
			
		||||
	/*
 | 
			
		||||
	 * The curr_ret_stack can be less than -1 only if it was
 | 
			
		||||
	 * filtered out and it's about to return from the function.
 | 
			
		||||
	 * Recover the index and continue to trace normal functions.
 | 
			
		||||
	 */
 | 
			
		||||
	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 +299,20 @@ 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;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Do not trace a function if it's filtered by set_graph_notrace.
 | 
			
		||||
	 * Make the index of ret stack negative to indicate that it should
 | 
			
		||||
	 * ignore further functions.  But it needs its own ret stack entry
 | 
			
		||||
	 * to recover the original index in order to continue tracing after
 | 
			
		||||
	 * returning from the function.
 | 
			
		||||
	 */
 | 
			
		||||
	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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue