perf_counter tools: Add locking to perf top
[linux-2.6-block.git] / Documentation / perf_counter / builtin-stat.c
CommitLineData
ddcacfa0 1/*
5242519b 2 * perf stat: /usr/bin/time -alike performance counter statistics utility
ddcacfa0
IM
3
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
5242519b 11 $ perf stat -e 1 -e 3 -e 5 ls -lR /usr/include/ >/dev/null
ddcacfa0
IM
12
13 Performance counter stats for 'ls':
14
15 163516953 instructions
16 2295 cache-misses
17 2855182 branch-misses
5242519b
IM
18 *
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)
ddcacfa0
IM
30 */
31
1a482f38 32#include "perf.h"
16f762a2 33#include "builtin.h"
148be2c1 34#include "util/util.h"
5242519b
IM
35#include "util/parse-options.h"
36#include "util/parse-events.h"
ddcacfa0 37
ddcacfa0 38#include <sys/prctl.h>
16c8a109 39
ddcacfa0 40static int system_wide = 0;
5242519b 41static int inherit = 1;
ddcacfa0 42
5242519b 43static __u64 default_event_id[MAX_COUNTERS] = {
ddcacfa0
IM
44 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};
5242519b 54
ddcacfa0
IM
55static int default_interval = 100000;
56static int event_count[MAX_COUNTERS];
57static int fd[MAX_NR_CPUS][MAX_COUNTERS];
58
5242519b 59static int target_pid = -1;
ddcacfa0 60static int nr_cpus = 0;
ddcacfa0
IM
61static unsigned int page_size;
62
66cf7829 63static int scale = 1;
ddcacfa0
IM
64
65static const unsigned int default_count[] = {
66 1000000,
67 1000000,
68 10000,
69 10000,
70 1000000,
71 10000,
72};
73
2996f5dd
IM
74static __u64 event_res[MAX_COUNTERS][3];
75static __u64 event_scaled[MAX_COUNTERS];
76
be1ac0d8
IM
77static __u64 runtime_nsecs;
78
ddcacfa0
IM
79static void create_perfstat_counter(int counter)
80{
81 struct perf_counter_hw_event hw_event;
82
83 memset(&hw_event, 0, sizeof(hw_event));
84 hw_event.config = event_id[counter];
85 hw_event.record_type = 0;
5242519b 86 hw_event.nmi = 1;
16c8a109
PZ
87 hw_event.exclude_kernel = event_mask[counter] & EVENT_MASK_KERNEL;
88 hw_event.exclude_user = event_mask[counter] & EVENT_MASK_USER;
89
ddcacfa0
IM
90 if (scale)
91 hw_event.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
92 PERF_FORMAT_TOTAL_TIME_RUNNING;
93
94 if (system_wide) {
95 int cpu;
96 for (cpu = 0; cpu < nr_cpus; cpu ++) {
97 fd[cpu][counter] = sys_perf_counter_open(&hw_event, -1, cpu, -1, 0);
98 if (fd[cpu][counter] < 0) {
99 printf("perfstat error: syscall returned with %d (%s)\n",
100 fd[cpu][counter], strerror(errno));
101 exit(-1);
102 }
103 }
104 } else {
5242519b 105 hw_event.inherit = inherit;
ddcacfa0
IM
106 hw_event.disabled = 1;
107
108 fd[0][counter] = sys_perf_counter_open(&hw_event, 0, -1, -1, 0);
109 if (fd[0][counter] < 0) {
110 printf("perfstat error: syscall returned with %d (%s)\n",
111 fd[0][counter], strerror(errno));
112 exit(-1);
113 }
114 }
115}
116
c04f5e5d
IM
117/*
118 * Does the counter have nsecs as a unit?
119 */
120static inline int nsec_counter(int counter)
121{
122 if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK))
123 return 1;
124 if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK))
125 return 1;
126
127 return 0;
128}
129
130/*
2996f5dd 131 * Read out the results of a single counter:
c04f5e5d 132 */
2996f5dd 133static void read_counter(int counter)
c04f5e5d 134{
2996f5dd 135 __u64 *count, single_count[3];
c04f5e5d
IM
136 ssize_t res;
137 int cpu, nv;
138 int scaled;
139
2996f5dd
IM
140 count = event_res[counter];
141
c04f5e5d 142 count[0] = count[1] = count[2] = 0;
2996f5dd 143
c04f5e5d
IM
144 nv = scale ? 3 : 1;
145 for (cpu = 0; cpu < nr_cpus; cpu ++) {
146 res = read(fd[cpu][counter], single_count, nv * sizeof(__u64));
147 assert(res == nv * sizeof(__u64));
148
149 count[0] += single_count[0];
150 if (scale) {
151 count[1] += single_count[1];
152 count[2] += single_count[2];
153 }
154 }
155
156 scaled = 0;
157 if (scale) {
158 if (count[2] == 0) {
2996f5dd
IM
159 event_scaled[counter] = -1;
160 count[0] = 0;
c04f5e5d
IM
161 return;
162 }
2996f5dd 163
c04f5e5d 164 if (count[2] < count[1]) {
2996f5dd 165 event_scaled[counter] = 1;
c04f5e5d
IM
166 count[0] = (unsigned long long)
167 ((double)count[0] * count[1] / count[2] + 0.5);
168 }
169 }
be1ac0d8
IM
170 /*
171 * Save the full runtime - to allow normalization during printout:
172 */
173 if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK))
174 runtime_nsecs = count[0];
2996f5dd
IM
175}
176
177/*
178 * Print out the results of a single counter:
179 */
180static void print_counter(int counter)
181{
182 __u64 *count;
183 int scaled;
184
185 count = event_res[counter];
186 scaled = event_scaled[counter];
187
188 if (scaled == -1) {
189 fprintf(stderr, " %14s %-20s\n",
190 "<not counted>", event_name(counter));
191 return;
192 }
c04f5e5d
IM
193
194 if (nsec_counter(counter)) {
195 double msecs = (double)count[0] / 1000000;
196
197 fprintf(stderr, " %14.6f %-20s (msecs)",
198 msecs, event_name(counter));
199 } else {
be1ac0d8 200 fprintf(stderr, " %14Ld %-20s",
c04f5e5d 201 count[0], event_name(counter));
be1ac0d8
IM
202 if (runtime_nsecs)
203 fprintf(stderr, " # %12.3f M/sec",
204 (double)count[0]/runtime_nsecs*1000.0);
c04f5e5d
IM
205 }
206 if (scaled)
207 fprintf(stderr, " (scaled from %.2f%%)",
208 (double) count[2] / count[1] * 100);
209 fprintf(stderr, "\n");
210}
211
16f762a2 212static int do_perfstat(int argc, const char **argv)
ddcacfa0
IM
213{
214 unsigned long long t0, t1;
215 int counter;
ddcacfa0
IM
216 int status;
217 int pid;
218
219 if (!system_wide)
220 nr_cpus = 1;
221
222 for (counter = 0; counter < nr_counters; counter++)
223 create_perfstat_counter(counter);
224
ddcacfa0
IM
225 /*
226 * Enable counters and exec the command:
227 */
228 t0 = rdclock();
229 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
230
231 if ((pid = fork()) < 0)
232 perror("failed to fork");
233 if (!pid) {
5242519b 234 if (execvp(argv[0], (char **)argv)) {
ddcacfa0
IM
235 perror(argv[0]);
236 exit(-1);
237 }
238 }
239 while (wait(&status) >= 0)
240 ;
241 prctl(PR_TASK_PERF_COUNTERS_DISABLE);
242 t1 = rdclock();
243
244 fflush(stdout);
245
246 fprintf(stderr, "\n");
247 fprintf(stderr, " Performance counter stats for \'%s\':\n",
248 argv[0]);
249 fprintf(stderr, "\n");
250
2996f5dd
IM
251 for (counter = 0; counter < nr_counters; counter++)
252 read_counter(counter);
253
c04f5e5d
IM
254 for (counter = 0; counter < nr_counters; counter++)
255 print_counter(counter);
ddcacfa0 256
ddcacfa0 257
ddcacfa0
IM
258 fprintf(stderr, "\n");
259 fprintf(stderr, " Wall-clock time elapsed: %12.6f msecs\n",
260 (double)(t1-t0)/1e6);
261 fprintf(stderr, "\n");
262
263 return 0;
264}
265
5242519b 266static void skip_signal(int signo)
ddcacfa0 267{
5242519b
IM
268}
269
270static const char * const stat_usage[] = {
271 "perf stat [<options>] <command>",
272 NULL
273};
274
275static char events_help_msg[EVENTS_HELP_MAX];
276
277static const struct option options[] = {
278 OPT_CALLBACK('e', "event", NULL, "event",
279 events_help_msg, parse_events),
280 OPT_INTEGER('c', "count", &default_interval,
281 "event period to sample"),
282 OPT_BOOLEAN('i', "inherit", &inherit,
283 "child tasks inherit counters"),
284 OPT_INTEGER('p', "pid", &target_pid,
285 "stat events on existing pid"),
286 OPT_BOOLEAN('a', "all-cpus", &system_wide,
287 "system-wide collection from all CPUs"),
288 OPT_BOOLEAN('l', "scale", &scale,
289 "scale/normalize counters"),
290 OPT_END()
291};
292
293int cmd_stat(int argc, const char **argv, const char *prefix)
294{
295 int counter;
296
297 page_size = sysconf(_SC_PAGE_SIZE);
298
299 create_events_help(events_help_msg);
300 memcpy(event_id, default_event_id, sizeof(default_event_id));
301
302 argc = parse_options(argc, argv, options, stat_usage, 0);
303 if (!argc)
304 usage_with_options(stat_usage, options);
ddcacfa0
IM
305
306 if (!nr_counters) {
307 nr_counters = 8;
308 }
309
310 for (counter = 0; counter < nr_counters; counter++) {
311 if (event_count[counter])
312 continue;
313
314 event_count[counter] = default_interval;
315 }
ddcacfa0
IM
316 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
317 assert(nr_cpus <= MAX_NR_CPUS);
318 assert(nr_cpus >= 0);
319
58d7e993
IM
320 /*
321 * We dont want to block the signals - that would cause
322 * child tasks to inherit that and Ctrl-C would not work.
323 * What we want is for Ctrl-C to work in the exec()-ed
324 * task, but being ignored by perf stat itself:
325 */
326 signal(SIGINT, skip_signal);
327 signal(SIGALRM, skip_signal);
328 signal(SIGABRT, skip_signal);
329
ddcacfa0
IM
330 return do_perfstat(argc, argv);
331}