diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 169 | 
1 files changed, 108 insertions, 61 deletions
| diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 9aed1a5cf553..dd11c830eb84 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -40,7 +40,7 @@ struct fgraph_data {  #define TRACE_GRAPH_PRINT_OVERHEAD	0x4  #define TRACE_GRAPH_PRINT_PROC		0x8  #define TRACE_GRAPH_PRINT_DURATION	0x10 -#define TRACE_GRAPH_PRINT_ABS_TIME	0X20 +#define TRACE_GRAPH_PRINT_ABS_TIME	0x20  static struct tracer_opt trace_opts[] = {  	/* Display overruns? (for self-debug purpose) */ @@ -179,7 +179,7 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer)  	return ret;  } -static int __trace_graph_entry(struct trace_array *tr, +int __trace_graph_entry(struct trace_array *tr,  				struct ftrace_graph_ent *trace,  				unsigned long flags,  				int pc) @@ -246,7 +246,7 @@ int trace_graph_thresh_entry(struct ftrace_graph_ent *trace)  		return trace_graph_entry(trace);  } -static void __trace_graph_return(struct trace_array *tr, +void __trace_graph_return(struct trace_array *tr,  				struct ftrace_graph_ret *trace,  				unsigned long flags,  				int pc) @@ -490,9 +490,10 @@ get_return_for_leaf(struct trace_iterator *iter,  			 * We need to consume the current entry to see  			 * the next one.  			 */ -			ring_buffer_consume(iter->tr->buffer, iter->cpu, NULL); +			ring_buffer_consume(iter->tr->buffer, iter->cpu, +					    NULL, NULL);  			event = ring_buffer_peek(iter->tr->buffer, iter->cpu, -						 NULL); +						 NULL, NULL);  		}  		if (!event) @@ -526,17 +527,18 @@ get_return_for_leaf(struct trace_iterator *iter,  /* Signal a overhead of time execution to the output */  static int -print_graph_overhead(unsigned long long duration, struct trace_seq *s) +print_graph_overhead(unsigned long long duration, struct trace_seq *s, +		     u32 flags)  {  	/* If duration disappear, we don't need anything */ -	if (!(tracer_flags.val & TRACE_GRAPH_PRINT_DURATION)) +	if (!(flags & TRACE_GRAPH_PRINT_DURATION))  		return 1;  	/* Non nested entry or return */  	if (duration == -1)  		return trace_seq_printf(s, "  "); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) { +	if (flags & TRACE_GRAPH_PRINT_OVERHEAD) {  		/* Duration exceeded 100 msecs */  		if (duration > 100000ULL)  			return trace_seq_printf(s, "! "); @@ -562,7 +564,7 @@ static int print_graph_abs_time(u64 t, struct trace_seq *s)  static enum print_line_t  print_graph_irq(struct trace_iterator *iter, unsigned long addr, -		enum trace_type type, int cpu, pid_t pid) +		enum trace_type type, int cpu, pid_t pid, u32 flags)  {  	int ret;  	struct trace_seq *s = &iter->seq; @@ -572,21 +574,21 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,  		return TRACE_TYPE_UNHANDLED;  	/* Absolute time */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { +	if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {  		ret = print_graph_abs_time(iter->ts, s);  		if (!ret)  			return TRACE_TYPE_PARTIAL_LINE;  	}  	/* Cpu */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { +	if (flags & TRACE_GRAPH_PRINT_CPU) {  		ret = print_graph_cpu(s, cpu);  		if (ret == TRACE_TYPE_PARTIAL_LINE)  			return TRACE_TYPE_PARTIAL_LINE;  	}  	/* Proc */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) { +	if (flags & TRACE_GRAPH_PRINT_PROC) {  		ret = print_graph_proc(s, pid);  		if (ret == TRACE_TYPE_PARTIAL_LINE)  			return TRACE_TYPE_PARTIAL_LINE; @@ -596,7 +598,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,  	}  	/* No overhead */ -	ret = print_graph_overhead(-1, s); +	ret = print_graph_overhead(-1, s, flags);  	if (!ret)  		return TRACE_TYPE_PARTIAL_LINE; @@ -609,7 +611,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,  		return TRACE_TYPE_PARTIAL_LINE;  	/* Don't close the duration column if haven't one */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) +	if (flags & TRACE_GRAPH_PRINT_DURATION)  		trace_seq_printf(s, " |");  	ret = trace_seq_printf(s, "\n"); @@ -679,7 +681,8 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s)  static enum print_line_t  print_graph_entry_leaf(struct trace_iterator *iter,  		struct ftrace_graph_ent_entry *entry, -		struct ftrace_graph_ret_entry *ret_entry, struct trace_seq *s) +		struct ftrace_graph_ret_entry *ret_entry, +		struct trace_seq *s, u32 flags)  {  	struct fgraph_data *data = iter->private;  	struct ftrace_graph_ret *graph_ret; @@ -711,12 +714,12 @@ print_graph_entry_leaf(struct trace_iterator *iter,  	}  	/* Overhead */ -	ret = print_graph_overhead(duration, s); +	ret = print_graph_overhead(duration, s, flags);  	if (!ret)  		return TRACE_TYPE_PARTIAL_LINE;  	/* Duration */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) { +	if (flags & TRACE_GRAPH_PRINT_DURATION) {  		ret = print_graph_duration(duration, s);  		if (ret == TRACE_TYPE_PARTIAL_LINE)  			return TRACE_TYPE_PARTIAL_LINE; @@ -739,7 +742,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,  static enum print_line_t  print_graph_entry_nested(struct trace_iterator *iter,  			 struct ftrace_graph_ent_entry *entry, -			 struct trace_seq *s, int cpu) +			 struct trace_seq *s, int cpu, u32 flags)  {  	struct ftrace_graph_ent *call = &entry->graph_ent;  	struct fgraph_data *data = iter->private; @@ -759,12 +762,12 @@ print_graph_entry_nested(struct trace_iterator *iter,  	}  	/* No overhead */ -	ret = print_graph_overhead(-1, s); +	ret = print_graph_overhead(-1, s, flags);  	if (!ret)  		return TRACE_TYPE_PARTIAL_LINE;  	/* No time */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) { +	if (flags & TRACE_GRAPH_PRINT_DURATION) {  		ret = trace_seq_printf(s, "            |  ");  		if (!ret)  			return TRACE_TYPE_PARTIAL_LINE; @@ -790,7 +793,7 @@ print_graph_entry_nested(struct trace_iterator *iter,  static enum print_line_t  print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, -		     int type, unsigned long addr) +		     int type, unsigned long addr, u32 flags)  {  	struct fgraph_data *data = iter->private;  	struct trace_entry *ent = iter->ent; @@ -803,27 +806,27 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,  	if (type) {  		/* Interrupt */ -		ret = print_graph_irq(iter, addr, type, cpu, ent->pid); +		ret = print_graph_irq(iter, addr, type, cpu, ent->pid, flags);  		if (ret == TRACE_TYPE_PARTIAL_LINE)  			return TRACE_TYPE_PARTIAL_LINE;  	}  	/* Absolute time */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { +	if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {  		ret = print_graph_abs_time(iter->ts, s);  		if (!ret)  			return TRACE_TYPE_PARTIAL_LINE;  	}  	/* Cpu */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { +	if (flags & TRACE_GRAPH_PRINT_CPU) {  		ret = print_graph_cpu(s, cpu);  		if (ret == TRACE_TYPE_PARTIAL_LINE)  			return TRACE_TYPE_PARTIAL_LINE;  	}  	/* Proc */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) { +	if (flags & TRACE_GRAPH_PRINT_PROC) {  		ret = print_graph_proc(s, ent->pid);  		if (ret == TRACE_TYPE_PARTIAL_LINE)  			return TRACE_TYPE_PARTIAL_LINE; @@ -845,7 +848,7 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,  static enum print_line_t  print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, -			struct trace_iterator *iter) +			struct trace_iterator *iter, u32 flags)  {  	struct fgraph_data *data = iter->private;  	struct ftrace_graph_ent *call = &field->graph_ent; @@ -853,14 +856,14 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,  	static enum print_line_t ret;  	int cpu = iter->cpu; -	if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func)) +	if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags))  		return TRACE_TYPE_PARTIAL_LINE;  	leaf_ret = get_return_for_leaf(iter, field);  	if (leaf_ret) -		ret = print_graph_entry_leaf(iter, field, leaf_ret, s); +		ret = print_graph_entry_leaf(iter, field, leaf_ret, s, flags);  	else -		ret = print_graph_entry_nested(iter, field, s, cpu); +		ret = print_graph_entry_nested(iter, field, s, cpu, flags);  	if (data) {  		/* @@ -879,7 +882,8 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,  static enum print_line_t  print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, -		   struct trace_entry *ent, struct trace_iterator *iter) +		   struct trace_entry *ent, struct trace_iterator *iter, +		   u32 flags)  {  	unsigned long long duration = trace->rettime - trace->calltime;  	struct fgraph_data *data = iter->private; @@ -909,16 +913,16 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,  		}  	} -	if (print_graph_prologue(iter, s, 0, 0)) +	if (print_graph_prologue(iter, s, 0, 0, flags))  		return TRACE_TYPE_PARTIAL_LINE;  	/* Overhead */ -	ret = print_graph_overhead(duration, s); +	ret = print_graph_overhead(duration, s, flags);  	if (!ret)  		return TRACE_TYPE_PARTIAL_LINE;  	/* Duration */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) { +	if (flags & TRACE_GRAPH_PRINT_DURATION) {  		ret = print_graph_duration(duration, s);  		if (ret == TRACE_TYPE_PARTIAL_LINE)  			return TRACE_TYPE_PARTIAL_LINE; @@ -948,14 +952,15 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,  	}  	/* Overrun */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) { +	if (flags & TRACE_GRAPH_PRINT_OVERRUN) {  		ret = trace_seq_printf(s, " (Overruns: %lu)\n",  					trace->overrun);  		if (!ret)  			return TRACE_TYPE_PARTIAL_LINE;  	} -	ret = print_graph_irq(iter, trace->func, TRACE_GRAPH_RET, cpu, pid); +	ret = print_graph_irq(iter, trace->func, TRACE_GRAPH_RET, +			      cpu, pid, flags);  	if (ret == TRACE_TYPE_PARTIAL_LINE)  		return TRACE_TYPE_PARTIAL_LINE; @@ -963,8 +968,8 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,  }  static enum print_line_t -print_graph_comment(struct trace_seq *s,  struct trace_entry *ent, -		    struct trace_iterator *iter) +print_graph_comment(struct trace_seq *s, struct trace_entry *ent, +		    struct trace_iterator *iter, u32 flags)  {  	unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);  	struct fgraph_data *data = iter->private; @@ -976,16 +981,16 @@ print_graph_comment(struct trace_seq *s,  struct trace_entry *ent,  	if (data)  		depth = per_cpu_ptr(data->cpu_data, iter->cpu)->depth; -	if (print_graph_prologue(iter, s, 0, 0)) +	if (print_graph_prologue(iter, s, 0, 0, flags))  		return TRACE_TYPE_PARTIAL_LINE;  	/* No overhead */ -	ret = print_graph_overhead(-1, s); +	ret = print_graph_overhead(-1, s, flags);  	if (!ret)  		return TRACE_TYPE_PARTIAL_LINE;  	/* No time */ -	if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) { +	if (flags & TRACE_GRAPH_PRINT_DURATION) {  		ret = trace_seq_printf(s, "            |  ");  		if (!ret)  			return TRACE_TYPE_PARTIAL_LINE; @@ -1040,7 +1045,7 @@ print_graph_comment(struct trace_seq *s,  struct trace_entry *ent,  enum print_line_t -print_graph_function(struct trace_iterator *iter) +print_graph_function_flags(struct trace_iterator *iter, u32 flags)  {  	struct ftrace_graph_ent_entry *field;  	struct fgraph_data *data = iter->private; @@ -1061,7 +1066,7 @@ print_graph_function(struct trace_iterator *iter)  	if (data && data->failed) {  		field = &data->ent;  		iter->cpu = data->cpu; -		ret = print_graph_entry(field, s, iter); +		ret = print_graph_entry(field, s, iter, flags);  		if (ret == TRACE_TYPE_HANDLED && iter->cpu != cpu) {  			per_cpu_ptr(data->cpu_data, iter->cpu)->ignore = 1;  			ret = TRACE_TYPE_NO_CONSUME; @@ -1081,32 +1086,49 @@ print_graph_function(struct trace_iterator *iter)  		struct ftrace_graph_ent_entry saved;  		trace_assign_type(field, entry);  		saved = *field; -		return print_graph_entry(&saved, s, iter); +		return print_graph_entry(&saved, s, iter, flags);  	}  	case TRACE_GRAPH_RET: {  		struct ftrace_graph_ret_entry *field;  		trace_assign_type(field, entry); -		return print_graph_return(&field->ret, s, entry, iter); +		return print_graph_return(&field->ret, s, entry, iter, flags);  	} +	case TRACE_STACK: +	case TRACE_FN: +		/* dont trace stack and functions as comments */ +		return TRACE_TYPE_UNHANDLED; +  	default: -		return print_graph_comment(s, entry, iter); +		return print_graph_comment(s, entry, iter, flags);  	}  	return TRACE_TYPE_HANDLED;  } -static void print_lat_header(struct seq_file *s) +static enum print_line_t +print_graph_function(struct trace_iterator *iter) +{ +	return print_graph_function_flags(iter, tracer_flags.val); +} + +static enum print_line_t +print_graph_function_event(struct trace_iterator *iter, int flags) +{ +	return print_graph_function(iter); +} + +static void print_lat_header(struct seq_file *s, u32 flags)  {  	static const char spaces[] = "                "	/* 16 spaces */  		"    "					/* 4 spaces */  		"                 ";			/* 17 spaces */  	int size = 0; -	if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) +	if (flags & TRACE_GRAPH_PRINT_ABS_TIME)  		size += 16; -	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) +	if (flags & TRACE_GRAPH_PRINT_CPU)  		size += 4; -	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) +	if (flags & TRACE_GRAPH_PRINT_PROC)  		size += 17;  	seq_printf(s, "#%.*s  _-----=> irqs-off        \n", size, spaces); @@ -1117,43 +1139,48 @@ static void print_lat_header(struct seq_file *s)  	seq_printf(s, "#%.*s|||| /                     \n", size, spaces);  } -static void print_graph_headers(struct seq_file *s) +void print_graph_headers_flags(struct seq_file *s, u32 flags)  {  	int lat = trace_flags & TRACE_ITER_LATENCY_FMT;  	if (lat) -		print_lat_header(s); +		print_lat_header(s, flags);  	/* 1st line */  	seq_printf(s, "#"); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) +	if (flags & TRACE_GRAPH_PRINT_ABS_TIME)  		seq_printf(s, "     TIME       "); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) +	if (flags & TRACE_GRAPH_PRINT_CPU)  		seq_printf(s, " CPU"); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) +	if (flags & TRACE_GRAPH_PRINT_PROC)  		seq_printf(s, "  TASK/PID       ");  	if (lat)  		seq_printf(s, "|||||"); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) +	if (flags & TRACE_GRAPH_PRINT_DURATION)  		seq_printf(s, "  DURATION   ");  	seq_printf(s, "               FUNCTION CALLS\n");  	/* 2nd line */  	seq_printf(s, "#"); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) +	if (flags & TRACE_GRAPH_PRINT_ABS_TIME)  		seq_printf(s, "      |         "); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) +	if (flags & TRACE_GRAPH_PRINT_CPU)  		seq_printf(s, " |  "); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) +	if (flags & TRACE_GRAPH_PRINT_PROC)  		seq_printf(s, "   |    |        ");  	if (lat)  		seq_printf(s, "|||||"); -	if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) +	if (flags & TRACE_GRAPH_PRINT_DURATION)  		seq_printf(s, "   |   |      ");  	seq_printf(s, "               |   |   |   |\n");  } -static void graph_trace_open(struct trace_iterator *iter) +void print_graph_headers(struct seq_file *s) +{ +	print_graph_headers_flags(s, tracer_flags.val); +} + +void graph_trace_open(struct trace_iterator *iter)  {  	/* pid and depth on the last trace processed */  	struct fgraph_data *data; @@ -1188,7 +1215,7 @@ static void graph_trace_open(struct trace_iterator *iter)  	pr_warning("function graph tracer: not enough memory\n");  } -static void graph_trace_close(struct trace_iterator *iter) +void graph_trace_close(struct trace_iterator *iter)  {  	struct fgraph_data *data = iter->private; @@ -1198,6 +1225,16 @@ static void graph_trace_close(struct trace_iterator *iter)  	}  } +static struct trace_event graph_trace_entry_event = { +	.type		= TRACE_GRAPH_ENT, +	.trace		= print_graph_function_event, +}; + +static struct trace_event graph_trace_ret_event = { +	.type		= TRACE_GRAPH_RET, +	.trace		= print_graph_function_event, +}; +  static struct tracer graph_trace __read_mostly = {  	.name		= "function_graph",  	.open		= graph_trace_open, @@ -1219,6 +1256,16 @@ static __init int init_graph_trace(void)  {  	max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); +	if (!register_ftrace_event(&graph_trace_entry_event)) { +		pr_warning("Warning: could not register graph trace events\n"); +		return 1; +	} + +	if (!register_ftrace_event(&graph_trace_ret_event)) { +		pr_warning("Warning: could not register graph trace events\n"); +		return 1; +	} +  	return register_tracer(&graph_trace);  } |