aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/perf_counter/builtin-stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/perf_counter/builtin-stat.c')
-rw-r--r--Documentation/perf_counter/builtin-stat.c414
1 files changed, 62 insertions, 352 deletions
diff --git a/Documentation/perf_counter/builtin-stat.c b/Documentation/perf_counter/builtin-stat.c
index c1053d820c1f..e7cb9412212b 100644
--- a/Documentation/perf_counter/builtin-stat.c
+++ b/Documentation/perf_counter/builtin-stat.c
@@ -1,35 +1,5 @@
1/* 1/*
2 * kerneltop.c: show top kernel functions - performance counters showcase 2 * perf stat: /usr/bin/time -alike performance counter statistics utility
3
4 Build with:
5
6 cc -O6 -Wall -c -o kerneltop.o kerneltop.c -lrt
7
8 Sample output:
9
10------------------------------------------------------------------------------
11 KernelTop: 2669 irqs/sec [NMI, cache-misses/cache-refs], (all, cpu: 2)
12------------------------------------------------------------------------------
13
14 weight RIP kernel function
15 ______ ________________ _______________
16
17 35.20 - ffffffff804ce74b : skb_copy_and_csum_dev
18 33.00 - ffffffff804cb740 : sock_alloc_send_skb
19 31.26 - ffffffff804ce808 : skb_push
20 22.43 - ffffffff80510004 : tcp_established_options
21 19.00 - ffffffff8027d250 : find_get_page
22 15.76 - ffffffff804e4fc9 : eth_type_trans
23 15.20 - ffffffff804d8baa : dst_release
24 14.86 - ffffffff804cf5d8 : skb_release_head_state
25 14.00 - ffffffff802217d5 : read_hpet
26 12.00 - ffffffff804ffb7f : __ip_local_out
27 11.97 - ffffffff804fc0c8 : ip_local_deliver_finish
28 8.54 - ffffffff805001a3 : ip_queue_xmit
29 */
30
31/*
32 * perfstat: /usr/bin/time -alike performance counter statistics utility
33 3
34 It summarizes the counter events of all tasks (and child tasks), 4 It summarizes the counter events of all tasks (and child tasks),
35 covering all CPUs that the command (or workload) executes on. 5 covering all CPUs that the command (or workload) executes on.
@@ -38,59 +8,38 @@
38 8
39 Sample output: 9 Sample output:
40 10
41 $ ./perfstat -e 1 -e 3 -e 5 ls -lR /usr/include/ >/dev/null 11 $ perf stat -e 1 -e 3 -e 5 ls -lR /usr/include/ >/dev/null
42 12
43 Performance counter stats for 'ls': 13 Performance counter stats for 'ls':
44 14
45 163516953 instructions 15 163516953 instructions
46 2295 cache-misses 16 2295 cache-misses
47 2855182 branch-misses 17 2855182 branch-misses
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)
48 */ 30 */
49 31
50 /*
51 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
52 *
53 * Improvements and fixes by:
54 *
55 * Arjan van de Ven <arjan@linux.intel.com>
56 * Yanmin Zhang <yanmin.zhang@intel.com>
57 * Wu Fengguang <fengguang.wu@intel.com>
58 * Mike Galbraith <efault@gmx.de>
59 * Paul Mackerras <paulus@samba.org>
60 *
61 * Released under the GPL v2. (and only v2, not any later version)
62 */
63
64#include "perf.h" 32#include "perf.h"
65#include "util/util.h" 33#include "util/util.h"
34#include "util/parse-options.h"
35#include "util/parse-events.h"
66 36
67#include <getopt.h>
68#include <assert.h>
69#include <fcntl.h>
70#include <stdio.h>
71#include <errno.h>
72#include <time.h>
73#include <sched.h>
74#include <pthread.h>
75
76#include <sys/syscall.h>
77#include <sys/ioctl.h>
78#include <sys/poll.h>
79#include <sys/prctl.h> 37#include <sys/prctl.h>
80#include <sys/wait.h>
81#include <sys/uio.h>
82#include <sys/mman.h>
83
84#include <linux/unistd.h>
85#include <linux/types.h>
86
87#define EVENT_MASK_KERNEL 1
88#define EVENT_MASK_USER 2
89 38
90static int system_wide = 0; 39static int system_wide = 0;
40static int inherit = 1;
91 41
92static int nr_counters = 0; 42static __u64 default_event_id[MAX_COUNTERS] = {
93static __u64 event_id[MAX_COUNTERS] = {
94 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), 43 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
95 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), 44 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),
96 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), 45 EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
@@ -101,20 +50,15 @@ static __u64 event_id[MAX_COUNTERS] = {
101 EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), 50 EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES),
102 EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), 51 EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES),
103}; 52};
53
104static int default_interval = 100000; 54static int default_interval = 100000;
105static int event_count[MAX_COUNTERS]; 55static int event_count[MAX_COUNTERS];
106static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 56static int fd[MAX_NR_CPUS][MAX_COUNTERS];
107static int event_mask[MAX_COUNTERS];
108 57
109static int tid = -1; 58static int target_pid = -1;
110static int profile_cpu = -1;
111static int nr_cpus = 0; 59static int nr_cpus = 0;
112static int nmi = 1;
113static int group = 0;
114static unsigned int page_size; 60static unsigned int page_size;
115 61
116static int zero;
117
118static int scale = 1; 62static int scale = 1;
119 63
120static const unsigned int default_count[] = { 64static const unsigned int default_count[] = {
@@ -126,197 +70,6 @@ static const unsigned int default_count[] = {
126 10000, 70 10000,
127}; 71};
128 72
129static char *hw_event_names[] = {
130 "CPU cycles",
131 "instructions",
132 "cache references",
133 "cache misses",
134 "branches",
135 "branch misses",
136 "bus cycles",
137};
138
139static char *sw_event_names[] = {
140 "cpu clock ticks",
141 "task clock ticks",
142 "pagefaults",
143 "context switches",
144 "CPU migrations",
145 "minor faults",
146 "major faults",
147};
148
149struct event_symbol {
150 __u64 event;
151 char *symbol;
152};
153
154static struct event_symbol event_symbols[] = {
155 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
156 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
157 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
158 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
159 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
160 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
161 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
162 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
163 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
164
165 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
166 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
167 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
168 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
169 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
170 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
171 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
172 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
173 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
174 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
175};
176
177#define __PERF_COUNTER_FIELD(config, name) \
178 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
179
180#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
181#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
182#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
183#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
184
185static void display_events_help(void)
186{
187 unsigned int i;
188 __u64 e;
189
190 printf(
191 " -e EVENT --event=EVENT # symbolic-name abbreviations");
192
193 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
194 int type, id;
195
196 e = event_symbols[i].event;
197 type = PERF_COUNTER_TYPE(e);
198 id = PERF_COUNTER_ID(e);
199
200 printf("\n %d:%d: %-20s",
201 type, id, event_symbols[i].symbol);
202 }
203
204 printf("\n"
205 " rNNN: raw PMU events (eventsel+umask)\n\n");
206}
207
208static void display_help(void)
209{
210 printf(
211 "Usage: perfstat [<events...>] <cmd...>\n\n"
212 "PerfStat Options (up to %d event types can be specified):\n\n",
213 MAX_COUNTERS);
214
215 display_events_help();
216
217 printf(
218 " -l # scale counter values\n"
219 " -a # system-wide collection\n");
220 exit(0);
221}
222
223static char *event_name(int ctr)
224{
225 __u64 config = event_id[ctr];
226 int type = PERF_COUNTER_TYPE(config);
227 int id = PERF_COUNTER_ID(config);
228 static char buf[32];
229
230 if (PERF_COUNTER_RAW(config)) {
231 sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config));
232 return buf;
233 }
234
235 switch (type) {
236 case PERF_TYPE_HARDWARE:
237 if (id < PERF_HW_EVENTS_MAX)
238 return hw_event_names[id];
239 return "unknown-hardware";
240
241 case PERF_TYPE_SOFTWARE:
242 if (id < PERF_SW_EVENTS_MAX)
243 return sw_event_names[id];
244 return "unknown-software";
245
246 default:
247 break;
248 }
249
250 return "unknown";
251}
252
253/*
254 * Each event can have multiple symbolic names.
255 * Symbolic names are (almost) exactly matched.
256 */
257static __u64 match_event_symbols(char *str)
258{
259 __u64 config, id;
260 int type;
261 unsigned int i;
262 char mask_str[4];
263
264 if (sscanf(str, "r%llx", &config) == 1)
265 return config | PERF_COUNTER_RAW_MASK;
266
267 switch (sscanf(str, "%d:%llu:%2s", &type, &id, mask_str)) {
268 case 3:
269 if (strchr(mask_str, 'k'))
270 event_mask[nr_counters] |= EVENT_MASK_USER;
271 if (strchr(mask_str, 'u'))
272 event_mask[nr_counters] |= EVENT_MASK_KERNEL;
273 case 2:
274 return EID(type, id);
275
276 default:
277 break;
278 }
279
280 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
281 if (!strncmp(str, event_symbols[i].symbol,
282 strlen(event_symbols[i].symbol)))
283 return event_symbols[i].event;
284 }
285
286 return ~0ULL;
287}
288
289static int parse_events(char *str)
290{
291 __u64 config;
292
293again:
294 if (nr_counters == MAX_COUNTERS)
295 return -1;
296
297 config = match_event_symbols(str);
298 if (config == ~0ULL)
299 return -1;
300
301 event_id[nr_counters] = config;
302 nr_counters++;
303
304 str = strstr(str, ",");
305 if (str) {
306 str++;
307 goto again;
308 }
309
310 return 0;
311}
312
313
314/*
315 * perfstat
316 */
317
318char fault_here[1000000];
319
320static void create_perfstat_counter(int counter) 73static void create_perfstat_counter(int counter)
321{ 74{
322 struct perf_counter_hw_event hw_event; 75 struct perf_counter_hw_event hw_event;
@@ -324,7 +77,7 @@ static void create_perfstat_counter(int counter)
324 memset(&hw_event, 0, sizeof(hw_event)); 77 memset(&hw_event, 0, sizeof(hw_event));
325 hw_event.config = event_id[counter]; 78 hw_event.config = event_id[counter];
326 hw_event.record_type = 0; 79 hw_event.record_type = 0;
327 hw_event.nmi = 0; 80 hw_event.nmi = 1;
328 hw_event.exclude_kernel = event_mask[counter] & EVENT_MASK_KERNEL; 81 hw_event.exclude_kernel = event_mask[counter] & EVENT_MASK_KERNEL;
329 hw_event.exclude_user = event_mask[counter] & EVENT_MASK_USER; 82 hw_event.exclude_user = event_mask[counter] & EVENT_MASK_USER;
330 83
@@ -343,7 +96,7 @@ static void create_perfstat_counter(int counter)
343 } 96 }
344 } 97 }
345 } else { 98 } else {
346 hw_event.inherit = 1; 99 hw_event.inherit = inherit;
347 hw_event.disabled = 1; 100 hw_event.disabled = 1;
348 101
349 fd[0][counter] = sys_perf_counter_open(&hw_event, 0, -1, -1, 0); 102 fd[0][counter] = sys_perf_counter_open(&hw_event, 0, -1, -1, 0);
@@ -355,7 +108,7 @@ static void create_perfstat_counter(int counter)
355 } 108 }
356} 109}
357 110
358int do_perfstat(int argc, char *argv[]) 111int do_perfstat(int argc, const char **argv)
359{ 112{
360 unsigned long long t0, t1; 113 unsigned long long t0, t1;
361 int counter; 114 int counter;
@@ -369,12 +122,6 @@ int do_perfstat(int argc, char *argv[])
369 for (counter = 0; counter < nr_counters; counter++) 122 for (counter = 0; counter < nr_counters; counter++)
370 create_perfstat_counter(counter); 123 create_perfstat_counter(counter);
371 124
372 argc -= optind;
373 argv += optind;
374
375 if (!argc)
376 display_help();
377
378 /* 125 /*
379 * Enable counters and exec the command: 126 * Enable counters and exec the command:
380 */ 127 */
@@ -384,7 +131,7 @@ int do_perfstat(int argc, char *argv[])
384 if ((pid = fork()) < 0) 131 if ((pid = fork()) < 0)
385 perror("failed to fork"); 132 perror("failed to fork");
386 if (!pid) { 133 if (!pid) {
387 if (execvp(argv[0], argv)) { 134 if (execvp(argv[0], (char **)argv)) {
388 perror(argv[0]); 135 perror(argv[0]);
389 exit(-1); 136 exit(-1);
390 } 137 }
@@ -458,70 +205,45 @@ int do_perfstat(int argc, char *argv[])
458 return 0; 205 return 0;
459} 206}
460 207
461static void process_options(int argc, char **argv) 208static void skip_signal(int signo)
462{ 209{
463 int error = 0, counter; 210}
464 211
465 for (;;) { 212static const char * const stat_usage[] = {
466 int option_index = 0; 213 "perf stat [<options>] <command>",
467 /** Options for getopt */ 214 NULL
468 static struct option long_options[] = { 215};
469 {"count", required_argument, NULL, 'c'}, 216
470 {"cpu", required_argument, NULL, 'C'}, 217static char events_help_msg[EVENTS_HELP_MAX];
471 {"delay", required_argument, NULL, 'd'}, 218
472 {"dump_symtab", no_argument, NULL, 'D'}, 219static const struct option options[] = {
473 {"event", required_argument, NULL, 'e'}, 220 OPT_CALLBACK('e', "event", NULL, "event",
474 {"filter", required_argument, NULL, 'f'}, 221 events_help_msg, parse_events),
475 {"group", required_argument, NULL, 'g'}, 222 OPT_INTEGER('c', "count", &default_interval,
476 {"help", no_argument, NULL, 'h'}, 223 "event period to sample"),
477 {"nmi", required_argument, NULL, 'n'}, 224 OPT_BOOLEAN('i', "inherit", &inherit,
478 {"munmap_info", no_argument, NULL, 'U'}, 225 "child tasks inherit counters"),
479 {"pid", required_argument, NULL, 'p'}, 226 OPT_INTEGER('p', "pid", &target_pid,
480 {"realtime", required_argument, NULL, 'r'}, 227 "stat events on existing pid"),
481 {"scale", no_argument, NULL, 'l'}, 228 OPT_BOOLEAN('a', "all-cpus", &system_wide,
482 {"symbol", required_argument, NULL, 's'}, 229 "system-wide collection from all CPUs"),
483 {"stat", no_argument, NULL, 'S'}, 230 OPT_BOOLEAN('l', "scale", &scale,
484 {"vmlinux", required_argument, NULL, 'x'}, 231 "scale/normalize counters"),
485 {"zero", no_argument, NULL, 'z'}, 232 OPT_END()
486 {NULL, 0, NULL, 0 } 233};
487 }; 234
488 int c = getopt_long(argc, argv, "+:ac:C:d:De:f:g:hln:m:p:r:s:Sx:zMU", 235int cmd_stat(int argc, const char **argv, const char *prefix)
489 long_options, &option_index); 236{
490 if (c == -1) 237 int counter;
491 break; 238
492 239 page_size = sysconf(_SC_PAGE_SIZE);
493 switch (c) { 240
494 case 'a': system_wide = 1; break; 241 create_events_help(events_help_msg);
495 case 'c': default_interval = atoi(optarg); break; 242 memcpy(event_id, default_event_id, sizeof(default_event_id));
496 case 'C': 243
497 /* CPU and PID are mutually exclusive */ 244 argc = parse_options(argc, argv, options, stat_usage, 0);
498 if (tid != -1) { 245 if (!argc)
499 printf("WARNING: CPU switch overriding PID\n"); 246 usage_with_options(stat_usage, options);
500 sleep(1);
501 tid = -1;
502 }
503 profile_cpu = atoi(optarg); break;
504
505 case 'e': error = parse_events(optarg); break;
506
507 case 'g': group = atoi(optarg); break;
508 case 'h': display_help(); break;
509 case 'l': scale = 1; break;
510 case 'n': nmi = atoi(optarg); break;
511 case 'p':
512 /* CPU and PID are mutually exclusive */
513 if (profile_cpu != -1) {
514 printf("WARNING: PID switch overriding CPU\n");
515 sleep(1);
516 profile_cpu = -1;
517 }
518 tid = atoi(optarg); break;
519 case 'z': zero = 1; break;
520 default: error = 1; break;
521 }
522 }
523 if (error)
524 display_help();
525 247
526 if (!nr_counters) { 248 if (!nr_counters) {
527 nr_counters = 8; 249 nr_counters = 8;
@@ -533,18 +255,6 @@ static void process_options(int argc, char **argv)
533 255
534 event_count[counter] = default_interval; 256 event_count[counter] = default_interval;
535 } 257 }
536}
537
538static void skip_signal(int signo)
539{
540}
541
542int cmd_stat(int argc, char **argv, const char *prefix)
543{
544 page_size = sysconf(_SC_PAGE_SIZE);
545
546 process_options(argc, argv);
547
548 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 258 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
549 assert(nr_cpus <= MAX_NR_CPUS); 259 assert(nr_cpus <= MAX_NR_CPUS);
550 assert(nr_cpus >= 0); 260 assert(nr_cpus >= 0);