diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
| -rw-r--r-- | tools/perf/builtin-script.c | 233 | 
1 files changed, 158 insertions, 75 deletions
| diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 447457786362..484ce6067d23 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -82,38 +82,64 @@ static bool			native_arch;  unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;  enum perf_output_field { -	PERF_OUTPUT_COMM            = 1U << 0, -	PERF_OUTPUT_TID             = 1U << 1, -	PERF_OUTPUT_PID             = 1U << 2, -	PERF_OUTPUT_TIME            = 1U << 3, -	PERF_OUTPUT_CPU             = 1U << 4, -	PERF_OUTPUT_EVNAME          = 1U << 5, -	PERF_OUTPUT_TRACE           = 1U << 6, -	PERF_OUTPUT_IP              = 1U << 7, -	PERF_OUTPUT_SYM             = 1U << 8, -	PERF_OUTPUT_DSO             = 1U << 9, -	PERF_OUTPUT_ADDR            = 1U << 10, -	PERF_OUTPUT_SYMOFFSET       = 1U << 11, -	PERF_OUTPUT_SRCLINE         = 1U << 12, -	PERF_OUTPUT_PERIOD          = 1U << 13, -	PERF_OUTPUT_IREGS	    = 1U << 14, -	PERF_OUTPUT_BRSTACK	    = 1U << 15, -	PERF_OUTPUT_BRSTACKSYM	    = 1U << 16, -	PERF_OUTPUT_DATA_SRC	    = 1U << 17, -	PERF_OUTPUT_WEIGHT	    = 1U << 18, -	PERF_OUTPUT_BPF_OUTPUT	    = 1U << 19, -	PERF_OUTPUT_CALLINDENT	    = 1U << 20, -	PERF_OUTPUT_INSN	    = 1U << 21, -	PERF_OUTPUT_INSNLEN	    = 1U << 22, -	PERF_OUTPUT_BRSTACKINSN	    = 1U << 23, -	PERF_OUTPUT_BRSTACKOFF	    = 1U << 24, -	PERF_OUTPUT_SYNTH           = 1U << 25, -	PERF_OUTPUT_PHYS_ADDR       = 1U << 26, -	PERF_OUTPUT_UREGS	    = 1U << 27, -	PERF_OUTPUT_METRIC	    = 1U << 28, -	PERF_OUTPUT_MISC            = 1U << 29, -	PERF_OUTPUT_SRCCODE	    = 1U << 30, -	PERF_OUTPUT_IPC             = 1U << 31, +	PERF_OUTPUT_COMM            = 1ULL << 0, +	PERF_OUTPUT_TID             = 1ULL << 1, +	PERF_OUTPUT_PID             = 1ULL << 2, +	PERF_OUTPUT_TIME            = 1ULL << 3, +	PERF_OUTPUT_CPU             = 1ULL << 4, +	PERF_OUTPUT_EVNAME          = 1ULL << 5, +	PERF_OUTPUT_TRACE           = 1ULL << 6, +	PERF_OUTPUT_IP              = 1ULL << 7, +	PERF_OUTPUT_SYM             = 1ULL << 8, +	PERF_OUTPUT_DSO             = 1ULL << 9, +	PERF_OUTPUT_ADDR            = 1ULL << 10, +	PERF_OUTPUT_SYMOFFSET       = 1ULL << 11, +	PERF_OUTPUT_SRCLINE         = 1ULL << 12, +	PERF_OUTPUT_PERIOD          = 1ULL << 13, +	PERF_OUTPUT_IREGS	    = 1ULL << 14, +	PERF_OUTPUT_BRSTACK	    = 1ULL << 15, +	PERF_OUTPUT_BRSTACKSYM	    = 1ULL << 16, +	PERF_OUTPUT_DATA_SRC	    = 1ULL << 17, +	PERF_OUTPUT_WEIGHT	    = 1ULL << 18, +	PERF_OUTPUT_BPF_OUTPUT	    = 1ULL << 19, +	PERF_OUTPUT_CALLINDENT	    = 1ULL << 20, +	PERF_OUTPUT_INSN	    = 1ULL << 21, +	PERF_OUTPUT_INSNLEN	    = 1ULL << 22, +	PERF_OUTPUT_BRSTACKINSN	    = 1ULL << 23, +	PERF_OUTPUT_BRSTACKOFF	    = 1ULL << 24, +	PERF_OUTPUT_SYNTH           = 1ULL << 25, +	PERF_OUTPUT_PHYS_ADDR       = 1ULL << 26, +	PERF_OUTPUT_UREGS	    = 1ULL << 27, +	PERF_OUTPUT_METRIC	    = 1ULL << 28, +	PERF_OUTPUT_MISC            = 1ULL << 29, +	PERF_OUTPUT_SRCCODE	    = 1ULL << 30, +	PERF_OUTPUT_IPC             = 1ULL << 31, +	PERF_OUTPUT_TOD             = 1ULL << 32, +}; + +struct perf_script { +	struct perf_tool	tool; +	struct perf_session	*session; +	bool			show_task_events; +	bool			show_mmap_events; +	bool			show_switch_events; +	bool			show_namespace_events; +	bool			show_lost_events; +	bool			show_round_events; +	bool			show_bpf_events; +	bool			show_cgroup_events; +	bool			show_text_poke_events; +	bool			allocated; +	bool			per_event_dump; +	bool			stitch_lbr; +	struct evswitch		evswitch; +	struct perf_cpu_map	*cpus; +	struct perf_thread_map *threads; +	int			name_width; +	const char              *time_str; +	struct perf_time_interval *ptime_range; +	int			range_size; +	int			range_num;  };  struct output_option { @@ -152,6 +178,7 @@ struct output_option {  	{.str = "misc", .field = PERF_OUTPUT_MISC},  	{.str = "srccode", .field = PERF_OUTPUT_SRCCODE},  	{.str = "ipc", .field = PERF_OUTPUT_IPC}, +	{.str = "tod", .field = PERF_OUTPUT_TOD},  };  enum { @@ -388,7 +415,7 @@ static int evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *  	return evsel__do_check_stype(evsel, sample_type, sample_msg, field, false);  } -static int perf_evsel__check_attr(struct evsel *evsel, struct perf_session *session) +static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)  {  	struct perf_event_attr *attr = &evsel->core.attr;  	bool allow_user_set; @@ -443,8 +470,7 @@ static int perf_evsel__check_attr(struct evsel *evsel, struct perf_session *sess  		return -EINVAL;  	}  	if (PRINT_FIELD(BRSTACKINSN) && !allow_user_set && -	    !(perf_evlist__combined_branch_type(session->evlist) & -	      PERF_SAMPLE_BRANCH_ANY)) { +	    !(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_ANY)) {  		pr_err("Display of branch stack assembler requested, but non all-branch filter set\n"  		       "Hint: run 'perf record -b ...'\n");  		return -EINVAL; @@ -503,6 +529,7 @@ static void set_print_ip_opts(struct perf_event_attr *attr)   */  static int perf_session__check_output_opt(struct perf_session *session)  { +	bool tod = false;  	unsigned int j;  	struct evsel *evsel; @@ -522,13 +549,14 @@ static int perf_session__check_output_opt(struct perf_session *session)  		}  		if (evsel && output[j].fields && -			perf_evsel__check_attr(evsel, session)) +			evsel__check_attr(evsel, session))  			return -1;  		if (evsel == NULL)  			continue;  		set_print_ip_opts(&evsel->core.attr); +		tod |= output[j].fields & PERF_OUTPUT_TOD;  	}  	if (!no_callchain) { @@ -569,13 +597,17 @@ static int perf_session__check_output_opt(struct perf_session *session)  		}  	} +	if (tod && !session->header.env.clock.enabled) { +		pr_err("Can't provide 'tod' time, missing clock data. " +		       "Please record with -k/--clockid option.\n"); +		return -1; +	}  out:  	return 0;  }  static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, -				     FILE *fp -) +				     FILE *fp)  {  	unsigned i = 0, r;  	int printed = 0; @@ -593,6 +625,56 @@ static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask,  	return printed;  } +#define DEFAULT_TOD_FMT "%F %H:%M:%S" + +static char* +tod_scnprintf(struct perf_script *script, char *buf, int buflen, +	     u64 timestamp) +{ +	u64 tod_ns, clockid_ns; +	struct perf_env *env; +	unsigned long nsec; +	struct tm ltime; +	char date[64]; +	time_t sec; + +	buf[0] = '\0'; +	if (buflen < 64 || !script) +		return buf; + +	env = &script->session->header.env; +	if (!env->clock.enabled) { +		scnprintf(buf, buflen, "disabled"); +		return buf; +	} + +	clockid_ns = env->clock.clockid_ns; +	tod_ns     = env->clock.tod_ns; + +	if (timestamp > clockid_ns) +		tod_ns += timestamp - clockid_ns; +	else +		tod_ns -= clockid_ns - timestamp; + +	sec  = (time_t) (tod_ns / NSEC_PER_SEC); +	nsec = tod_ns - sec * NSEC_PER_SEC; + +	if (localtime_r(&sec, <ime) == NULL) { +		scnprintf(buf, buflen, "failed"); +	} else { +		strftime(date, sizeof(date), DEFAULT_TOD_FMT, <ime); + +		if (symbol_conf.nanosecs) { +			snprintf(buf, buflen, "%s.%09lu", date, nsec); +		} else { +			snprintf(buf, buflen, "%s.%06lu", +				 date, nsec / NSEC_PER_USEC); +		} +	} + +	return buf; +} +  static int perf_sample__fprintf_iregs(struct perf_sample *sample,  				      struct perf_event_attr *attr, FILE *fp)  { @@ -607,7 +689,8 @@ static int perf_sample__fprintf_uregs(struct perf_sample *sample,  					 attr->sample_regs_user, fp);  } -static int perf_sample__fprintf_start(struct perf_sample *sample, +static int perf_sample__fprintf_start(struct perf_script *script, +				      struct perf_sample *sample,  				      struct thread *thread,  				      struct evsel *evsel,  				      u32 type, FILE *fp) @@ -616,6 +699,7 @@ static int perf_sample__fprintf_start(struct perf_sample *sample,  	unsigned long secs;  	unsigned long long nsecs;  	int printed = 0; +	char tstr[128];  	if (PRINT_FIELD(COMM)) {  		if (latency_format) @@ -684,6 +768,11 @@ static int perf_sample__fprintf_start(struct perf_sample *sample,  		printed += ret;  	} +	if (PRINT_FIELD(TOD)) { +		tod_scnprintf(script, tstr, sizeof(tstr), sample->time); +		printed += fprintf(fp, "%s ", tstr); +	} +  	if (PRINT_FIELD(TIME)) {  		u64 t = sample->time;  		if (reltime) { @@ -1668,31 +1757,7 @@ static int perf_sample__fprintf_synth(struct perf_sample *sample,  	return 0;  } -struct perf_script { -	struct perf_tool	tool; -	struct perf_session	*session; -	bool			show_task_events; -	bool			show_mmap_events; -	bool			show_switch_events; -	bool			show_namespace_events; -	bool			show_lost_events; -	bool			show_round_events; -	bool			show_bpf_events; -	bool			show_cgroup_events; -	bool			allocated; -	bool			per_event_dump; -	bool			stitch_lbr; -	struct evswitch		evswitch; -	struct perf_cpu_map	*cpus; -	struct perf_thread_map *threads; -	int			name_width; -	const char              *time_str; -	struct perf_time_interval *ptime_range; -	int			range_size; -	int			range_num; -}; - -static int perf_evlist__max_name_len(struct evlist *evlist) +static int evlist__max_name_len(struct evlist *evlist)  {  	struct evsel *evsel;  	int max = 0; @@ -1739,7 +1804,7 @@ static void script_print_metric(struct perf_stat_config *config __maybe_unused,  	if (!fmt)  		return; -	perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel, +	perf_sample__fprintf_start(NULL, mctx->sample, mctx->thread, mctx->evsel,  				   PERF_RECORD_SAMPLE, mctx->fp);  	fputs("\tmetric: ", mctx->fp);  	if (color) @@ -1754,7 +1819,7 @@ static void script_new_line(struct perf_stat_config *config __maybe_unused,  {  	struct metric_ctx *mctx = ctx; -	perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel, +	perf_sample__fprintf_start(NULL, mctx->sample, mctx->thread, mctx->evsel,  				   PERF_RECORD_SAMPLE, mctx->fp);  	fputs("\tmetric: ", mctx->fp);  } @@ -1865,7 +1930,7 @@ static void process_event(struct perf_script *script,  	++es->samples; -	perf_sample__fprintf_start(sample, thread, evsel, +	perf_sample__fprintf_start(script, sample, thread, evsel,  				   PERF_RECORD_SAMPLE, fp);  	if (PRINT_FIELD(PERIOD)) @@ -1875,7 +1940,7 @@ static void process_event(struct perf_script *script,  		const char *evname = evsel__name(evsel);  		if (!script->name_width) -			script->name_width = perf_evlist__max_name_len(script->session->evlist); +			script->name_width = evlist__max_name_len(script->session->evlist);  		fprintf(fp, "%*s: ", script->name_width, evname ?: "[unknown]");  	} @@ -2120,7 +2185,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,  	}  	if (evsel->core.attr.sample_type) { -		err = perf_evsel__check_attr(evsel, scr->session); +		err = evsel__check_attr(evsel, scr->session);  		if (err)  			return err;  	} @@ -2129,7 +2194,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,  	 * Check if we need to enable callchains based  	 * on events sample_type.  	 */ -	sample_type = perf_evlist__combined_sample_type(evlist); +	sample_type = evlist__combined_sample_type(evlist);  	callchain_param_setup(sample_type);  	/* Enable fields for callchain entries */ @@ -2174,11 +2239,11 @@ static int print_event_with_time(struct perf_tool *tool,  		thread = machine__findnew_thread(machine, pid, tid);  	if (thread && evsel) { -		perf_sample__fprintf_start(sample, thread, evsel, +		perf_sample__fprintf_start(script, sample, thread, evsel,  					   event->header.type, stdout);  	} -	perf_event__fprintf(event, stdout); +	perf_event__fprintf(event, machine, stdout);  	thread__put(thread); @@ -2313,7 +2378,7 @@ process_finished_round_event(struct perf_tool *tool __maybe_unused,  			     struct ordered_events *oe __maybe_unused)  { -	perf_event__fprintf(event, stdout); +	perf_event__fprintf(event, NULL, stdout);  	return 0;  } @@ -2330,6 +2395,18 @@ process_bpf_events(struct perf_tool *tool __maybe_unused,  			   sample->tid);  } +static int process_text_poke_events(struct perf_tool *tool, +				    union perf_event *event, +				    struct perf_sample *sample, +				    struct machine *machine) +{ +	if (perf_event__process_text_poke(tool, event, sample, machine) < 0) +		return -1; + +	return print_event(tool, event, sample, machine, sample->pid, +			   sample->tid); +} +  static void sig_handler(int sig __maybe_unused)  {  	session_done = 1; @@ -2438,6 +2515,10 @@ static int __cmd_script(struct perf_script *script)  		script->tool.ksymbol = process_bpf_events;  		script->tool.bpf     = process_bpf_events;  	} +	if (script->show_text_poke_events) { +		script->tool.ksymbol   = process_bpf_events; +		script->tool.text_poke = process_text_poke_events; +	}  	if (perf_script__setup_per_event_dump(script)) {  		pr_err("Couldn't create the per event dump files\n"); @@ -3171,7 +3252,7 @@ static int have_cmd(int argc, const char **argv)  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); +	u64 sample_type = evlist__combined_sample_type(session->evlist);  	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {  		if ((sample_type & PERF_SAMPLE_REGS_USER) && @@ -3423,7 +3504,7 @@ int cmd_script(int argc, const char **argv)  		     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"  		     "addr,symoff,srcline,period,iregs,uregs,brstack,"  		     "brstacksym,flags,bpf-output,brstackinsn,brstackoff," -		     "callindent,insn,insnlen,synth,phys_addr,metric,misc,ipc", +		     "callindent,insn,insnlen,synth,phys_addr,metric,misc,ipc,tod",  		     parse_output_fields),  	OPT_BOOLEAN('a', "all-cpus", &system_wide,  		    "system-wide collection from all CPUs"), @@ -3474,6 +3555,8 @@ int cmd_script(int argc, const char **argv)  		    "Show round events (if recorded)"),  	OPT_BOOLEAN('\0', "show-bpf-events", &script.show_bpf_events,  		    "Show bpf related events (if recorded)"), +	OPT_BOOLEAN('\0', "show-text-poke-events", &script.show_text_poke_events, +		    "Show text poke related events (if recorded)"),  	OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump,  		    "Dump trace output to files named by the monitored events"),  	OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), | 
