diff options
Diffstat (limited to 'tools/perf/builtin-stat.c')
| -rw-r--r-- | tools/perf/builtin-stat.c | 120 | 
1 files changed, 109 insertions, 11 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f17dc601b0f3..096ccb25c11f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -80,6 +80,9 @@  #include <sys/stat.h>  #include <sys/wait.h>  #include <unistd.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h>  #include "sane_ctype.h" @@ -164,6 +167,7 @@ static bool			forever				= false;  static bool			metric_only			= false;  static bool			force_metric_only		= false;  static bool			no_merge			= false; +static bool			walltime_run_table		= false;  static struct timespec		ref_time;  static struct cpu_map		*aggr_map;  static aggr_get_id_t		aggr_get_id; @@ -173,6 +177,9 @@ static const char		*output_name;  static int			output_fd;  static int			print_free_counters_hint;  static int			print_mixed_hw_group_error; +static u64			*walltime_run; +static bool			ru_display			= false; +static struct rusage		ru_data;  struct perf_stat {  	bool			 record; @@ -569,7 +576,7 @@ static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel)  	return leader;  } -static int __run_perf_stat(int argc, const char **argv) +static int __run_perf_stat(int argc, const char **argv, int run_idx)  {  	int interval = stat_config.interval;  	int times = stat_config.times; @@ -724,7 +731,7 @@ try_again:  					break;  			}  		} -		waitpid(child_pid, &status, 0); +		wait4(child_pid, &status, 0, &ru_data);  		if (workload_exec_errno) {  			const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); @@ -752,6 +759,9 @@ try_again:  	t1 = rdclock(); +	if (walltime_run_table) +		walltime_run[run_idx] = t1 - t0; +  	update_stats(&walltime_nsecs_stats, t1 - t0);  	/* @@ -766,7 +776,7 @@ try_again:  	return WEXITSTATUS(status);  } -static int run_perf_stat(int argc, const char **argv) +static int run_perf_stat(int argc, const char **argv, int run_idx)  {  	int ret; @@ -779,7 +789,7 @@ static int run_perf_stat(int argc, const char **argv)  	if (sync_run)  		sync(); -	ret = __run_perf_stat(argc, argv); +	ret = __run_perf_stat(argc, argv, run_idx);  	if (ret)  		return ret; @@ -1764,19 +1774,81 @@ static void print_header(int argc, const char **argv)  	}  } +static int get_precision(double num) +{ +	if (num > 1) +		return 0; + +	return lround(ceil(-log10(num))); +} + +static void print_table(FILE *output, int precision, double avg) +{ +	char tmp[64]; +	int idx, indent = 0; + +	scnprintf(tmp, 64, " %17.*f", precision, avg); +	while (tmp[indent] == ' ') +		indent++; + +	fprintf(output, "%*s# Table of individual measurements:\n", indent, ""); + +	for (idx = 0; idx < run_count; idx++) { +		double run = (double) walltime_run[idx] / NSEC_PER_SEC; +		int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5); + +		fprintf(output, " %17.*f (%+.*f) ", +			precision, run, precision, run - avg); + +		for (h = 0; h < n; h++) +			fprintf(output, "#"); + +		fprintf(output, "\n"); +	} + +	fprintf(output, "\n%*s# Final result:\n", indent, ""); +} + +static double timeval2double(struct timeval *t) +{ +	return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC; +} +  static void print_footer(void)  { +	double avg = avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC;  	FILE *output = stat_config.output;  	int n;  	if (!null_run)  		fprintf(output, "\n"); -	fprintf(output, " %17.9f seconds time elapsed", -			avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC); -	if (run_count > 1) { -		fprintf(output, "                                        "); -		print_noise_pct(stddev_stats(&walltime_nsecs_stats), -				avg_stats(&walltime_nsecs_stats)); + +	if (run_count == 1) { +		fprintf(output, " %17.9f seconds time elapsed", avg); + +		if (ru_display) { +			double ru_utime = timeval2double(&ru_data.ru_utime); +			double ru_stime = timeval2double(&ru_data.ru_stime); + +			fprintf(output, "\n\n"); +			fprintf(output, " %17.9f seconds user\n", ru_utime); +			fprintf(output, " %17.9f seconds sys\n", ru_stime); +		} +	} else { +		double sd = stddev_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; +		/* +		 * Display at most 2 more significant +		 * digits than the stddev inaccuracy. +		 */ +		int precision = get_precision(sd) + 2; + +		if (walltime_run_table) +			print_table(output, precision, avg); + +		fprintf(output, " %17.*f +- %.*f seconds time elapsed", +			precision, avg, precision, sd); + +		print_noise_pct(sd, avg);  	}  	fprintf(output, "\n\n"); @@ -1952,6 +2024,8 @@ static const struct option stat_options[] = {  		    "be more verbose (show counter open errors, etc)"),  	OPT_INTEGER('r', "repeat", &run_count,  		    "repeat command and print average + stddev (max: 100, forever: 0)"), +	OPT_BOOLEAN(0, "table", &walltime_run_table, +		    "display details about each run (only with -r option)"),  	OPT_BOOLEAN('n', "null", &null_run,  		    "null run - dont start any counters"),  	OPT_INCR('d', "detailed", &detailed_run, @@ -2843,6 +2917,13 @@ int cmd_stat(int argc, const char **argv)  		goto out;  	} +	if (walltime_run_table && run_count <= 1) { +		fprintf(stderr, "--table is only supported with -r\n"); +		parse_options_usage(stat_usage, stat_options, "r", 1); +		parse_options_usage(NULL, stat_options, "table", 0); +		goto out; +	} +  	if (output_fd < 0) {  		fprintf(stderr, "argument to --log-fd must be a > 0\n");  		parse_options_usage(stat_usage, stat_options, "log-fd", 0); @@ -2888,6 +2969,13 @@ int cmd_stat(int argc, const char **argv)  	setup_system_wide(argc); +	/* +	 * Display user/system times only for single +	 * run and when there's specified tracee. +	 */ +	if ((run_count == 1) && target__none(&target)) +		ru_display = true; +  	if (run_count < 0) {  		pr_err("Run count must be a positive number\n");  		parse_options_usage(stat_usage, stat_options, "r", 1); @@ -2897,6 +2985,14 @@ int cmd_stat(int argc, const char **argv)  		run_count = 1;  	} +	if (walltime_run_table) { +		walltime_run = zalloc(run_count * sizeof(walltime_run[0])); +		if (!walltime_run) { +			pr_err("failed to setup -r option"); +			goto out; +		} +	} +  	if ((stat_config.aggr_mode == AGGR_THREAD) &&  		!target__has_task(&target)) {  		if (!target.system_wide || target.cpu_list) { @@ -3012,7 +3108,7 @@ int cmd_stat(int argc, const char **argv)  			fprintf(output, "[ perf stat: executing run #%d ... ]\n",  				run_idx + 1); -		status = run_perf_stat(argc, argv); +		status = run_perf_stat(argc, argv, run_idx);  		if (forever && status != -1) {  			print_counters(NULL, argc, argv);  			perf_stat__reset_stats(); @@ -3060,6 +3156,8 @@ int cmd_stat(int argc, const char **argv)  	perf_stat__exit_aggr_mode();  	perf_evlist__free_stats(evsel_list);  out: +	free(walltime_run); +  	if (smi_cost && smi_reset)  		sysfs__write_int(FREEZE_ON_SMI_PATH, 0);  | 
