diff options
Diffstat (limited to 'Documentation/perf_counter')
-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 | ||