diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-05-05 11:50:27 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-05 14:18:33 -0400 |
commit | 16c8a10932aef971292c9570eb5f60b5d4e83ed2 (patch) | |
tree | ee9f6860cad353bb7a5219468ffdc4e4fc700792 /Documentation | |
parent | 2023b359214bbc5bad31571cf50d7fb83b535c0a (diff) |
perf_counter: tools: update the tools to support process and inherited counters
"perf record":
- per task counter
- inherit switch
- nmi switch
"perf report":
- userspace/kernel filter
"perf stat":
- userspace/kernel filter
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
LKML-Reference: <20090505155437.389163017@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/perf_counter/builtin-record.c | 155 | ||||
-rw-r--r-- | Documentation/perf_counter/builtin-stat.c | 24 | ||||
-rw-r--r-- | Documentation/perf_counter/perf-report.cc | 27 |
3 files changed, 140 insertions, 66 deletions
diff --git a/Documentation/perf_counter/builtin-record.c b/Documentation/perf_counter/builtin-record.c index ddfdcf86fb20..5f5e6df0260d 100644 --- a/Documentation/perf_counter/builtin-record.c +++ b/Documentation/perf_counter/builtin-record.c | |||
@@ -45,7 +45,10 @@ static unsigned int mmap_pages = 16; | |||
45 | static int output; | 45 | static int output; |
46 | static char *output_name = "output.perf"; | 46 | static char *output_name = "output.perf"; |
47 | static int group = 0; | 47 | static int group = 0; |
48 | static unsigned int realtime_prio = 0; | 48 | static unsigned int realtime_prio = 0; |
49 | static int system_wide = 0; | ||
50 | static int inherit = 1; | ||
51 | static int nmi = 1; | ||
49 | 52 | ||
50 | const unsigned int default_count[] = { | 53 | const unsigned int default_count[] = { |
51 | 1000000, | 54 | 1000000, |
@@ -167,7 +170,7 @@ static void display_events_help(void) | |||
167 | static void display_help(void) | 170 | static void display_help(void) |
168 | { | 171 | { |
169 | printf( | 172 | printf( |
170 | "Usage: perf-record [<options>]\n" | 173 | "Usage: perf-record [<options>] <cmd>\n" |
171 | "perf-record Options (up to %d event types can be specified at once):\n\n", | 174 | "perf-record Options (up to %d event types can be specified at once):\n\n", |
172 | MAX_COUNTERS); | 175 | MAX_COUNTERS); |
173 | 176 | ||
@@ -178,12 +181,13 @@ static void display_help(void) | |||
178 | " -m pages --mmap_pages=<pages> # number of mmap data pages\n" | 181 | " -m pages --mmap_pages=<pages> # number of mmap data pages\n" |
179 | " -o file --output=<file> # output file\n" | 182 | " -o file --output=<file> # output file\n" |
180 | " -r prio --realtime=<prio> # use RT prio\n" | 183 | " -r prio --realtime=<prio> # use RT prio\n" |
184 | " -s --system # system wide profiling\n" | ||
181 | ); | 185 | ); |
182 | 186 | ||
183 | exit(0); | 187 | exit(0); |
184 | } | 188 | } |
185 | 189 | ||
186 | static void process_options(int argc, char *argv[]) | 190 | static void process_options(int argc, const char *argv[]) |
187 | { | 191 | { |
188 | int error = 0, counter; | 192 | int error = 0, counter; |
189 | 193 | ||
@@ -196,9 +200,12 @@ static void process_options(int argc, char *argv[]) | |||
196 | {"mmap_pages", required_argument, NULL, 'm'}, | 200 | {"mmap_pages", required_argument, NULL, 'm'}, |
197 | {"output", required_argument, NULL, 'o'}, | 201 | {"output", required_argument, NULL, 'o'}, |
198 | {"realtime", required_argument, NULL, 'r'}, | 202 | {"realtime", required_argument, NULL, 'r'}, |
203 | {"system", no_argument, NULL, 's'}, | ||
204 | {"inherit", no_argument, NULL, 'i'}, | ||
205 | {"nmi", no_argument, NULL, 'n'}, | ||
199 | {NULL, 0, NULL, 0 } | 206 | {NULL, 0, NULL, 0 } |
200 | }; | 207 | }; |
201 | int c = getopt_long(argc, argv, "+:c:e:m:o:r:", | 208 | int c = getopt_long(argc, argv, "+:c:e:m:o:r:sin", |
202 | long_options, &option_index); | 209 | long_options, &option_index); |
203 | if (c == -1) | 210 | if (c == -1) |
204 | break; | 211 | break; |
@@ -209,9 +216,16 @@ static void process_options(int argc, char *argv[]) | |||
209 | case 'm': mmap_pages = atoi(optarg); break; | 216 | case 'm': mmap_pages = atoi(optarg); break; |
210 | case 'o': output_name = strdup(optarg); break; | 217 | case 'o': output_name = strdup(optarg); break; |
211 | case 'r': realtime_prio = atoi(optarg); break; | 218 | case 'r': realtime_prio = atoi(optarg); break; |
219 | case 's': system_wide ^= 1; break; | ||
220 | case 'i': inherit ^= 1; break; | ||
221 | case 'n': nmi ^= 1; break; | ||
212 | default: error = 1; break; | 222 | default: error = 1; break; |
213 | } | 223 | } |
214 | } | 224 | } |
225 | |||
226 | if (argc - optind == 0) | ||
227 | error = 1; | ||
228 | |||
215 | if (error) | 229 | if (error) |
216 | display_help(); | 230 | display_help(); |
217 | 231 | ||
@@ -325,18 +339,82 @@ static void mmap_read(struct mmap_data *md) | |||
325 | 339 | ||
326 | static volatile int done = 0; | 340 | static volatile int done = 0; |
327 | 341 | ||
328 | static void sigchld_handler(int sig) | 342 | static void sig_handler(int sig) |
329 | { | 343 | { |
330 | if (sig == SIGCHLD) | 344 | done = 1; |
331 | done = 1; | ||
332 | } | 345 | } |
333 | 346 | ||
334 | int cmd_record(int argc, char **argv) | 347 | static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; |
348 | static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | ||
349 | |||
350 | static int nr_poll; | ||
351 | static int nr_cpu; | ||
352 | |||
353 | static void open_counters(int cpu) | ||
335 | { | 354 | { |
336 | struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; | ||
337 | struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | ||
338 | struct perf_counter_hw_event hw_event; | 355 | struct perf_counter_hw_event hw_event; |
339 | int i, counter, group_fd, nr_poll = 0; | 356 | int counter, group_fd; |
357 | int track = 1; | ||
358 | pid_t pid = -1; | ||
359 | |||
360 | if (cpu < 0) | ||
361 | pid = 0; | ||
362 | |||
363 | group_fd = -1; | ||
364 | for (counter = 0; counter < nr_counters; counter++) { | ||
365 | |||
366 | memset(&hw_event, 0, sizeof(hw_event)); | ||
367 | hw_event.config = event_id[counter]; | ||
368 | hw_event.irq_period = event_count[counter]; | ||
369 | hw_event.record_type = PERF_RECORD_IP | PERF_RECORD_TID; | ||
370 | hw_event.nmi = nmi; | ||
371 | hw_event.mmap = track; | ||
372 | hw_event.comm = track; | ||
373 | hw_event.inherit = (cpu < 0) && inherit; | ||
374 | |||
375 | track = 0; // only the first counter needs these | ||
376 | |||
377 | fd[nr_cpu][counter] = | ||
378 | sys_perf_counter_open(&hw_event, pid, cpu, group_fd, 0); | ||
379 | |||
380 | if (fd[nr_cpu][counter] < 0) { | ||
381 | int err = errno; | ||
382 | printf("kerneltop error: syscall returned with %d (%s)\n", | ||
383 | fd[nr_cpu][counter], strerror(err)); | ||
384 | if (err == EPERM) | ||
385 | printf("Are you root?\n"); | ||
386 | exit(-1); | ||
387 | } | ||
388 | assert(fd[nr_cpu][counter] >= 0); | ||
389 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); | ||
390 | |||
391 | /* | ||
392 | * First counter acts as the group leader: | ||
393 | */ | ||
394 | if (group && group_fd == -1) | ||
395 | group_fd = fd[nr_cpu][counter]; | ||
396 | |||
397 | event_array[nr_poll].fd = fd[nr_cpu][counter]; | ||
398 | event_array[nr_poll].events = POLLIN; | ||
399 | nr_poll++; | ||
400 | |||
401 | mmap_array[nr_cpu][counter].counter = counter; | ||
402 | mmap_array[nr_cpu][counter].prev = 0; | ||
403 | mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; | ||
404 | mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, | ||
405 | PROT_READ, MAP_SHARED, fd[nr_cpu][counter], 0); | ||
406 | if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { | ||
407 | printf("kerneltop error: failed to mmap with %d (%s)\n", | ||
408 | errno, strerror(errno)); | ||
409 | exit(-1); | ||
410 | } | ||
411 | } | ||
412 | nr_cpu++; | ||
413 | } | ||
414 | |||
415 | int cmd_record(int argc, const char **argv) | ||
416 | { | ||
417 | int i, counter; | ||
340 | pid_t pid; | 418 | pid_t pid; |
341 | int ret; | 419 | int ret; |
342 | 420 | ||
@@ -357,54 +435,13 @@ int cmd_record(int argc, char **argv) | |||
357 | argc -= optind; | 435 | argc -= optind; |
358 | argv += optind; | 436 | argv += optind; |
359 | 437 | ||
360 | for (i = 0; i < nr_cpus; i++) { | 438 | if (!system_wide) |
361 | group_fd = -1; | 439 | open_counters(-1); |
362 | for (counter = 0; counter < nr_counters; counter++) { | 440 | else for (i = 0; i < nr_cpus; i++) |
363 | 441 | open_counters(i); | |
364 | memset(&hw_event, 0, sizeof(hw_event)); | ||
365 | hw_event.config = event_id[counter]; | ||
366 | hw_event.irq_period = event_count[counter]; | ||
367 | hw_event.record_type = PERF_RECORD_IP | PERF_RECORD_TID; | ||
368 | hw_event.nmi = 1; | ||
369 | hw_event.mmap = 1; | ||
370 | hw_event.comm = 1; | ||
371 | |||
372 | fd[i][counter] = sys_perf_counter_open(&hw_event, -1, i, group_fd, 0); | ||
373 | if (fd[i][counter] < 0) { | ||
374 | int err = errno; | ||
375 | printf("kerneltop error: syscall returned with %d (%s)\n", | ||
376 | fd[i][counter], strerror(err)); | ||
377 | if (err == EPERM) | ||
378 | printf("Are you root?\n"); | ||
379 | exit(-1); | ||
380 | } | ||
381 | assert(fd[i][counter] >= 0); | ||
382 | fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); | ||
383 | |||
384 | /* | ||
385 | * First counter acts as the group leader: | ||
386 | */ | ||
387 | if (group && group_fd == -1) | ||
388 | group_fd = fd[i][counter]; | ||
389 | |||
390 | event_array[nr_poll].fd = fd[i][counter]; | ||
391 | event_array[nr_poll].events = POLLIN; | ||
392 | nr_poll++; | ||
393 | |||
394 | mmap_array[i][counter].counter = counter; | ||
395 | mmap_array[i][counter].prev = 0; | ||
396 | mmap_array[i][counter].mask = mmap_pages*page_size - 1; | ||
397 | mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size, | ||
398 | PROT_READ, MAP_SHARED, fd[i][counter], 0); | ||
399 | if (mmap_array[i][counter].base == MAP_FAILED) { | ||
400 | printf("kerneltop error: failed to mmap with %d (%s)\n", | ||
401 | errno, strerror(errno)); | ||
402 | exit(-1); | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | 442 | ||
407 | signal(SIGCHLD, sigchld_handler); | 443 | signal(SIGCHLD, sig_handler); |
444 | signal(SIGINT, sig_handler); | ||
408 | 445 | ||
409 | pid = fork(); | 446 | pid = fork(); |
410 | if (pid < 0) | 447 | if (pid < 0) |
@@ -434,7 +471,7 @@ int cmd_record(int argc, char **argv) | |||
434 | while (!done) { | 471 | while (!done) { |
435 | int hits = events; | 472 | int hits = events; |
436 | 473 | ||
437 | for (i = 0; i < nr_cpus; i++) { | 474 | for (i = 0; i < nr_cpu; i++) { |
438 | for (counter = 0; counter < nr_counters; counter++) | 475 | for (counter = 0; counter < nr_counters; counter++) |
439 | mmap_read(&mmap_array[i][counter]); | 476 | mmap_read(&mmap_array[i][counter]); |
440 | } | 477 | } |
diff --git a/Documentation/perf_counter/builtin-stat.c b/Documentation/perf_counter/builtin-stat.c index 6de38d256883..e2fa117eab58 100644 --- a/Documentation/perf_counter/builtin-stat.c +++ b/Documentation/perf_counter/builtin-stat.c | |||
@@ -87,6 +87,9 @@ | |||
87 | 87 | ||
88 | #include "perf.h" | 88 | #include "perf.h" |
89 | 89 | ||
90 | #define EVENT_MASK_KERNEL 1 | ||
91 | #define EVENT_MASK_USER 2 | ||
92 | |||
90 | static int system_wide = 0; | 93 | static int system_wide = 0; |
91 | 94 | ||
92 | static int nr_counters = 0; | 95 | static int nr_counters = 0; |
@@ -104,6 +107,7 @@ static __u64 event_id[MAX_COUNTERS] = { | |||
104 | static int default_interval = 100000; | 107 | static int default_interval = 100000; |
105 | static int event_count[MAX_COUNTERS]; | 108 | static int event_count[MAX_COUNTERS]; |
106 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; | 109 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; |
110 | static int event_mask[MAX_COUNTERS]; | ||
107 | 111 | ||
108 | static int tid = -1; | 112 | static int tid = -1; |
109 | static int profile_cpu = -1; | 113 | static int profile_cpu = -1; |
@@ -258,12 +262,23 @@ static __u64 match_event_symbols(char *str) | |||
258 | __u64 config, id; | 262 | __u64 config, id; |
259 | int type; | 263 | int type; |
260 | unsigned int i; | 264 | unsigned int i; |
265 | char mask_str[4]; | ||
261 | 266 | ||
262 | if (sscanf(str, "r%llx", &config) == 1) | 267 | if (sscanf(str, "r%llx", &config) == 1) |
263 | return config | PERF_COUNTER_RAW_MASK; | 268 | return config | PERF_COUNTER_RAW_MASK; |
264 | 269 | ||
265 | if (sscanf(str, "%d:%llu", &type, &id) == 2) | 270 | switch (sscanf(str, "%d:%llu:%2s", &type, &id, mask_str)) { |
266 | return EID(type, id); | 271 | case 3: |
272 | if (strchr(mask_str, 'u')) | ||
273 | event_mask[nr_counters] |= EVENT_MASK_USER; | ||
274 | if (strchr(mask_str, 'k')) | ||
275 | event_mask[nr_counters] |= EVENT_MASK_KERNEL; | ||
276 | case 2: | ||
277 | return EID(type, id); | ||
278 | |||
279 | default: | ||
280 | break; | ||
281 | } | ||
267 | 282 | ||
268 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { | 283 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { |
269 | if (!strncmp(str, event_symbols[i].symbol, | 284 | if (!strncmp(str, event_symbols[i].symbol, |
@@ -313,6 +328,11 @@ static void create_perfstat_counter(int counter) | |||
313 | hw_event.config = event_id[counter]; | 328 | hw_event.config = event_id[counter]; |
314 | hw_event.record_type = 0; | 329 | hw_event.record_type = 0; |
315 | hw_event.nmi = 0; | 330 | hw_event.nmi = 0; |
331 | hw_event.exclude_kernel = event_mask[counter] & EVENT_MASK_KERNEL; | ||
332 | hw_event.exclude_user = event_mask[counter] & EVENT_MASK_USER; | ||
333 | |||
334 | printf("exclude: %d\n", event_mask[counter]); | ||
335 | |||
316 | if (scale) | 336 | if (scale) |
317 | hw_event.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 337 | hw_event.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
318 | PERF_FORMAT_TOTAL_TIME_RUNNING; | 338 | PERF_FORMAT_TOTAL_TIME_RUNNING; |
diff --git a/Documentation/perf_counter/perf-report.cc b/Documentation/perf_counter/perf-report.cc index 911d7f3e7a65..8855107fe6b3 100644 --- a/Documentation/perf_counter/perf-report.cc +++ b/Documentation/perf_counter/perf-report.cc | |||
@@ -33,8 +33,13 @@ | |||
33 | #include <string> | 33 | #include <string> |
34 | 34 | ||
35 | 35 | ||
36 | #define SHOW_KERNEL 1 | ||
37 | #define SHOW_USER 2 | ||
38 | #define SHOW_HV 4 | ||
39 | |||
36 | static char const *input_name = "output.perf"; | 40 | static char const *input_name = "output.perf"; |
37 | static int input; | 41 | static int input; |
42 | static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; | ||
38 | 43 | ||
39 | static unsigned long page_size; | 44 | static unsigned long page_size; |
40 | static unsigned long mmap_window = 32; | 45 | static unsigned long mmap_window = 32; |
@@ -359,15 +364,21 @@ static void process_options(int argc, char *argv[]) | |||
359 | /** Options for getopt */ | 364 | /** Options for getopt */ |
360 | static struct option long_options[] = { | 365 | static struct option long_options[] = { |
361 | {"input", required_argument, NULL, 'i'}, | 366 | {"input", required_argument, NULL, 'i'}, |
367 | {"no-user", no_argument, NULL, 'u'}, | ||
368 | {"no-kernel", no_argument, NULL, 'k'}, | ||
369 | {"no-hv", no_argument, NULL, 'h'}, | ||
362 | {NULL, 0, NULL, 0 } | 370 | {NULL, 0, NULL, 0 } |
363 | }; | 371 | }; |
364 | int c = getopt_long(argc, argv, "+:i:", | 372 | int c = getopt_long(argc, argv, "+:i:kuh", |
365 | long_options, &option_index); | 373 | long_options, &option_index); |
366 | if (c == -1) | 374 | if (c == -1) |
367 | break; | 375 | break; |
368 | 376 | ||
369 | switch (c) { | 377 | switch (c) { |
370 | case 'i': input_name = strdup(optarg); break; | 378 | case 'i': input_name = strdup(optarg); break; |
379 | case 'k': show_mask &= ~SHOW_KERNEL; break; | ||
380 | case 'u': show_mask &= ~SHOW_USER; break; | ||
381 | case 'h': show_mask &= ~SHOW_HV; break; | ||
371 | default: error = 1; break; | 382 | default: error = 1; break; |
372 | } | 383 | } |
373 | } | 384 | } |
@@ -443,22 +454,28 @@ more: | |||
443 | 454 | ||
444 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) { | 455 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) { |
445 | std::string comm, sym, level; | 456 | std::string comm, sym, level; |
457 | int show = 0; | ||
446 | char output[1024]; | 458 | char output[1024]; |
447 | 459 | ||
448 | if (event->header.misc & PERF_EVENT_MISC_KERNEL) { | 460 | if (event->header.misc & PERF_EVENT_MISC_KERNEL) { |
461 | show |= SHOW_KERNEL; | ||
449 | level = " [k] "; | 462 | level = " [k] "; |
450 | sym = resolve_kernel_symbol(event->ip.ip); | 463 | sym = resolve_kernel_symbol(event->ip.ip); |
451 | } else if (event->header.misc & PERF_EVENT_MISC_USER) { | 464 | } else if (event->header.misc & PERF_EVENT_MISC_USER) { |
465 | show |= SHOW_USER; | ||
452 | level = " [.] "; | 466 | level = " [.] "; |
453 | sym = resolve_user_symbol(event->ip.pid, event->ip.ip); | 467 | sym = resolve_user_symbol(event->ip.pid, event->ip.ip); |
454 | } else { | 468 | } else { |
469 | show |= SHOW_HV; | ||
455 | level = " [H] "; | 470 | level = " [H] "; |
456 | } | 471 | } |
457 | comm = resolve_comm(event->ip.pid); | ||
458 | 472 | ||
459 | snprintf(output, sizeof(output), "%16s %s %s", | 473 | if (show & show_mask) { |
460 | comm.c_str(), level.c_str(), sym.c_str()); | 474 | comm = resolve_comm(event->ip.pid); |
461 | hist[output]++; | 475 | snprintf(output, sizeof(output), "%16s %s %s", |
476 | comm.c_str(), level.c_str(), sym.c_str()); | ||
477 | hist[output]++; | ||
478 | } | ||
462 | 479 | ||
463 | total++; | 480 | total++; |
464 | 481 | ||