diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 78 | 
1 files changed, 54 insertions, 24 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index b1342c5d37c..e998a824e9d 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -18,6 +18,7 @@ struct fgraph_cpu_data {  	pid_t		last_pid;  	int		depth;  	int		ignore; +	unsigned long	enter_funcs[FTRACE_RETFUNC_DEPTH];  };  struct fgraph_data { @@ -212,13 +213,11 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)  	int cpu;  	int pc; -	if (unlikely(!tr)) -		return 0; -  	if (!ftrace_trace_task(current))  		return 0; -	if (!ftrace_graph_addr(trace->func)) +	/* trace it when it is-nested-in or is a function enabled. */ +	if (!(trace->depth || ftrace_graph_addr(trace->func)))  		return 0;  	local_irq_save(flags); @@ -231,9 +230,6 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)  	} else {  		ret = 0;  	} -	/* Only do the atomic if it is not already set */ -	if (!test_tsk_trace_graph(current)) -		set_tsk_trace_graph(current);  	atomic_dec(&data->disabled);  	local_irq_restore(flags); @@ -281,17 +277,24 @@ void trace_graph_return(struct ftrace_graph_ret *trace)  		pc = preempt_count();  		__trace_graph_return(tr, trace, flags, pc);  	} -	if (!trace->depth) -		clear_tsk_trace_graph(current);  	atomic_dec(&data->disabled);  	local_irq_restore(flags);  } +void set_graph_array(struct trace_array *tr) +{ +	graph_array = tr; + +	/* Make graph_array visible before we start tracing */ + +	smp_mb(); +} +  static int graph_trace_init(struct trace_array *tr)  {  	int ret; -	graph_array = tr; +	set_graph_array(tr);  	ret = register_ftrace_graph(&trace_graph_return,  				    &trace_graph_entry);  	if (ret) @@ -301,11 +304,6 @@ static int graph_trace_init(struct trace_array *tr)  	return 0;  } -void set_graph_array(struct trace_array *tr) -{ -	graph_array = tr; -} -  static void graph_trace_reset(struct trace_array *tr)  {  	tracing_stop_cmdline_record(); @@ -673,15 +671,21 @@ print_graph_entry_leaf(struct trace_iterator *iter,  	duration = graph_ret->rettime - graph_ret->calltime;  	if (data) { +		struct fgraph_cpu_data *cpu_data;  		int cpu = iter->cpu; -		int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); + +		cpu_data = per_cpu_ptr(data->cpu_data, cpu);  		/*  		 * Comments display at + 1 to depth. Since  		 * this is a leaf function, keep the comments  		 * equal to this depth.  		 */ -		*depth = call->depth - 1; +		cpu_data->depth = call->depth - 1; + +		/* No need to keep this function around for this depth */ +		if (call->depth < FTRACE_RETFUNC_DEPTH) +			cpu_data->enter_funcs[call->depth] = 0;  	}  	/* Overhead */ @@ -721,10 +725,15 @@ print_graph_entry_nested(struct trace_iterator *iter,  	int i;  	if (data) { +		struct fgraph_cpu_data *cpu_data;  		int cpu = iter->cpu; -		int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); -		*depth = call->depth; +		cpu_data = per_cpu_ptr(data->cpu_data, cpu); +		cpu_data->depth = call->depth; + +		/* Save this function pointer to see if the exit matches */ +		if (call->depth < FTRACE_RETFUNC_DEPTH) +			cpu_data->enter_funcs[call->depth] = call->func;  	}  	/* No overhead */ @@ -854,19 +863,28 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,  	struct fgraph_data *data = iter->private;  	pid_t pid = ent->pid;  	int cpu = iter->cpu; +	int func_match = 1;  	int ret;  	int i;  	if (data) { +		struct fgraph_cpu_data *cpu_data;  		int cpu = iter->cpu; -		int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); + +		cpu_data = per_cpu_ptr(data->cpu_data, cpu);  		/*  		 * Comments display at + 1 to depth. This is the  		 * return from a function, we now want the comments  		 * to display at the same level of the bracket.  		 */ -		*depth = trace->depth - 1; +		cpu_data->depth = trace->depth - 1; + +		if (trace->depth < FTRACE_RETFUNC_DEPTH) { +			if (cpu_data->enter_funcs[trace->depth] != trace->func) +				func_match = 0; +			cpu_data->enter_funcs[trace->depth] = 0; +		}  	}  	if (print_graph_prologue(iter, s, 0, 0)) @@ -891,9 +909,21 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,  			return TRACE_TYPE_PARTIAL_LINE;  	} -	ret = trace_seq_printf(s, "}\n"); -	if (!ret) -		return TRACE_TYPE_PARTIAL_LINE; +	/* +	 * If the return function does not have a matching entry, +	 * then the entry was lost. Instead of just printing +	 * the '}' and letting the user guess what function this +	 * belongs to, write out the function name. +	 */ +	if (func_match) { +		ret = trace_seq_printf(s, "}\n"); +		if (!ret) +			return TRACE_TYPE_PARTIAL_LINE; +	} else { +		ret = trace_seq_printf(s, "} (%ps)\n", (void *)trace->func); +		if (!ret) +			return TRACE_TYPE_PARTIAL_LINE; +	}  	/* Overrun */  	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) {  |