aboutsummaryrefslogtreecommitdiffstats
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:26:32 -0400
commit0e9b20b8a1cab6c6ab4f98f917a2d98783103969 (patch)
treefb294181846f82f1cd3dc96bcbd8a8506c3f8b27
parent4e97ddf09ee3ce715fc334399bae4cc0c0a13057 (diff)
perf record: Convert to Git option parsing
Remove getopt usage and use Git's much more advanced and more compact command option library. Git's library (util/parse-options.[ch]) constructs help texts and error messages automatically, and has a number of other convenience features as well. 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.c372
-rw-r--r--Documentation/perf_counter/builtin-top.c3
2 files changed, 177 insertions, 198 deletions
diff --git a/Documentation/perf_counter/builtin-record.c b/Documentation/perf_counter/builtin-record.c
index f225efaff9f5..f12a7822fcf1 100644
--- a/Documentation/perf_counter/builtin-record.c
+++ b/Documentation/perf_counter/builtin-record.c
@@ -2,6 +2,8 @@
2 2
3#include "perf.h" 3#include "perf.h"
4#include "util/util.h" 4#include "util/util.h"
5#include "util/parse-options.h"
6#include "util/exec_cmd.h"
5 7
6#include <sys/types.h> 8#include <sys/types.h>
7#include <sys/stat.h> 9#include <sys/stat.h>
@@ -11,7 +13,6 @@
11#include <stdlib.h> 13#include <stdlib.h>
12#include <string.h> 14#include <string.h>
13#include <limits.h> 15#include <limits.h>
14#include <getopt.h>
15#include <assert.h> 16#include <assert.h>
16#include <fcntl.h> 17#include <fcntl.h>
17#include <stdio.h> 18#include <stdio.h>
@@ -33,8 +34,8 @@
33 34
34 35
35 36
36#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) 37#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
37#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 38#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
38 39
39static int nr_counters = 0; 40static int nr_counters = 0;
40static __u64 event_id[MAX_COUNTERS] = { }; 41static __u64 event_id[MAX_COUNTERS] = { };
@@ -45,7 +46,7 @@ static int nr_cpus = 0;
45static unsigned int page_size; 46static unsigned int page_size;
46static unsigned int mmap_pages = 16; 47static unsigned int mmap_pages = 16;
47static int output; 48static int output;
48static char *output_name = "output.perf"; 49static const char *output_name = "output.perf";
49static int group = 0; 50static int group = 0;
50static unsigned int realtime_prio = 0; 51static unsigned int realtime_prio = 0;
51static int system_wide = 0; 52static int system_wide = 0;
@@ -62,192 +63,6 @@ const unsigned int default_count[] = {
62 10000, 63 10000,
63}; 64};
64 65
65struct event_symbol {
66 __u64 event;
67 char *symbol;
68};
69
70static struct event_symbol event_symbols[] = {
71 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
72 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
73 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
74 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
75 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
76 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
77 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
78 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
79 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
80
81 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
82 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
83 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
84 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
85 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
86 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
87 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
88 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
89 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
90 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
91};
92
93/*
94 * Each event can have multiple symbolic names.
95 * Symbolic names are (almost) exactly matched.
96 */
97static __u64 match_event_symbols(char *str)
98{
99 __u64 config, id;
100 int type;
101 unsigned int i;
102
103 if (sscanf(str, "r%llx", &config) == 1)
104 return config | PERF_COUNTER_RAW_MASK;
105
106 if (sscanf(str, "%d:%llu", &type, &id) == 2)
107 return EID(type, id);
108
109 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
110 if (!strncmp(str, event_symbols[i].symbol,
111 strlen(event_symbols[i].symbol)))
112 return event_symbols[i].event;
113 }
114
115 return ~0ULL;
116}
117
118static int parse_events(char *str)
119{
120 __u64 config;
121
122again:
123 if (nr_counters == MAX_COUNTERS)
124 return -1;
125
126 config = match_event_symbols(str);
127 if (config == ~0ULL)
128 return -1;
129
130 event_id[nr_counters] = config;
131 nr_counters++;
132
133 str = strstr(str, ",");
134 if (str) {
135 str++;
136 goto again;
137 }
138
139 return 0;
140}
141
142#define __PERF_COUNTER_FIELD(config, name) \
143 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
144
145#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
146#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
147#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
148#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
149
150static void display_events_help(void)
151{
152 unsigned int i;
153 __u64 e;
154
155 printf(
156 " -e EVENT --event=EVENT # symbolic-name abbreviations");
157
158 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
159 int type, id;
160
161 e = event_symbols[i].event;
162 type = PERF_COUNTER_TYPE(e);
163 id = PERF_COUNTER_ID(e);
164
165 printf("\n %d:%d: %-20s",
166 type, id, event_symbols[i].symbol);
167 }
168
169 printf("\n"
170 " rNNN: raw PMU events (eventsel+umask)\n\n");
171}
172
173static void display_help(void)
174{
175 printf(
176 "Usage: perf-record [<options>] <cmd>\n"
177 "perf-record Options (up to %d event types can be specified at once):\n\n",
178 MAX_COUNTERS);
179
180 display_events_help();
181
182 printf(
183 " -c CNT --count=CNT # event period to sample\n"
184 " -m pages --mmap_pages=<pages> # number of mmap data pages\n"
185 " -o file --output=<file> # output file\n"
186 " -p pid --pid=<pid> # record events on existing pid\n"
187 " -r prio --realtime=<prio> # use RT prio\n"
188 " -s --system # system wide profiling\n"
189 );
190
191 exit(0);
192}
193
194static void process_options(int argc, char * const argv[])
195{
196 int error = 0, counter;
197
198 for (;;) {
199 int option_index = 0;
200 /** Options for getopt */
201 static struct option long_options[] = {
202 {"count", required_argument, NULL, 'c'},
203 {"event", required_argument, NULL, 'e'},
204 {"mmap_pages", required_argument, NULL, 'm'},
205 {"output", required_argument, NULL, 'o'},
206 {"pid", required_argument, NULL, 'p'},
207 {"realtime", required_argument, NULL, 'r'},
208 {"system", no_argument, NULL, 's'},
209 {"inherit", no_argument, NULL, 'i'},
210 {"nmi", no_argument, NULL, 'n'},
211 {NULL, 0, NULL, 0 }
212 };
213 int c = getopt_long(argc, argv, "+:c:e:m:o:p:r:sin",
214 long_options, &option_index);
215 if (c == -1)
216 break;
217
218 switch (c) {
219 case 'c': default_interval = atoi(optarg); break;
220 case 'e': error = parse_events(optarg); break;
221 case 'm': mmap_pages = atoi(optarg); break;
222 case 'o': output_name = strdup(optarg); break;
223 case 'p': target_pid = atoi(optarg); break;
224 case 'r': realtime_prio = atoi(optarg); break;
225 case 's': system_wide ^= 1; break;
226 case 'i': inherit ^= 1; break;
227 case 'n': nmi ^= 1; break;
228 default: error = 1; break;
229 }
230 }
231
232 if (argc - optind == 0 && target_pid == -1)
233 error = 1;
234
235 if (error)
236 display_help();
237
238 if (!nr_counters) {
239 nr_counters = 1;
240 event_id[0] = 0;
241 }
242
243 for (counter = 0; counter < nr_counters; counter++) {
244 if (event_count[counter])
245 continue;
246
247 event_count[counter] = default_interval;
248 }
249}
250
251struct mmap_data { 66struct mmap_data {
252 int counter; 67 int counter;
253 void *base; 68 void *base;
@@ -538,16 +353,13 @@ static void open_counters(int cpu, pid_t pid)
538 nr_cpu++; 353 nr_cpu++;
539} 354}
540 355
541int cmd_record(int argc, char * const argv[]) 356static int __cmd_record(int argc, const char **argv)
542{ 357{
543 int i, counter; 358 int i, counter;
544 pid_t pid; 359 pid_t pid;
545 int ret; 360 int ret;
546 361
547 page_size = sysconf(_SC_PAGE_SIZE); 362 page_size = sysconf(_SC_PAGE_SIZE);
548
549 process_options(argc, argv);
550
551 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 363 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
552 assert(nr_cpus <= MAX_NR_CPUS); 364 assert(nr_cpus <= MAX_NR_CPUS);
553 assert(nr_cpus >= 0); 365 assert(nr_cpus >= 0);
@@ -558,9 +370,6 @@ int cmd_record(int argc, char * const argv[])
558 exit(-1); 370 exit(-1);
559 } 371 }
560 372
561 argc -= optind;
562 argv += optind;
563
564 if (!system_wide) { 373 if (!system_wide) {
565 open_counters(-1, target_pid != -1 ? target_pid : 0); 374 open_counters(-1, target_pid != -1 ? target_pid : 0);
566 } else for (i = 0; i < nr_cpus; i++) 375 } else for (i = 0; i < nr_cpus; i++)
@@ -575,7 +384,7 @@ int cmd_record(int argc, char * const argv[])
575 perror("failed to fork"); 384 perror("failed to fork");
576 385
577 if (!pid) { 386 if (!pid) {
578 if (execvp(argv[0], argv)) { 387 if (execvp(argv[0], (char **)argv)) {
579 perror(argv[0]); 388 perror(argv[0]);
580 exit(-1); 389 exit(-1);
581 } 390 }
@@ -610,3 +419,170 @@ int cmd_record(int argc, char * const argv[])
610 419
611 return 0; 420 return 0;
612} 421}
422
423struct event_symbol {
424 __u64 event;
425 char *symbol;
426};
427
428static struct event_symbol event_symbols[] = {
429 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
430 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
431 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
432 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
433 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
434 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
435 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
436 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
437 {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
438
439 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
440 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
441 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
442 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
443 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
444 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
445 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
446 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
447 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
448 {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
449};
450
451/*
452 * Each event can have multiple symbolic names.
453 * Symbolic names are (almost) exactly matched.
454 */
455static __u64 match_event_symbols(const char *str)
456{
457 __u64 config, id;
458 int type;
459 unsigned int i;
460
461 if (sscanf(str, "r%llx", &config) == 1)
462 return config | PERF_COUNTER_RAW_MASK;
463
464 if (sscanf(str, "%d:%llu", &type, &id) == 2)
465 return EID(type, id);
466
467 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
468 if (!strncmp(str, event_symbols[i].symbol,
469 strlen(event_symbols[i].symbol)))
470 return event_symbols[i].event;
471 }
472
473 return ~0ULL;
474}
475
476static int parse_events(const struct option *opt, const char *str, int unset)
477{
478 __u64 config;
479
480again:
481 if (nr_counters == MAX_COUNTERS)
482 return -1;
483
484 config = match_event_symbols(str);
485 if (config == ~0ULL)
486 return -1;
487
488 event_id[nr_counters] = config;
489 nr_counters++;
490
491 str = strstr(str, ",");
492 if (str) {
493 str++;
494 goto again;
495 }
496
497 return 0;
498}
499
500static char events_help[100000];
501
502#define __PERF_COUNTER_FIELD(config, name) \
503 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
504
505#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
506#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
507#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
508#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
509
510
511
512static void create_events_help(void)
513{
514 unsigned int i;
515 char *str;
516 __u64 e;
517
518 str = events_help;
519
520 str += sprintf(str,
521 "event name: [");
522
523 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
524 int type, id;
525
526 e = event_symbols[i].event;
527 type = PERF_COUNTER_TYPE(e);
528 id = PERF_COUNTER_ID(e);
529
530 if (i)
531 str += sprintf(str, "|");
532
533 str += sprintf(str, "%s",
534 event_symbols[i].symbol);
535 }
536
537 str += sprintf(str, "|rNNN]");
538}
539
540static const char * const record_usage[] = {
541 "perf record [<options>] <command>",
542 NULL
543};
544
545const struct option options[] = {
546 OPT_CALLBACK('e', "event", NULL, "event",
547 events_help, parse_events),
548 OPT_INTEGER('c', "count", &default_interval,
549 "event period to sample"),
550 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
551 "number of mmap data pages"),
552 OPT_STRING('o', "output", &output_name, "file",
553 "output file name"),
554 OPT_BOOLEAN('i', "inherit", &inherit,
555 "child tasks inherit counters"),
556 OPT_INTEGER('p', "pid", &target_pid,
557 "record events on existing pid"),
558 OPT_INTEGER('r', "realtime", &realtime_prio,
559 "collect data with this RT SCHED_FIFO priority"),
560 OPT_BOOLEAN('a', "all-cpus", &system_wide,
561 "system-wide collection from all CPUs"),
562 OPT_END()
563};
564
565int cmd_record(int argc, const char **argv, const char *prefix)
566{
567 int counter;
568
569 create_events_help();
570
571 argc = parse_options(argc, argv, options, record_usage, 0);
572 if (!argc)
573 usage_with_options(record_usage, options);
574
575 if (!nr_counters) {
576 nr_counters = 1;
577 event_id[0] = 0;
578 }
579
580 for (counter = 0; counter < nr_counters; counter++) {
581 if (event_count[counter])
582 continue;
583
584 event_count[counter] = default_interval;
585 }
586
587 return __cmd_record(argc, argv);
588}
diff --git a/Documentation/perf_counter/builtin-top.c b/Documentation/perf_counter/builtin-top.c
index 4bed265926dd..626b32076499 100644
--- a/Documentation/perf_counter/builtin-top.c
+++ b/Documentation/perf_counter/builtin-top.c
@@ -42,13 +42,16 @@
42 * Released under the GPL v2. (and only v2, not any later version) 42 * Released under the GPL v2. (and only v2, not any later version)
43 */ 43 */
44 44
45
45#include "perf.h" 46#include "perf.h"
46#include "util/util.h" 47#include "util/util.h"
47 48
48#include <getopt.h> 49#include <getopt.h>
49#include <assert.h> 50#include <assert.h>
50#include <fcntl.h> 51#include <fcntl.h>
52
51#include <stdio.h> 53#include <stdio.h>
54
52#include <errno.h> 55#include <errno.h>
53#include <time.h> 56#include <time.h>
54#include <sched.h> 57#include <sched.h>