diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-05-26 03:17:18 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-26 05:59:34 -0400 |
commit | 5242519b0296d128425368fc6ab17f541d5fa775 (patch) | |
tree | 2fb13c01ff80c4ff0818bdcb2d9d9edfbe244036 | |
parent | 8ad8db3788fd9a449941fb2392ca85af4ee1cde1 (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>
-rw-r--r-- | Documentation/perf_counter/builtin-record.c | 3 | ||||
-rw-r--r-- | Documentation/perf_counter/builtin-stat.c | 414 | ||||
-rw-r--r-- | Documentation/perf_counter/util/parse-events.c | 82 | ||||
-rw-r--r-- | Documentation/perf_counter/util/parse-events.h | 10 |
4 files changed, 145 insertions, 364 deletions
diff --git a/Documentation/perf_counter/builtin-record.c b/Documentation/perf_counter/builtin-record.c index 6fa6ed664950..ec2b787b23bd 100644 --- a/Documentation/perf_counter/builtin-record.c +++ b/Documentation/perf_counter/builtin-record.c | |||
@@ -4,7 +4,6 @@ | |||
4 | #include "util/util.h" | 4 | #include "util/util.h" |
5 | #include "util/parse-options.h" | 5 | #include "util/parse-options.h" |
6 | #include "util/parse-events.h" | 6 | #include "util/parse-events.h" |
7 | #include "util/exec_cmd.h" | ||
8 | 7 | ||
9 | #include <sched.h> | 8 | #include <sched.h> |
10 | 9 | ||
@@ -400,7 +399,7 @@ static const char * const record_usage[] = { | |||
400 | 399 | ||
401 | static char events_help_msg[EVENTS_HELP_MAX]; | 400 | static char events_help_msg[EVENTS_HELP_MAX]; |
402 | 401 | ||
403 | const struct option options[] = { | 402 | static const struct option options[] = { |
404 | OPT_CALLBACK('e', "event", NULL, "event", | 403 | OPT_CALLBACK('e', "event", NULL, "event", |
405 | events_help_msg, parse_events), | 404 | events_help_msg, parse_events), |
406 | OPT_INTEGER('c', "count", &default_interval, | 405 | OPT_INTEGER('c', "count", &default_interval, |
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 | ||
90 | static int system_wide = 0; | 39 | static int system_wide = 0; |
40 | static int inherit = 1; | ||
91 | 41 | ||
92 | static int nr_counters = 0; | 42 | static __u64 default_event_id[MAX_COUNTERS] = { |
93 | static __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 | |||
104 | static int default_interval = 100000; | 54 | static int default_interval = 100000; |
105 | static int event_count[MAX_COUNTERS]; | 55 | static int event_count[MAX_COUNTERS]; |
106 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; | 56 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; |
107 | static int event_mask[MAX_COUNTERS]; | ||
108 | 57 | ||
109 | static int tid = -1; | 58 | static int target_pid = -1; |
110 | static int profile_cpu = -1; | ||
111 | static int nr_cpus = 0; | 59 | static int nr_cpus = 0; |
112 | static int nmi = 1; | ||
113 | static int group = 0; | ||
114 | static unsigned int page_size; | 60 | static unsigned int page_size; |
115 | 61 | ||
116 | static int zero; | ||
117 | |||
118 | static int scale = 1; | 62 | static int scale = 1; |
119 | 63 | ||
120 | static const unsigned int default_count[] = { | 64 | static const unsigned int default_count[] = { |
@@ -126,197 +70,6 @@ static const unsigned int default_count[] = { | |||
126 | 10000, | 70 | 10000, |
127 | }; | 71 | }; |
128 | 72 | ||
129 | static 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 | |||
139 | static 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 | |||
149 | struct event_symbol { | ||
150 | __u64 event; | ||
151 | char *symbol; | ||
152 | }; | ||
153 | |||
154 | static 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 | |||
185 | static 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 | |||
208 | static 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 | |||
223 | static 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 | */ | ||
257 | static __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 | |||
289 | static int parse_events(char *str) | ||
290 | { | ||
291 | __u64 config; | ||
292 | |||
293 | again: | ||
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 | |||
318 | char fault_here[1000000]; | ||
319 | |||
320 | static void create_perfstat_counter(int counter) | 73 | static 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 | ||
358 | int do_perfstat(int argc, char *argv[]) | 111 | int 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 | ||
461 | static void process_options(int argc, char **argv) | 208 | static void skip_signal(int signo) |
462 | { | 209 | { |
463 | int error = 0, counter; | 210 | } |
464 | 211 | ||
465 | for (;;) { | 212 | static 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'}, | 217 | static char events_help_msg[EVENTS_HELP_MAX]; |
471 | {"delay", required_argument, NULL, 'd'}, | 218 | |
472 | {"dump_symtab", no_argument, NULL, 'D'}, | 219 | static 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", | 235 | int 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 | |||
538 | static void skip_signal(int signo) | ||
539 | { | ||
540 | } | ||
541 | |||
542 | int 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); |
diff --git a/Documentation/perf_counter/util/parse-events.c b/Documentation/perf_counter/util/parse-events.c index 77d0917d55d3..88c903eb260a 100644 --- a/Documentation/perf_counter/util/parse-events.c +++ b/Documentation/perf_counter/util/parse-events.c | |||
@@ -8,6 +8,7 @@ | |||
8 | int nr_counters; | 8 | int nr_counters; |
9 | 9 | ||
10 | __u64 event_id[MAX_COUNTERS] = { }; | 10 | __u64 event_id[MAX_COUNTERS] = { }; |
11 | int event_mask[MAX_COUNTERS]; | ||
11 | 12 | ||
12 | struct event_symbol { | 13 | struct event_symbol { |
13 | __u64 event; | 14 | __u64 event; |
@@ -37,6 +38,64 @@ static struct event_symbol event_symbols[] = { | |||
37 | {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", }, | 38 | {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", }, |
38 | }; | 39 | }; |
39 | 40 | ||
41 | #define __PERF_COUNTER_FIELD(config, name) \ | ||
42 | ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT) | ||
43 | |||
44 | #define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW) | ||
45 | #define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG) | ||
46 | #define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) | ||
47 | #define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) | ||
48 | |||
49 | static char *hw_event_names[] = { | ||
50 | "CPU cycles", | ||
51 | "instructions", | ||
52 | "cache references", | ||
53 | "cache misses", | ||
54 | "branches", | ||
55 | "branch misses", | ||
56 | "bus cycles", | ||
57 | }; | ||
58 | |||
59 | static char *sw_event_names[] = { | ||
60 | "cpu clock ticks", | ||
61 | "task clock ticks", | ||
62 | "pagefaults", | ||
63 | "context switches", | ||
64 | "CPU migrations", | ||
65 | "minor faults", | ||
66 | "major faults", | ||
67 | }; | ||
68 | |||
69 | char *event_name(int ctr) | ||
70 | { | ||
71 | __u64 config = event_id[ctr]; | ||
72 | int type = PERF_COUNTER_TYPE(config); | ||
73 | int id = PERF_COUNTER_ID(config); | ||
74 | static char buf[32]; | ||
75 | |||
76 | if (PERF_COUNTER_RAW(config)) { | ||
77 | sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config)); | ||
78 | return buf; | ||
79 | } | ||
80 | |||
81 | switch (type) { | ||
82 | case PERF_TYPE_HARDWARE: | ||
83 | if (id < PERF_HW_EVENTS_MAX) | ||
84 | return hw_event_names[id]; | ||
85 | return "unknown-hardware"; | ||
86 | |||
87 | case PERF_TYPE_SOFTWARE: | ||
88 | if (id < PERF_SW_EVENTS_MAX) | ||
89 | return sw_event_names[id]; | ||
90 | return "unknown-software"; | ||
91 | |||
92 | default: | ||
93 | break; | ||
94 | } | ||
95 | |||
96 | return "unknown"; | ||
97 | } | ||
98 | |||
40 | /* | 99 | /* |
41 | * Each event can have multiple symbolic names. | 100 | * Each event can have multiple symbolic names. |
42 | * Symbolic names are (almost) exactly matched. | 101 | * Symbolic names are (almost) exactly matched. |
@@ -46,12 +105,23 @@ static __u64 match_event_symbols(const char *str) | |||
46 | __u64 config, id; | 105 | __u64 config, id; |
47 | int type; | 106 | int type; |
48 | unsigned int i; | 107 | unsigned int i; |
108 | char mask_str[4]; | ||
49 | 109 | ||
50 | if (sscanf(str, "r%llx", &config) == 1) | 110 | if (sscanf(str, "r%llx", &config) == 1) |
51 | return config | PERF_COUNTER_RAW_MASK; | 111 | return config | PERF_COUNTER_RAW_MASK; |
52 | 112 | ||
53 | if (sscanf(str, "%d:%llu", &type, &id) == 2) | 113 | switch (sscanf(str, "%d:%llu:%2s", &type, &id, mask_str)) { |
54 | return EID(type, id); | 114 | case 3: |
115 | if (strchr(mask_str, 'k')) | ||
116 | event_mask[nr_counters] |= EVENT_MASK_USER; | ||
117 | if (strchr(mask_str, 'u')) | ||
118 | event_mask[nr_counters] |= EVENT_MASK_KERNEL; | ||
119 | case 2: | ||
120 | return EID(type, id); | ||
121 | |||
122 | default: | ||
123 | break; | ||
124 | } | ||
55 | 125 | ||
56 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { | 126 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { |
57 | if (!strncmp(str, event_symbols[i].symbol, | 127 | if (!strncmp(str, event_symbols[i].symbol, |
@@ -86,14 +156,6 @@ again: | |||
86 | return 0; | 156 | return 0; |
87 | } | 157 | } |
88 | 158 | ||
89 | #define __PERF_COUNTER_FIELD(config, name) \ | ||
90 | ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT) | ||
91 | |||
92 | #define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW) | ||
93 | #define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG) | ||
94 | #define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) | ||
95 | #define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) | ||
96 | |||
97 | /* | 159 | /* |
98 | * Create the help text for the event symbols: | 160 | * Create the help text for the event symbols: |
99 | */ | 161 | */ |
diff --git a/Documentation/perf_counter/util/parse-events.h b/Documentation/perf_counter/util/parse-events.h index 6e2ebe5ff7d7..0da306bb9028 100644 --- a/Documentation/perf_counter/util/parse-events.h +++ b/Documentation/perf_counter/util/parse-events.h | |||
@@ -1,6 +1,16 @@ | |||
1 | 1 | ||
2 | /* | ||
3 | * Parse symbolic events/counts passed in as options: | ||
4 | */ | ||
5 | |||
2 | extern int nr_counters; | 6 | extern int nr_counters; |
3 | extern __u64 event_id[MAX_COUNTERS]; | 7 | extern __u64 event_id[MAX_COUNTERS]; |
8 | extern int event_mask[MAX_COUNTERS]; | ||
9 | |||
10 | #define EVENT_MASK_KERNEL 1 | ||
11 | #define EVENT_MASK_USER 2 | ||
12 | |||
13 | extern char *event_name(int ctr); | ||
4 | 14 | ||
5 | extern int parse_events(const struct option *opt, const char *str, int unset); | 15 | extern int parse_events(const struct option *opt, const char *str, int unset); |
6 | 16 | ||