diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
| -rw-r--r-- | tools/perf/builtin-script.c | 108 | 
1 files changed, 100 insertions, 8 deletions
| diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 24809787369f..284a76e04628 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -6,6 +6,7 @@  #include "util/exec_cmd.h"  #include "util/header.h"  #include "util/parse-options.h" +#include "util/perf_regs.h"  #include "util/session.h"  #include "util/tool.h"  #include "util/symbol.h" @@ -46,6 +47,7 @@ enum perf_output_field {  	PERF_OUTPUT_SYMOFFSET       = 1U << 11,  	PERF_OUTPUT_SRCLINE         = 1U << 12,  	PERF_OUTPUT_PERIOD          = 1U << 13, +	PERF_OUTPUT_IREGS	    = 1U << 14,  };  struct output_option { @@ -66,6 +68,7 @@ struct output_option {  	{.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},  	{.str = "srcline", .field = PERF_OUTPUT_SRCLINE},  	{.str = "period", .field = PERF_OUTPUT_PERIOD}, +	{.str = "iregs", .field = PERF_OUTPUT_IREGS},  };  /* default set to maintain compatibility with current format */ @@ -255,6 +258,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,  					PERF_OUTPUT_PERIOD))  		return -EINVAL; +	if (PRINT_FIELD(IREGS) && +		perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS", +					PERF_OUTPUT_IREGS)) +		return -EINVAL; +  	return 0;  } @@ -352,6 +360,24 @@ out:  	return 0;  } +static void print_sample_iregs(union perf_event *event __maybe_unused, +			  struct perf_sample *sample, +			  struct thread *thread __maybe_unused, +			  struct perf_event_attr *attr) +{ +	struct regs_dump *regs = &sample->intr_regs; +	uint64_t mask = attr->sample_regs_intr; +	unsigned i = 0, r; + +	if (!regs) +		return; + +	for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { +		u64 val = regs->regs[i++]; +		printf("%5s:0x%"PRIx64" ", perf_reg_name(r), val); +	} +} +  static void print_sample_start(struct perf_sample *sample,  			       struct thread *thread,  			       struct perf_evsel *evsel) @@ -525,6 +551,9 @@ static void process_event(union perf_event *event, struct perf_sample *sample,  				     PERF_MAX_STACK_DEPTH);  	} +	if (PRINT_FIELD(IREGS)) +		print_sample_iregs(event, sample, thread, attr); +  	printf("\n");  } @@ -623,6 +652,7 @@ struct perf_script {  	struct perf_session	*session;  	bool			show_task_events;  	bool			show_mmap_events; +	bool			show_switch_events;  };  static int process_attr(struct perf_tool *tool, union perf_event *event, @@ -661,7 +691,7 @@ static int process_comm_event(struct perf_tool *tool,  	struct thread *thread;  	struct perf_script *script = container_of(tool, struct perf_script, tool);  	struct perf_session *session = script->session; -	struct perf_evsel *evsel = perf_evlist__first(session->evlist); +	struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);  	int ret = -1;  	thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid); @@ -695,7 +725,7 @@ static int process_fork_event(struct perf_tool *tool,  	struct thread *thread;  	struct perf_script *script = container_of(tool, struct perf_script, tool);  	struct perf_session *session = script->session; -	struct perf_evsel *evsel = perf_evlist__first(session->evlist); +	struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);  	if (perf_event__process_fork(tool, event, sample, machine) < 0)  		return -1; @@ -727,7 +757,7 @@ static int process_exit_event(struct perf_tool *tool,  	struct thread *thread;  	struct perf_script *script = container_of(tool, struct perf_script, tool);  	struct perf_session *session = script->session; -	struct perf_evsel *evsel = perf_evlist__first(session->evlist); +	struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);  	thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid);  	if (thread == NULL) { @@ -738,8 +768,8 @@ static int process_exit_event(struct perf_tool *tool,  	if (!evsel->attr.sample_id_all) {  		sample->cpu = 0;  		sample->time = 0; -		sample->tid = event->comm.tid; -		sample->pid = event->comm.pid; +		sample->tid = event->fork.tid; +		sample->pid = event->fork.pid;  	}  	print_sample_start(sample, thread, evsel);  	perf_event__fprintf(event, stdout); @@ -759,7 +789,7 @@ static int process_mmap_event(struct perf_tool *tool,  	struct thread *thread;  	struct perf_script *script = container_of(tool, struct perf_script, tool);  	struct perf_session *session = script->session; -	struct perf_evsel *evsel = perf_evlist__first(session->evlist); +	struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);  	if (perf_event__process_mmap(tool, event, sample, machine) < 0)  		return -1; @@ -790,7 +820,7 @@ static int process_mmap2_event(struct perf_tool *tool,  	struct thread *thread;  	struct perf_script *script = container_of(tool, struct perf_script, tool);  	struct perf_session *session = script->session; -	struct perf_evsel *evsel = perf_evlist__first(session->evlist); +	struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);  	if (perf_event__process_mmap2(tool, event, sample, machine) < 0)  		return -1; @@ -813,6 +843,32 @@ static int process_mmap2_event(struct perf_tool *tool,  	return 0;  } +static int process_switch_event(struct perf_tool *tool, +				union perf_event *event, +				struct perf_sample *sample, +				struct machine *machine) +{ +	struct thread *thread; +	struct perf_script *script = container_of(tool, struct perf_script, tool); +	struct perf_session *session = script->session; +	struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); + +	if (perf_event__process_switch(tool, event, sample, machine) < 0) +		return -1; + +	thread = machine__findnew_thread(machine, sample->pid, +					 sample->tid); +	if (thread == NULL) { +		pr_debug("problem processing SWITCH event, skipping it.\n"); +		return -1; +	} + +	print_sample_start(sample, thread, evsel); +	perf_event__fprintf(event, stdout); +	thread__put(thread); +	return 0; +} +  static void sig_handler(int sig __maybe_unused)  {  	session_done = 1; @@ -834,6 +890,8 @@ static int __cmd_script(struct perf_script *script)  		script->tool.mmap = process_mmap_event;  		script->tool.mmap2 = process_mmap2_event;  	} +	if (script->show_switch_events) +		script->tool.context_switch = process_switch_event;  	ret = perf_session__process_events(script->session); @@ -1532,6 +1590,22 @@ static int have_cmd(int argc, const char **argv)  	return 0;  } +static void script__setup_sample_type(struct perf_script *script) +{ +	struct perf_session *session = script->session; +	u64 sample_type = perf_evlist__combined_sample_type(session->evlist); + +	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { +		if ((sample_type & PERF_SAMPLE_REGS_USER) && +		    (sample_type & PERF_SAMPLE_STACK_USER)) +			callchain_param.record_mode = CALLCHAIN_DWARF; +		else if (sample_type & PERF_SAMPLE_BRANCH_STACK) +			callchain_param.record_mode = CALLCHAIN_LBR; +		else +			callchain_param.record_mode = CALLCHAIN_FP; +	} +} +  int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)  {  	bool show_full_info = false; @@ -1598,7 +1672,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)  		     "comma separated output fields prepend with 'type:'. "  		     "Valid types: hw,sw,trace,raw. "  		     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," -		     "addr,symoff,period,flags", parse_output_fields), +		     "addr,symoff,period,iregs,flags", parse_output_fields),  	OPT_BOOLEAN('a', "all-cpus", &system_wide,  		    "system-wide collection from all CPUs"),  	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", @@ -1618,10 +1692,19 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)  		    "Show the fork/comm/exit events"),  	OPT_BOOLEAN('\0', "show-mmap-events", &script.show_mmap_events,  		    "Show the mmap events"), +	OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events, +		    "Show context switch events (if recorded)"),  	OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),  	OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",  			    "Instruction Tracing options",  			    itrace_parse_synth_opts), +	OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename, +			"Show full source file name path for source lines"), +	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, +			"Enable symbol demangling"), +	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, +			"Enable kernel symbol demangling"), +  	OPT_END()  	};  	const char * const script_subcommands[] = { "record", "report", NULL }; @@ -1816,6 +1899,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)  		goto out_delete;  	script.session = session; +	script__setup_sample_type(&script);  	session->itrace_synth_opts = &itrace_synth_opts; @@ -1830,6 +1914,14 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)  	else  		symbol_conf.use_callchain = false; +	if (session->tevent.pevent && +	    pevent_set_function_resolver(session->tevent.pevent, +					 machine__resolve_kernel_addr, +					 &session->machines.host) < 0) { +		pr_err("%s: failed to set libtraceevent function resolver\n", __func__); +		return -1; +	} +  	if (generate_script_lang) {  		struct stat perf_stat;  		int input; |