blob: 0c92eb7255261a23242c80c46abb6a1df8927e34 [file] [log] [blame]
Ingo Molnarddcacfa2009-04-20 15:37:32 +02001/*
Ingo Molnar52425192009-05-26 09:17:18 +02002 * perf stat: /usr/bin/time -alike performance counter statistics utility
Ingo Molnarddcacfa2009-04-20 15:37:32 +02003
4 It summarizes the counter events of all tasks (and child tasks),
5 covering all CPUs that the command (or workload) executes on.
6 It only counts the per-task events of the workload started,
7 independent of how many other tasks run on those CPUs.
8
9 Sample output:
10
Ingo Molnar52425192009-05-26 09:17:18 +020011 $ perf stat -e 1 -e 3 -e 5 ls -lR /usr/include/ >/dev/null
Ingo Molnarddcacfa2009-04-20 15:37:32 +020012
13 Performance counter stats for 'ls':
14
15 163516953 instructions
16 2295 cache-misses
17 2855182 branch-misses
Ingo Molnar52425192009-05-26 09:17:18 +020018 *
19 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
20 *
21 * Improvements and fixes by:
22 *
23 * Arjan van de Ven <arjan@linux.intel.com>
24 * Yanmin Zhang <yanmin.zhang@intel.com>
25 * Wu Fengguang <fengguang.wu@intel.com>
26 * Mike Galbraith <efault@gmx.de>
27 * Paul Mackerras <paulus@samba.org>
28 *
29 * Released under the GPL v2. (and only v2, not any later version)
Ingo Molnarddcacfa2009-04-20 15:37:32 +020030 */
31
Peter Zijlstra1a482f32009-05-23 18:28:58 +020032#include "perf.h"
Ingo Molnar16f762a2009-05-27 09:10:38 +020033#include "builtin.h"
Ingo Molnar148be2c2009-04-27 08:02:14 +020034#include "util/util.h"
Ingo Molnar52425192009-05-26 09:17:18 +020035#include "util/parse-options.h"
36#include "util/parse-events.h"
Ingo Molnarddcacfa2009-04-20 15:37:32 +020037
Ingo Molnarddcacfa2009-04-20 15:37:32 +020038#include <sys/prctl.h>
Peter Zijlstra16c8a102009-05-05 17:50:27 +020039
Ingo Molnarddcacfa2009-04-20 15:37:32 +020040static int system_wide = 0;
Ingo Molnar52425192009-05-26 09:17:18 +020041static int inherit = 1;
Ingo Molnarddcacfa2009-04-20 15:37:32 +020042
Ingo Molnar52425192009-05-26 09:17:18 +020043static __u64 default_event_id[MAX_COUNTERS] = {
Ingo Molnarddcacfa2009-04-20 15:37:32 +020044 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
45 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),
46 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
47 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),
48
49 EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES),
50 EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS),
51 EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES),
52 EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES),
53};
Ingo Molnar52425192009-05-26 09:17:18 +020054
Ingo Molnarddcacfa2009-04-20 15:37:32 +020055static int default_interval = 100000;
56static int event_count[MAX_COUNTERS];
57static int fd[MAX_NR_CPUS][MAX_COUNTERS];
58
Ingo Molnar52425192009-05-26 09:17:18 +020059static int target_pid = -1;
Ingo Molnarddcacfa2009-04-20 15:37:32 +020060static int nr_cpus = 0;
Ingo Molnarddcacfa2009-04-20 15:37:32 +020061static unsigned int page_size;
62
Ingo Molnar66cf7822009-04-30 13:53:33 +020063static int scale = 1;
Ingo Molnarddcacfa2009-04-20 15:37:32 +020064
65static const unsigned int default_count[] = {
66 1000000,
67 1000000,
68 10000,
69 10000,
70 1000000,
71 10000,
72};
73
Ingo Molnar2996f5d2009-05-29 09:10:54 +020074static __u64 event_res[MAX_COUNTERS][3];
75static __u64 event_scaled[MAX_COUNTERS];
76
Ingo Molnarddcacfa2009-04-20 15:37:32 +020077static void create_perfstat_counter(int counter)
78{
79 struct perf_counter_hw_event hw_event;
80
81 memset(&hw_event, 0, sizeof(hw_event));
82 hw_event.config = event_id[counter];
83 hw_event.record_type = 0;
Ingo Molnar52425192009-05-26 09:17:18 +020084 hw_event.nmi = 1;
Peter Zijlstra16c8a102009-05-05 17:50:27 +020085 hw_event.exclude_kernel = event_mask[counter] & EVENT_MASK_KERNEL;
86 hw_event.exclude_user = event_mask[counter] & EVENT_MASK_USER;
87
Ingo Molnarddcacfa2009-04-20 15:37:32 +020088 if (scale)
89 hw_event.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
90 PERF_FORMAT_TOTAL_TIME_RUNNING;
91
92 if (system_wide) {
93 int cpu;
94 for (cpu = 0; cpu < nr_cpus; cpu ++) {
95 fd[cpu][counter] = sys_perf_counter_open(&hw_event, -1, cpu, -1, 0);
96 if (fd[cpu][counter] < 0) {
97 printf("perfstat error: syscall returned with %d (%s)\n",
98 fd[cpu][counter], strerror(errno));
99 exit(-1);
100 }
101 }
102 } else {
Ingo Molnar52425192009-05-26 09:17:18 +0200103 hw_event.inherit = inherit;
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200104 hw_event.disabled = 1;
105
106 fd[0][counter] = sys_perf_counter_open(&hw_event, 0, -1, -1, 0);
107 if (fd[0][counter] < 0) {
108 printf("perfstat error: syscall returned with %d (%s)\n",
109 fd[0][counter], strerror(errno));
110 exit(-1);
111 }
112 }
113}
114
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200115/*
116 * Does the counter have nsecs as a unit?
117 */
118static inline int nsec_counter(int counter)
119{
120 if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK))
121 return 1;
122 if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK))
123 return 1;
124
125 return 0;
126}
127
128/*
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200129 * Read out the results of a single counter:
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200130 */
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200131static void read_counter(int counter)
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200132{
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200133 __u64 *count, single_count[3];
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200134 ssize_t res;
135 int cpu, nv;
136 int scaled;
137
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200138 count = event_res[counter];
139
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200140 count[0] = count[1] = count[2] = 0;
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200141
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200142 nv = scale ? 3 : 1;
143 for (cpu = 0; cpu < nr_cpus; cpu ++) {
144 res = read(fd[cpu][counter], single_count, nv * sizeof(__u64));
145 assert(res == nv * sizeof(__u64));
146
147 count[0] += single_count[0];
148 if (scale) {
149 count[1] += single_count[1];
150 count[2] += single_count[2];
151 }
152 }
153
154 scaled = 0;
155 if (scale) {
156 if (count[2] == 0) {
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200157 event_scaled[counter] = -1;
158 count[0] = 0;
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200159 return;
160 }
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200161
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200162 if (count[2] < count[1]) {
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200163 event_scaled[counter] = 1;
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200164 count[0] = (unsigned long long)
165 ((double)count[0] * count[1] / count[2] + 0.5);
166 }
167 }
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200168}
169
170/*
171 * Print out the results of a single counter:
172 */
173static void print_counter(int counter)
174{
175 __u64 *count;
176 int scaled;
177
178 count = event_res[counter];
179 scaled = event_scaled[counter];
180
181 if (scaled == -1) {
182 fprintf(stderr, " %14s %-20s\n",
183 "<not counted>", event_name(counter));
184 return;
185 }
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200186
187 if (nsec_counter(counter)) {
188 double msecs = (double)count[0] / 1000000;
189
190 fprintf(stderr, " %14.6f %-20s (msecs)",
191 msecs, event_name(counter));
192 } else {
193 fprintf(stderr, " %14Ld %-20s (events)",
194 count[0], event_name(counter));
195 }
196 if (scaled)
197 fprintf(stderr, " (scaled from %.2f%%)",
198 (double) count[2] / count[1] * 100);
199 fprintf(stderr, "\n");
200}
201
Ingo Molnar16f762a2009-05-27 09:10:38 +0200202static int do_perfstat(int argc, const char **argv)
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200203{
204 unsigned long long t0, t1;
205 int counter;
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200206 int status;
207 int pid;
208
209 if (!system_wide)
210 nr_cpus = 1;
211
212 for (counter = 0; counter < nr_counters; counter++)
213 create_perfstat_counter(counter);
214
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200215 /*
216 * Enable counters and exec the command:
217 */
218 t0 = rdclock();
219 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
220
221 if ((pid = fork()) < 0)
222 perror("failed to fork");
223 if (!pid) {
Ingo Molnar52425192009-05-26 09:17:18 +0200224 if (execvp(argv[0], (char **)argv)) {
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200225 perror(argv[0]);
226 exit(-1);
227 }
228 }
229 while (wait(&status) >= 0)
230 ;
231 prctl(PR_TASK_PERF_COUNTERS_DISABLE);
232 t1 = rdclock();
233
234 fflush(stdout);
235
236 fprintf(stderr, "\n");
237 fprintf(stderr, " Performance counter stats for \'%s\':\n",
238 argv[0]);
239 fprintf(stderr, "\n");
240
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200241 for (counter = 0; counter < nr_counters; counter++)
Ingo Molnar2996f5d2009-05-29 09:10:54 +0200242 read_counter(counter);
243
244 for (counter = 0; counter < nr_counters; counter++)
Ingo Molnarc04f5e52009-05-29 09:10:54 +0200245 print_counter(counter);
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200246
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200247
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200248 fprintf(stderr, "\n");
249 fprintf(stderr, " Wall-clock time elapsed: %12.6f msecs\n",
250 (double)(t1-t0)/1e6);
251 fprintf(stderr, "\n");
252
253 return 0;
254}
255
Ingo Molnar52425192009-05-26 09:17:18 +0200256static void skip_signal(int signo)
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200257{
Ingo Molnar52425192009-05-26 09:17:18 +0200258}
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200259
Ingo Molnar52425192009-05-26 09:17:18 +0200260static const char * const stat_usage[] = {
261 "perf stat [<options>] <command>",
262 NULL
263};
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200264
Ingo Molnar52425192009-05-26 09:17:18 +0200265static char events_help_msg[EVENTS_HELP_MAX];
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200266
Ingo Molnar52425192009-05-26 09:17:18 +0200267static const struct option options[] = {
268 OPT_CALLBACK('e', "event", NULL, "event",
269 events_help_msg, parse_events),
270 OPT_INTEGER('c', "count", &default_interval,
271 "event period to sample"),
272 OPT_BOOLEAN('i', "inherit", &inherit,
273 "child tasks inherit counters"),
274 OPT_INTEGER('p', "pid", &target_pid,
275 "stat events on existing pid"),
276 OPT_BOOLEAN('a', "all-cpus", &system_wide,
277 "system-wide collection from all CPUs"),
278 OPT_BOOLEAN('l', "scale", &scale,
279 "scale/normalize counters"),
280 OPT_END()
281};
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200282
Ingo Molnar52425192009-05-26 09:17:18 +0200283int cmd_stat(int argc, const char **argv, const char *prefix)
284{
285 int counter;
286
287 page_size = sysconf(_SC_PAGE_SIZE);
288
289 create_events_help(events_help_msg);
290 memcpy(event_id, default_event_id, sizeof(default_event_id));
291
292 argc = parse_options(argc, argv, options, stat_usage, 0);
293 if (!argc)
294 usage_with_options(stat_usage, options);
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200295
296 if (!nr_counters) {
297 nr_counters = 8;
298 }
299
300 for (counter = 0; counter < nr_counters; counter++) {
301 if (event_count[counter])
302 continue;
303
304 event_count[counter] = default_interval;
305 }
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200306 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
307 assert(nr_cpus <= MAX_NR_CPUS);
308 assert(nr_cpus >= 0);
309
Ingo Molnar58d7e992009-05-15 11:03:23 +0200310 /*
311 * We dont want to block the signals - that would cause
312 * child tasks to inherit that and Ctrl-C would not work.
313 * What we want is for Ctrl-C to work in the exec()-ed
314 * task, but being ignored by perf stat itself:
315 */
316 signal(SIGINT, skip_signal);
317 signal(SIGALRM, skip_signal);
318 signal(SIGABRT, skip_signal);
319
Ingo Molnarddcacfa2009-04-20 15:37:32 +0200320 return do_perfstat(argc, argv);
321}