diff options
| author | Ingo Molnar <mingo@kernel.org> | 2018-12-03 13:42:17 +0300 | 
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2018-12-03 13:42:17 +0300 | 
| commit | 5f675231e456cb599b283f8361f01cf34b0617df (patch) | |
| tree | afb2bdfd6fdbb18336146f41ba7659120a5ff9d2 /tools/perf/builtin-script.c | |
| parent | 3e184501083c38fa091f640acb13af17a21fd228 (diff) | |
| parent | 2595646791c319cadfdbf271563aac97d0843dc7 (diff) | |
| download | linux-5f675231e456cb599b283f8361f01cf34b0617df.tar.xz | |
Merge tag 'v4.20-rc5' into sched/core, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/builtin-script.c')
| -rw-r--r-- | tools/perf/builtin-script.c | 166 | 
1 files changed, 142 insertions, 24 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4da5e32b9e03..b5bc85bd0bbe 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -44,6 +44,7 @@  #include <sys/stat.h>  #include <fcntl.h>  #include <unistd.h> +#include <subcmd/pager.h>  #include "sane_ctype.h" @@ -912,7 +913,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,  static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,  			    struct perf_insn *x, u8 *inbuf, int len, -			    int insn, FILE *fp) +			    int insn, FILE *fp, int *total_cycles)  {  	int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip,  			      dump_insn(x, ip, inbuf, len, NULL), @@ -921,7 +922,8 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,  			      en->flags.in_tx ? " INTX" : "",  			      en->flags.abort ? " ABORT" : "");  	if (en->flags.cycles) { -		printed += fprintf(fp, " %d cycles", en->flags.cycles); +		*total_cycles += en->flags.cycles; +		printed += fprintf(fp, " %d cycles [%d]", en->flags.cycles, *total_cycles);  		if (insn)  			printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles);  	} @@ -978,6 +980,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,  	u8 buffer[MAXBB];  	unsigned off;  	struct symbol *lastsym = NULL; +	int total_cycles = 0;  	if (!(br && br->nr))  		return 0; @@ -998,7 +1001,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,  		printed += ip__fprintf_sym(br->entries[nr - 1].from, thread,  					   x.cpumode, x.cpu, &lastsym, attr, fp);  		printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], -					    &x, buffer, len, 0, fp); +					    &x, buffer, len, 0, fp, &total_cycles);  	}  	/* Print all blocks */ @@ -1026,7 +1029,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,  			printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp);  			if (ip == end) { -				printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp); +				printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp, +							    &total_cycles);  				break;  			} else {  				printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, @@ -1104,6 +1108,35 @@ out:  	return printed;  } +static const char *resolve_branch_sym(struct perf_sample *sample, +				      struct perf_evsel *evsel, +				      struct thread *thread, +				      struct addr_location *al, +				      u64 *ip) +{ +	struct addr_location addr_al; +	struct perf_event_attr *attr = &evsel->attr; +	const char *name = NULL; + +	if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { +		if (sample_addr_correlates_sym(attr)) { +			thread__resolve(thread, &addr_al, sample); +			if (addr_al.sym) +				name = addr_al.sym->name; +			else +				*ip = sample->addr; +		} else { +			*ip = sample->addr; +		} +	} else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { +		if (al->sym) +			name = al->sym->name; +		else +			*ip = sample->ip; +	} +	return name; +} +  static int perf_sample__fprintf_callindent(struct perf_sample *sample,  					   struct perf_evsel *evsel,  					   struct thread *thread, @@ -1111,7 +1144,6 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,  {  	struct perf_event_attr *attr = &evsel->attr;  	size_t depth = thread_stack__depth(thread); -	struct addr_location addr_al;  	const char *name = NULL;  	static int spacing;  	int len = 0; @@ -1125,22 +1157,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,  	if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN)  		depth += 1; -	if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { -		if (sample_addr_correlates_sym(attr)) { -			thread__resolve(thread, &addr_al, sample); -			if (addr_al.sym) -				name = addr_al.sym->name; -			else -				ip = sample->addr; -		} else { -			ip = sample->addr; -		} -	} else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { -		if (al->sym) -			name = al->sym->name; -		else -			ip = sample->ip; -	} +	name = resolve_branch_sym(sample, evsel, thread, al, &ip);  	if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) {  		dlen += fprintf(fp, "("); @@ -1646,6 +1663,47 @@ static void perf_sample__fprint_metric(struct perf_script *script,  	}  } +static bool show_event(struct perf_sample *sample, +		       struct perf_evsel *evsel, +		       struct thread *thread, +		       struct addr_location *al) +{ +	int depth = thread_stack__depth(thread); + +	if (!symbol_conf.graph_function) +		return true; + +	if (thread->filter) { +		if (depth <= thread->filter_entry_depth) { +			thread->filter = false; +			return false; +		} +		return true; +	} else { +		const char *s = symbol_conf.graph_function; +		u64 ip; +		const char *name = resolve_branch_sym(sample, evsel, thread, al, +				&ip); +		unsigned nlen; + +		if (!name) +			return false; +		nlen = strlen(name); +		while (*s) { +			unsigned len = strcspn(s, ","); +			if (nlen == len && !strncmp(name, s, len)) { +				thread->filter = true; +				thread->filter_entry_depth = depth; +				return true; +			} +			s += len; +			if (*s == ',') +				s++; +		} +		return false; +	} +} +  static void process_event(struct perf_script *script,  			  struct perf_sample *sample, struct perf_evsel *evsel,  			  struct addr_location *al, @@ -1660,6 +1718,9 @@ static void process_event(struct perf_script *script,  	if (output[type].fields == 0)  		return; +	if (!show_event(sample, evsel, thread, al)) +		return; +  	++es->samples;  	perf_sample__fprintf_start(sample, thread, evsel, @@ -1737,6 +1798,9 @@ static void process_event(struct perf_script *script,  	if (PRINT_FIELD(METRIC))  		perf_sample__fprint_metric(script, thread, evsel, sample, fp); + +	if (verbose) +		fflush(fp);  }  static struct scripting_ops	*scripting_ops; @@ -3100,6 +3164,44 @@ static int perf_script__process_auxtrace_info(struct perf_session *session,  #define perf_script__process_auxtrace_info 0  #endif +static int parse_insn_trace(const struct option *opt __maybe_unused, +			    const char *str __maybe_unused, +			    int unset __maybe_unused) +{ +	parse_output_fields(NULL, "+insn,-event,-period", 0); +	itrace_parse_synth_opts(opt, "i0ns", 0); +	nanosecs = true; +	return 0; +} + +static int parse_xed(const struct option *opt __maybe_unused, +		     const char *str __maybe_unused, +		     int unset __maybe_unused) +{ +	force_pager("xed -F insn: -A -64 | less"); +	return 0; +} + +static int parse_call_trace(const struct option *opt __maybe_unused, +			    const char *str __maybe_unused, +			    int unset __maybe_unused) +{ +	parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent", 0); +	itrace_parse_synth_opts(opt, "cewp", 0); +	nanosecs = true; +	return 0; +} + +static int parse_callret_trace(const struct option *opt __maybe_unused, +			    const char *str __maybe_unused, +			    int unset __maybe_unused) +{ +	parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent,+flags", 0); +	itrace_parse_synth_opts(opt, "crewp", 0); +	nanosecs = true; +	return 0; +} +  int cmd_script(int argc, const char **argv)  {  	bool show_full_info = false; @@ -3109,7 +3211,10 @@ int cmd_script(int argc, const char **argv)  	char *rec_script_path = NULL;  	char *rep_script_path = NULL;  	struct perf_session *session; -	struct itrace_synth_opts itrace_synth_opts = { .set = false, }; +	struct itrace_synth_opts itrace_synth_opts = { +		.set = false, +		.default_no_sample = true, +	};  	char *script_path = NULL;  	const char **__argv;  	int i, j, err = 0; @@ -3184,6 +3289,16 @@ int cmd_script(int argc, const char **argv)  		    "system-wide collection from all CPUs"),  	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",  		   "only consider these symbols"), +	OPT_CALLBACK_OPTARG(0, "insn-trace", &itrace_synth_opts, NULL, NULL, +			"Decode instructions from itrace", parse_insn_trace), +	OPT_CALLBACK_OPTARG(0, "xed", NULL, NULL, NULL, +			"Run xed disassembler on output", parse_xed), +	OPT_CALLBACK_OPTARG(0, "call-trace", &itrace_synth_opts, NULL, NULL, +			"Decode calls from from itrace", parse_call_trace), +	OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL, +			"Decode calls and returns from itrace", parse_callret_trace), +	OPT_STRING(0, "graph-function", &symbol_conf.graph_function, "symbol[,symbol...]", +			"Only print symbols and callees with --call-trace/--call-ret-trace"),  	OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]",  		   "Stop display of callgraph at these symbols"),  	OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), @@ -3417,8 +3532,10 @@ int cmd_script(int argc, const char **argv)  		exit(-1);  	} -	if (!script_name) +	if (!script_name) {  		setup_pager(); +		use_browser = 0; +	}  	session = perf_session__new(&data, false, &script.tool);  	if (session == NULL) @@ -3439,7 +3556,8 @@ int cmd_script(int argc, const char **argv)  	script.session = session;  	script__setup_sample_type(&script); -	if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) +	if ((output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) || +	    symbol_conf.graph_function)  		itrace_synth_opts.thread_stack = true;  	session->itrace_synth_opts = &itrace_synth_opts;  | 
