aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/perf_counter/builtin-stat.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-05-26 03:17:18 -0400
committerIngo Molnar <mingo@elte.hu>2009-05-26 05:59:34 -0400
commit5242519b0296d128425368fc6ab17f541d5fa775 (patch)
tree2fb13c01ff80c4ff0818bdcb2d9d9edfbe244036 /Documentation/perf_counter/builtin-stat.c
parent8ad8db3788fd9a449941fb2392ca85af4ee1cde1 (diff)
perf stat: Convert to Git option parsing
Remove getopt usage and use Git's much more advanced and more compact command option library. Extend the event parser library with the extensions that were in perf-stat before. Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: John Kacur <jkacur@redhat.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
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);