xref: /openbmc/linux/tools/perf/builtin-stat.c (revision b9ebdcc0)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-stat.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin stat command: Give a precise performance counters summary
586470930SIngo Molnar  * overview about any workload, CPU or specific PID.
686470930SIngo Molnar  *
786470930SIngo Molnar  * Sample output:
886470930SIngo Molnar 
986470930SIngo Molnar    $ perf stat ~/hackbench 10
1086470930SIngo Molnar    Time: 0.104
1186470930SIngo Molnar 
1286470930SIngo Molnar     Performance counter stats for '/home/mingo/hackbench':
1386470930SIngo Molnar 
1486470930SIngo Molnar        1255.538611  task clock ticks     #      10.143 CPU utilization factor
1586470930SIngo Molnar              54011  context switches     #       0.043 M/sec
1686470930SIngo Molnar                385  CPU migrations       #       0.000 M/sec
1786470930SIngo Molnar              17755  pagefaults           #       0.014 M/sec
1886470930SIngo Molnar         3808323185  CPU cycles           #    3033.219 M/sec
1986470930SIngo Molnar         1575111190  instructions         #    1254.530 M/sec
2086470930SIngo Molnar           17367895  cache references     #      13.833 M/sec
2186470930SIngo Molnar            7674421  cache misses         #       6.112 M/sec
2286470930SIngo Molnar 
2386470930SIngo Molnar     Wall-clock time elapsed:   123.786620 msecs
2486470930SIngo Molnar 
2586470930SIngo Molnar  *
2686470930SIngo Molnar  * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
2786470930SIngo Molnar  *
2886470930SIngo Molnar  * Improvements and fixes by:
2986470930SIngo Molnar  *
3086470930SIngo Molnar  *   Arjan van de Ven <arjan@linux.intel.com>
3186470930SIngo Molnar  *   Yanmin Zhang <yanmin.zhang@intel.com>
3286470930SIngo Molnar  *   Wu Fengguang <fengguang.wu@intel.com>
3386470930SIngo Molnar  *   Mike Galbraith <efault@gmx.de>
3486470930SIngo Molnar  *   Paul Mackerras <paulus@samba.org>
356e750a8fSJaswinder Singh Rajput  *   Jaswinder Singh Rajput <jaswinder@kernel.org>
3686470930SIngo Molnar  *
3786470930SIngo Molnar  * Released under the GPL v2. (and only v2, not any later version)
3886470930SIngo Molnar  */
3986470930SIngo Molnar 
4086470930SIngo Molnar #include "perf.h"
4186470930SIngo Molnar #include "builtin.h"
4286470930SIngo Molnar #include "util/util.h"
4386470930SIngo Molnar #include "util/parse-options.h"
4486470930SIngo Molnar #include "util/parse-events.h"
4586470930SIngo Molnar 
4686470930SIngo Molnar #include <sys/prctl.h>
4742202dd5SIngo Molnar #include <math.h>
4886470930SIngo Molnar 
49c3043569SJaswinder Singh Rajput static struct perf_counter_attr default_attrs[] = {
5086470930SIngo Molnar 
51f4dbfa8fSPeter Zijlstra   { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK	},
52f4dbfa8fSPeter Zijlstra   { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
53f4dbfa8fSPeter Zijlstra   { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS	},
54f4dbfa8fSPeter Zijlstra   { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS	},
5586470930SIngo Molnar 
56f4dbfa8fSPeter Zijlstra   { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES	},
57f4dbfa8fSPeter Zijlstra   { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS	},
58f4dbfa8fSPeter Zijlstra   { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES},
59f4dbfa8fSPeter Zijlstra   { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES	},
60f4dbfa8fSPeter Zijlstra 
6186470930SIngo Molnar };
6286470930SIngo Molnar 
6342202dd5SIngo Molnar #define MAX_RUN			100
6486470930SIngo Molnar 
653d632595SJaswinder Singh Rajput static int			system_wide			=  0;
663d632595SJaswinder Singh Rajput static int			verbose				=  0;
67f37a291cSIngo Molnar static unsigned int		nr_cpus				=  0;
6842202dd5SIngo Molnar static int			run_idx				=  0;
6942202dd5SIngo Molnar 
703d632595SJaswinder Singh Rajput static int			run_count			=  1;
713d632595SJaswinder Singh Rajput static int			inherit				=  1;
723d632595SJaswinder Singh Rajput static int			scale				=  1;
733d632595SJaswinder Singh Rajput static int			target_pid			= -1;
740cfb7a13SIngo Molnar static int			null_run			=  0;
7542202dd5SIngo Molnar 
763d632595SJaswinder Singh Rajput static int			fd[MAX_NR_CPUS][MAX_COUNTERS];
7742202dd5SIngo Molnar 
789cffa8d5SPaul Mackerras static u64			runtime_nsecs[MAX_RUN];
799cffa8d5SPaul Mackerras static u64			walltime_nsecs[MAX_RUN];
809cffa8d5SPaul Mackerras static u64			runtime_cycles[MAX_RUN];
8142202dd5SIngo Molnar 
823d632595SJaswinder Singh Rajput static u64			event_res[MAX_RUN][MAX_COUNTERS][3];
833d632595SJaswinder Singh Rajput static u64			event_scaled[MAX_RUN][MAX_COUNTERS];
843d632595SJaswinder Singh Rajput 
859cffa8d5SPaul Mackerras static u64			event_res_avg[MAX_COUNTERS][3];
869cffa8d5SPaul Mackerras static u64			event_res_noise[MAX_COUNTERS][3];
8742202dd5SIngo Molnar 
889cffa8d5SPaul Mackerras static u64			event_scaled_avg[MAX_COUNTERS];
8942202dd5SIngo Molnar 
909cffa8d5SPaul Mackerras static u64			runtime_nsecs_avg;
919cffa8d5SPaul Mackerras static u64			runtime_nsecs_noise;
9242202dd5SIngo Molnar 
939cffa8d5SPaul Mackerras static u64			walltime_nsecs_avg;
949cffa8d5SPaul Mackerras static u64			walltime_nsecs_noise;
9542202dd5SIngo Molnar 
969cffa8d5SPaul Mackerras static u64			runtime_cycles_avg;
979cffa8d5SPaul Mackerras static u64			runtime_cycles_noise;
9886470930SIngo Molnar 
99b9ebdcc0SJaswinder Singh Rajput #define MATCH_EVENT(t, c, counter)			\
100b9ebdcc0SJaswinder Singh Rajput 	(attrs[counter].type == PERF_TYPE_##t &&	\
101b9ebdcc0SJaswinder Singh Rajput 	 attrs[counter].config == PERF_COUNT_##c)
102b9ebdcc0SJaswinder Singh Rajput 
103cca03c0aSJaswinder Singh Rajput #define ERR_PERF_OPEN \
104cca03c0aSJaswinder Singh Rajput "Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"
105cca03c0aSJaswinder Singh Rajput 
106051ae7f7SPaul Mackerras static void create_perf_stat_counter(int counter, int pid)
10786470930SIngo Molnar {
10886470930SIngo Molnar 	struct perf_counter_attr *attr = attrs + counter;
10986470930SIngo Molnar 
11086470930SIngo Molnar 	if (scale)
11186470930SIngo Molnar 		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
11286470930SIngo Molnar 				    PERF_FORMAT_TOTAL_TIME_RUNNING;
11386470930SIngo Molnar 
11486470930SIngo Molnar 	if (system_wide) {
115f37a291cSIngo Molnar 		unsigned int cpu;
116f37a291cSIngo Molnar 
11786470930SIngo Molnar 		for (cpu = 0; cpu < nr_cpus; cpu++) {
11886470930SIngo Molnar 			fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
119cca03c0aSJaswinder Singh Rajput 			if (fd[cpu][counter] < 0 && verbose)
120cca03c0aSJaswinder Singh Rajput 				fprintf(stderr, ERR_PERF_OPEN, counter,
121cca03c0aSJaswinder Singh Rajput 					fd[cpu][counter], strerror(errno));
12286470930SIngo Molnar 		}
12386470930SIngo Molnar 	} else {
12486470930SIngo Molnar 		attr->inherit	     = inherit;
12586470930SIngo Molnar 		attr->disabled	     = 1;
12657e7986eSPaul Mackerras 		attr->enable_on_exec = 1;
12786470930SIngo Molnar 
128051ae7f7SPaul Mackerras 		fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
129cca03c0aSJaswinder Singh Rajput 		if (fd[0][counter] < 0 && verbose)
130cca03c0aSJaswinder Singh Rajput 			fprintf(stderr, ERR_PERF_OPEN, counter,
131cca03c0aSJaswinder Singh Rajput 				fd[0][counter], strerror(errno));
13286470930SIngo Molnar 	}
13386470930SIngo Molnar }
13486470930SIngo Molnar 
13586470930SIngo Molnar /*
13686470930SIngo Molnar  * Does the counter have nsecs as a unit?
13786470930SIngo Molnar  */
13886470930SIngo Molnar static inline int nsec_counter(int counter)
13986470930SIngo Molnar {
140b9ebdcc0SJaswinder Singh Rajput 	if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) ||
141b9ebdcc0SJaswinder Singh Rajput 	    MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
14286470930SIngo Molnar 		return 1;
14386470930SIngo Molnar 
14486470930SIngo Molnar 	return 0;
14586470930SIngo Molnar }
14686470930SIngo Molnar 
14786470930SIngo Molnar /*
14886470930SIngo Molnar  * Read out the results of a single counter:
14986470930SIngo Molnar  */
15086470930SIngo Molnar static void read_counter(int counter)
15186470930SIngo Molnar {
1529cffa8d5SPaul Mackerras 	u64 *count, single_count[3];
153f37a291cSIngo Molnar 	unsigned int cpu;
154f37a291cSIngo Molnar 	size_t res, nv;
15586470930SIngo Molnar 	int scaled;
15686470930SIngo Molnar 
15742202dd5SIngo Molnar 	count = event_res[run_idx][counter];
15886470930SIngo Molnar 
15986470930SIngo Molnar 	count[0] = count[1] = count[2] = 0;
16086470930SIngo Molnar 
16186470930SIngo Molnar 	nv = scale ? 3 : 1;
16286470930SIngo Molnar 	for (cpu = 0; cpu < nr_cpus; cpu++) {
163743ee1f8SIngo Molnar 		if (fd[cpu][counter] < 0)
164743ee1f8SIngo Molnar 			continue;
165743ee1f8SIngo Molnar 
1669cffa8d5SPaul Mackerras 		res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
1679cffa8d5SPaul Mackerras 		assert(res == nv * sizeof(u64));
168f37a291cSIngo Molnar 
16942202dd5SIngo Molnar 		close(fd[cpu][counter]);
17042202dd5SIngo Molnar 		fd[cpu][counter] = -1;
17186470930SIngo Molnar 
17286470930SIngo Molnar 		count[0] += single_count[0];
17386470930SIngo Molnar 		if (scale) {
17486470930SIngo Molnar 			count[1] += single_count[1];
17586470930SIngo Molnar 			count[2] += single_count[2];
17686470930SIngo Molnar 		}
17786470930SIngo Molnar 	}
17886470930SIngo Molnar 
17986470930SIngo Molnar 	scaled = 0;
18086470930SIngo Molnar 	if (scale) {
18186470930SIngo Molnar 		if (count[2] == 0) {
18242202dd5SIngo Molnar 			event_scaled[run_idx][counter] = -1;
18386470930SIngo Molnar 			count[0] = 0;
18486470930SIngo Molnar 			return;
18586470930SIngo Molnar 		}
18686470930SIngo Molnar 
18786470930SIngo Molnar 		if (count[2] < count[1]) {
18842202dd5SIngo Molnar 			event_scaled[run_idx][counter] = 1;
18986470930SIngo Molnar 			count[0] = (unsigned long long)
19086470930SIngo Molnar 				((double)count[0] * count[1] / count[2] + 0.5);
19186470930SIngo Molnar 		}
19286470930SIngo Molnar 	}
19386470930SIngo Molnar 	/*
19486470930SIngo Molnar 	 * Save the full runtime - to allow normalization during printout:
19586470930SIngo Molnar 	 */
196b9ebdcc0SJaswinder Singh Rajput 	if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
19742202dd5SIngo Molnar 		runtime_nsecs[run_idx] = count[0];
198b9ebdcc0SJaswinder Singh Rajput 	if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
19942202dd5SIngo Molnar 		runtime_cycles[run_idx] = count[0];
20086470930SIngo Molnar }
20186470930SIngo Molnar 
202f37a291cSIngo Molnar static int run_perf_stat(int argc __used, const char **argv)
20386470930SIngo Molnar {
20486470930SIngo Molnar 	unsigned long long t0, t1;
20542202dd5SIngo Molnar 	int status = 0;
20686470930SIngo Molnar 	int counter;
20786470930SIngo Molnar 	int pid;
208051ae7f7SPaul Mackerras 	int child_ready_pipe[2], go_pipe[2];
209051ae7f7SPaul Mackerras 	char buf;
21086470930SIngo Molnar 
21186470930SIngo Molnar 	if (!system_wide)
21286470930SIngo Molnar 		nr_cpus = 1;
21386470930SIngo Molnar 
214051ae7f7SPaul Mackerras 	if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
215051ae7f7SPaul Mackerras 		perror("failed to create pipes");
216051ae7f7SPaul Mackerras 		exit(1);
217051ae7f7SPaul Mackerras 	}
218051ae7f7SPaul Mackerras 
219051ae7f7SPaul Mackerras 	if ((pid = fork()) < 0)
220051ae7f7SPaul Mackerras 		perror("failed to fork");
221051ae7f7SPaul Mackerras 
222051ae7f7SPaul Mackerras 	if (!pid) {
223051ae7f7SPaul Mackerras 		close(child_ready_pipe[0]);
224051ae7f7SPaul Mackerras 		close(go_pipe[1]);
225051ae7f7SPaul Mackerras 		fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
226051ae7f7SPaul Mackerras 
227051ae7f7SPaul Mackerras 		/*
228051ae7f7SPaul Mackerras 		 * Do a dummy execvp to get the PLT entry resolved,
229051ae7f7SPaul Mackerras 		 * so we avoid the resolver overhead on the real
230051ae7f7SPaul Mackerras 		 * execvp call.
231051ae7f7SPaul Mackerras 		 */
232051ae7f7SPaul Mackerras 		execvp("", (char **)argv);
233051ae7f7SPaul Mackerras 
234051ae7f7SPaul Mackerras 		/*
235051ae7f7SPaul Mackerras 		 * Tell the parent we're ready to go
236051ae7f7SPaul Mackerras 		 */
237051ae7f7SPaul Mackerras 		close(child_ready_pipe[1]);
238051ae7f7SPaul Mackerras 
239051ae7f7SPaul Mackerras 		/*
240051ae7f7SPaul Mackerras 		 * Wait until the parent tells us to go.
241051ae7f7SPaul Mackerras 		 */
242051ae7f7SPaul Mackerras 		read(go_pipe[0], &buf, 1);
243051ae7f7SPaul Mackerras 
244051ae7f7SPaul Mackerras 		execvp(argv[0], (char **)argv);
245051ae7f7SPaul Mackerras 
246051ae7f7SPaul Mackerras 		perror(argv[0]);
247051ae7f7SPaul Mackerras 		exit(-1);
248051ae7f7SPaul Mackerras 	}
249051ae7f7SPaul Mackerras 
250051ae7f7SPaul Mackerras 	/*
251051ae7f7SPaul Mackerras 	 * Wait for the child to be ready to exec.
252051ae7f7SPaul Mackerras 	 */
253051ae7f7SPaul Mackerras 	close(child_ready_pipe[1]);
254051ae7f7SPaul Mackerras 	close(go_pipe[0]);
255051ae7f7SPaul Mackerras 	read(child_ready_pipe[0], &buf, 1);
256051ae7f7SPaul Mackerras 	close(child_ready_pipe[0]);
257051ae7f7SPaul Mackerras 
25886470930SIngo Molnar 	for (counter = 0; counter < nr_counters; counter++)
259051ae7f7SPaul Mackerras 		create_perf_stat_counter(counter, pid);
26086470930SIngo Molnar 
26186470930SIngo Molnar 	/*
26286470930SIngo Molnar 	 * Enable counters and exec the command:
26386470930SIngo Molnar 	 */
26486470930SIngo Molnar 	t0 = rdclock();
26586470930SIngo Molnar 
266051ae7f7SPaul Mackerras 	close(go_pipe[1]);
26742202dd5SIngo Molnar 	wait(&status);
26886470930SIngo Molnar 
26986470930SIngo Molnar 	t1 = rdclock();
27086470930SIngo Molnar 
27142202dd5SIngo Molnar 	walltime_nsecs[run_idx] = t1 - t0;
27242202dd5SIngo Molnar 
27342202dd5SIngo Molnar 	for (counter = 0; counter < nr_counters; counter++)
27442202dd5SIngo Molnar 		read_counter(counter);
27542202dd5SIngo Molnar 
27642202dd5SIngo Molnar 	return WEXITSTATUS(status);
27742202dd5SIngo Molnar }
27842202dd5SIngo Molnar 
2799cffa8d5SPaul Mackerras static void print_noise(u64 *count, u64 *noise)
28042202dd5SIngo Molnar {
28142202dd5SIngo Molnar 	if (run_count > 1)
28242202dd5SIngo Molnar 		fprintf(stderr, "   ( +- %7.3f%% )",
28342202dd5SIngo Molnar 			(double)noise[0]/(count[0]+1)*100.0);
28442202dd5SIngo Molnar }
28542202dd5SIngo Molnar 
2869cffa8d5SPaul Mackerras static void nsec_printout(int counter, u64 *count, u64 *noise)
28742202dd5SIngo Molnar {
28842202dd5SIngo Molnar 	double msecs = (double)count[0] / 1000000;
28942202dd5SIngo Molnar 
2906e750a8fSJaswinder Singh Rajput 	fprintf(stderr, " %14.6f  %-24s", msecs, event_name(counter));
29142202dd5SIngo Molnar 
292b9ebdcc0SJaswinder Singh Rajput 	if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
29342202dd5SIngo Molnar 		if (walltime_nsecs_avg)
29442202dd5SIngo Molnar 			fprintf(stderr, " # %10.3f CPUs ",
29542202dd5SIngo Molnar 				(double)count[0] / (double)walltime_nsecs_avg);
29642202dd5SIngo Molnar 	}
29742202dd5SIngo Molnar 	print_noise(count, noise);
29842202dd5SIngo Molnar }
29942202dd5SIngo Molnar 
3009cffa8d5SPaul Mackerras static void abs_printout(int counter, u64 *count, u64 *noise)
30142202dd5SIngo Molnar {
3026e750a8fSJaswinder Singh Rajput 	fprintf(stderr, " %14Ld  %-24s", count[0], event_name(counter));
30342202dd5SIngo Molnar 
30442202dd5SIngo Molnar 	if (runtime_cycles_avg &&
305b9ebdcc0SJaswinder Singh Rajput 	    MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
30642202dd5SIngo Molnar 		fprintf(stderr, " # %10.3f IPC  ",
30742202dd5SIngo Molnar 			(double)count[0] / (double)runtime_cycles_avg);
30842202dd5SIngo Molnar 	} else {
30942202dd5SIngo Molnar 		if (runtime_nsecs_avg) {
31042202dd5SIngo Molnar 			fprintf(stderr, " # %10.3f M/sec",
31142202dd5SIngo Molnar 				(double)count[0]/runtime_nsecs_avg*1000.0);
31242202dd5SIngo Molnar 		}
31342202dd5SIngo Molnar 	}
31442202dd5SIngo Molnar 	print_noise(count, noise);
31542202dd5SIngo Molnar }
31642202dd5SIngo Molnar 
31742202dd5SIngo Molnar /*
31842202dd5SIngo Molnar  * Print out the results of a single counter:
31942202dd5SIngo Molnar  */
32042202dd5SIngo Molnar static void print_counter(int counter)
32142202dd5SIngo Molnar {
3229cffa8d5SPaul Mackerras 	u64 *count, *noise;
32342202dd5SIngo Molnar 	int scaled;
32442202dd5SIngo Molnar 
32542202dd5SIngo Molnar 	count = event_res_avg[counter];
32642202dd5SIngo Molnar 	noise = event_res_noise[counter];
32742202dd5SIngo Molnar 	scaled = event_scaled_avg[counter];
32842202dd5SIngo Molnar 
32942202dd5SIngo Molnar 	if (scaled == -1) {
3306e750a8fSJaswinder Singh Rajput 		fprintf(stderr, " %14s  %-24s\n",
33142202dd5SIngo Molnar 			"<not counted>", event_name(counter));
33242202dd5SIngo Molnar 		return;
33342202dd5SIngo Molnar 	}
33442202dd5SIngo Molnar 
33542202dd5SIngo Molnar 	if (nsec_counter(counter))
33642202dd5SIngo Molnar 		nsec_printout(counter, count, noise);
33742202dd5SIngo Molnar 	else
33842202dd5SIngo Molnar 		abs_printout(counter, count, noise);
33942202dd5SIngo Molnar 
34042202dd5SIngo Molnar 	if (scaled)
341210ad39fSIngo Molnar 		fprintf(stderr, "  (scaled from %.2f%%)",
342210ad39fSIngo Molnar 			(double) count[2] / count[1] * 100);
34342202dd5SIngo Molnar 
34442202dd5SIngo Molnar 	fprintf(stderr, "\n");
34542202dd5SIngo Molnar }
34642202dd5SIngo Molnar 
34742202dd5SIngo Molnar /*
348ef281a19SIngo Molnar  * normalize_noise noise values down to stddev:
34942202dd5SIngo Molnar  */
3509cffa8d5SPaul Mackerras static void normalize_noise(u64 *val)
35142202dd5SIngo Molnar {
35242202dd5SIngo Molnar 	double res;
35342202dd5SIngo Molnar 
35442202dd5SIngo Molnar 	res = (double)*val / (run_count * sqrt((double)run_count));
35542202dd5SIngo Molnar 
3569cffa8d5SPaul Mackerras 	*val = (u64)res;
35742202dd5SIngo Molnar }
35842202dd5SIngo Molnar 
3599cffa8d5SPaul Mackerras static void update_avg(const char *name, int idx, u64 *avg, u64 *val)
360ef281a19SIngo Molnar {
361ef281a19SIngo Molnar 	*avg += *val;
362ef281a19SIngo Molnar 
363ef281a19SIngo Molnar 	if (verbose > 1)
364ef281a19SIngo Molnar 		fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
365ef281a19SIngo Molnar }
36642202dd5SIngo Molnar /*
36742202dd5SIngo Molnar  * Calculate the averages and noises:
36842202dd5SIngo Molnar  */
36942202dd5SIngo Molnar static void calc_avg(void)
37042202dd5SIngo Molnar {
37142202dd5SIngo Molnar 	int i, j;
37242202dd5SIngo Molnar 
373ef281a19SIngo Molnar 	if (verbose > 1)
374ef281a19SIngo Molnar 		fprintf(stderr, "\n");
375ef281a19SIngo Molnar 
37642202dd5SIngo Molnar 	for (i = 0; i < run_count; i++) {
377ef281a19SIngo Molnar 		update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i);
378ef281a19SIngo Molnar 		update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i);
379ef281a19SIngo Molnar 		update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i);
38042202dd5SIngo Molnar 
38142202dd5SIngo Molnar 		for (j = 0; j < nr_counters; j++) {
382ef281a19SIngo Molnar 			update_avg("counter/0", j,
383ef281a19SIngo Molnar 				event_res_avg[j]+0, event_res[i][j]+0);
384ef281a19SIngo Molnar 			update_avg("counter/1", j,
385ef281a19SIngo Molnar 				event_res_avg[j]+1, event_res[i][j]+1);
386ef281a19SIngo Molnar 			update_avg("counter/2", j,
387ef281a19SIngo Molnar 				event_res_avg[j]+2, event_res[i][j]+2);
388f37a291cSIngo Molnar 			if (event_scaled[i][j] != (u64)-1)
389ef281a19SIngo Molnar 				update_avg("scaled", j,
390ef281a19SIngo Molnar 					event_scaled_avg + j, event_scaled[i]+j);
391566747e6SIngo Molnar 			else
392566747e6SIngo Molnar 				event_scaled_avg[j] = -1;
39342202dd5SIngo Molnar 		}
39442202dd5SIngo Molnar 	}
39542202dd5SIngo Molnar 	runtime_nsecs_avg /= run_count;
39642202dd5SIngo Molnar 	walltime_nsecs_avg /= run_count;
39742202dd5SIngo Molnar 	runtime_cycles_avg /= run_count;
39842202dd5SIngo Molnar 
39942202dd5SIngo Molnar 	for (j = 0; j < nr_counters; j++) {
40042202dd5SIngo Molnar 		event_res_avg[j][0] /= run_count;
40142202dd5SIngo Molnar 		event_res_avg[j][1] /= run_count;
40242202dd5SIngo Molnar 		event_res_avg[j][2] /= run_count;
40342202dd5SIngo Molnar 	}
40442202dd5SIngo Molnar 
40542202dd5SIngo Molnar 	for (i = 0; i < run_count; i++) {
40642202dd5SIngo Molnar 		runtime_nsecs_noise +=
4079cffa8d5SPaul Mackerras 			abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
40842202dd5SIngo Molnar 		walltime_nsecs_noise +=
4099cffa8d5SPaul Mackerras 			abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
41042202dd5SIngo Molnar 		runtime_cycles_noise +=
4119cffa8d5SPaul Mackerras 			abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
41242202dd5SIngo Molnar 
41342202dd5SIngo Molnar 		for (j = 0; j < nr_counters; j++) {
41442202dd5SIngo Molnar 			event_res_noise[j][0] +=
4159cffa8d5SPaul Mackerras 				abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
41642202dd5SIngo Molnar 			event_res_noise[j][1] +=
4179cffa8d5SPaul Mackerras 				abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
41842202dd5SIngo Molnar 			event_res_noise[j][2] +=
4199cffa8d5SPaul Mackerras 				abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
42042202dd5SIngo Molnar 		}
42142202dd5SIngo Molnar 	}
42242202dd5SIngo Molnar 
423ef281a19SIngo Molnar 	normalize_noise(&runtime_nsecs_noise);
424ef281a19SIngo Molnar 	normalize_noise(&walltime_nsecs_noise);
425ef281a19SIngo Molnar 	normalize_noise(&runtime_cycles_noise);
42642202dd5SIngo Molnar 
42742202dd5SIngo Molnar 	for (j = 0; j < nr_counters; j++) {
428ef281a19SIngo Molnar 		normalize_noise(&event_res_noise[j][0]);
429ef281a19SIngo Molnar 		normalize_noise(&event_res_noise[j][1]);
430ef281a19SIngo Molnar 		normalize_noise(&event_res_noise[j][2]);
43142202dd5SIngo Molnar 	}
43242202dd5SIngo Molnar }
43342202dd5SIngo Molnar 
43442202dd5SIngo Molnar static void print_stat(int argc, const char **argv)
43542202dd5SIngo Molnar {
43642202dd5SIngo Molnar 	int i, counter;
43742202dd5SIngo Molnar 
43842202dd5SIngo Molnar 	calc_avg();
43942202dd5SIngo Molnar 
44086470930SIngo Molnar 	fflush(stdout);
44186470930SIngo Molnar 
44286470930SIngo Molnar 	fprintf(stderr, "\n");
44386470930SIngo Molnar 	fprintf(stderr, " Performance counter stats for \'%s", argv[0]);
44486470930SIngo Molnar 
44586470930SIngo Molnar 	for (i = 1; i < argc; i++)
44686470930SIngo Molnar 		fprintf(stderr, " %s", argv[i]);
44786470930SIngo Molnar 
44842202dd5SIngo Molnar 	fprintf(stderr, "\'");
44942202dd5SIngo Molnar 	if (run_count > 1)
45042202dd5SIngo Molnar 		fprintf(stderr, " (%d runs)", run_count);
45142202dd5SIngo Molnar 	fprintf(stderr, ":\n\n");
45286470930SIngo Molnar 
45386470930SIngo Molnar 	for (counter = 0; counter < nr_counters; counter++)
45486470930SIngo Molnar 		print_counter(counter);
45586470930SIngo Molnar 
45686470930SIngo Molnar 	fprintf(stderr, "\n");
457566747e6SIngo Molnar 	fprintf(stderr, " %14.9f  seconds time elapsed",
45842202dd5SIngo Molnar 			(double)walltime_nsecs_avg/1e9);
459566747e6SIngo Molnar 	if (run_count > 1) {
460566747e6SIngo Molnar 		fprintf(stderr, "   ( +- %7.3f%% )",
461566747e6SIngo Molnar 			100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg);
462566747e6SIngo Molnar 	}
463566747e6SIngo Molnar 	fprintf(stderr, "\n\n");
46486470930SIngo Molnar }
46586470930SIngo Molnar 
466f7b7c26eSPeter Zijlstra static volatile int signr = -1;
467f7b7c26eSPeter Zijlstra 
46886470930SIngo Molnar static void skip_signal(int signo)
46986470930SIngo Molnar {
470f7b7c26eSPeter Zijlstra 	signr = signo;
471f7b7c26eSPeter Zijlstra }
472f7b7c26eSPeter Zijlstra 
473f7b7c26eSPeter Zijlstra static void sig_atexit(void)
474f7b7c26eSPeter Zijlstra {
475f7b7c26eSPeter Zijlstra 	if (signr == -1)
476f7b7c26eSPeter Zijlstra 		return;
477f7b7c26eSPeter Zijlstra 
478f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
479f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
48086470930SIngo Molnar }
48186470930SIngo Molnar 
48286470930SIngo Molnar static const char * const stat_usage[] = {
48386470930SIngo Molnar 	"perf stat [<options>] <command>",
48486470930SIngo Molnar 	NULL
48586470930SIngo Molnar };
48686470930SIngo Molnar 
48786470930SIngo Molnar static const struct option options[] = {
48886470930SIngo Molnar 	OPT_CALLBACK('e', "event", NULL, "event",
48986470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
49086470930SIngo Molnar 		     parse_events),
49186470930SIngo Molnar 	OPT_BOOLEAN('i', "inherit", &inherit,
49286470930SIngo Molnar 		    "child tasks inherit counters"),
49386470930SIngo Molnar 	OPT_INTEGER('p', "pid", &target_pid,
49486470930SIngo Molnar 		    "stat events on existing pid"),
49586470930SIngo Molnar 	OPT_BOOLEAN('a', "all-cpus", &system_wide,
49686470930SIngo Molnar 		    "system-wide collection from all CPUs"),
49786470930SIngo Molnar 	OPT_BOOLEAN('S', "scale", &scale,
49886470930SIngo Molnar 		    "scale/normalize counters"),
499743ee1f8SIngo Molnar 	OPT_BOOLEAN('v', "verbose", &verbose,
500743ee1f8SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
50142202dd5SIngo Molnar 	OPT_INTEGER('r', "repeat", &run_count,
50242202dd5SIngo Molnar 		    "repeat command and print average + stddev (max: 100)"),
5030cfb7a13SIngo Molnar 	OPT_BOOLEAN('n', "null", &null_run,
5040cfb7a13SIngo Molnar 		    "null run - dont start any counters"),
50586470930SIngo Molnar 	OPT_END()
50686470930SIngo Molnar };
50786470930SIngo Molnar 
508f37a291cSIngo Molnar int cmd_stat(int argc, const char **argv, const char *prefix __used)
50986470930SIngo Molnar {
51042202dd5SIngo Molnar 	int status;
51142202dd5SIngo Molnar 
51286470930SIngo Molnar 	argc = parse_options(argc, argv, options, stat_usage, 0);
51386470930SIngo Molnar 	if (!argc)
51486470930SIngo Molnar 		usage_with_options(stat_usage, options);
51542202dd5SIngo Molnar 	if (run_count <= 0 || run_count > MAX_RUN)
51642202dd5SIngo Molnar 		usage_with_options(stat_usage, options);
51786470930SIngo Molnar 
518c3043569SJaswinder Singh Rajput 	/* Set attrs and nr_counters if no event is selected and !null_run */
519c3043569SJaswinder Singh Rajput 	if (!null_run && !nr_counters) {
520c3043569SJaswinder Singh Rajput 		memcpy(attrs, default_attrs, sizeof(default_attrs));
521c3043569SJaswinder Singh Rajput 		nr_counters = ARRAY_SIZE(default_attrs);
522c3043569SJaswinder Singh Rajput 	}
52386470930SIngo Molnar 
52486470930SIngo Molnar 	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
52586470930SIngo Molnar 	assert(nr_cpus <= MAX_NR_CPUS);
526f37a291cSIngo Molnar 	assert((int)nr_cpus >= 0);
52786470930SIngo Molnar 
52886470930SIngo Molnar 	/*
52986470930SIngo Molnar 	 * We dont want to block the signals - that would cause
53086470930SIngo Molnar 	 * child tasks to inherit that and Ctrl-C would not work.
53186470930SIngo Molnar 	 * What we want is for Ctrl-C to work in the exec()-ed
53286470930SIngo Molnar 	 * task, but being ignored by perf stat itself:
53386470930SIngo Molnar 	 */
534f7b7c26eSPeter Zijlstra 	atexit(sig_atexit);
53586470930SIngo Molnar 	signal(SIGINT,  skip_signal);
53686470930SIngo Molnar 	signal(SIGALRM, skip_signal);
53786470930SIngo Molnar 	signal(SIGABRT, skip_signal);
53886470930SIngo Molnar 
53942202dd5SIngo Molnar 	status = 0;
54042202dd5SIngo Molnar 	for (run_idx = 0; run_idx < run_count; run_idx++) {
54142202dd5SIngo Molnar 		if (run_count != 1 && verbose)
54242202dd5SIngo Molnar 			fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
54342202dd5SIngo Molnar 		status = run_perf_stat(argc, argv);
54442202dd5SIngo Molnar 	}
54542202dd5SIngo Molnar 
54642202dd5SIngo Molnar 	print_stat(argc, argv);
54742202dd5SIngo Molnar 
54842202dd5SIngo Molnar 	return status;
54986470930SIngo Molnar }
550