diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-09-11 17:19:45 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-09-13 04:22:40 -0400 |
commit | bcd3279f465cdcc1e0454b5f605f021c4ff4dbb5 (patch) | |
tree | 9a3d5fa6542742144aaecbfc796ec40b2287e04c /tools | |
parent | ad236fd23b6d6372dcacd549983cce051d2ccff6 (diff) |
perf tools: Allow the specification of all tracepoints at once
Currently, when one wants to activate every tracepoint
counters of a subsystem from perf record, the current sequence
is needed:
perf record -e subsys:ev1 -e subsys:ev2 -e subsys:ev3
This may annoy the most patient of us.
Now we can just do:
perf record -e subsys:*
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/parse-events.c | 204 |
1 files changed, 154 insertions, 50 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a587d41ae3c9..d06c66cd358b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -18,6 +18,12 @@ struct event_symbol { | |||
18 | const char *alias; | 18 | const char *alias; |
19 | }; | 19 | }; |
20 | 20 | ||
21 | enum event_result { | ||
22 | EVT_FAILED, | ||
23 | EVT_HANDLED, | ||
24 | EVT_HANDLED_ALL | ||
25 | }; | ||
26 | |||
21 | char debugfs_path[MAXPATHLEN]; | 27 | char debugfs_path[MAXPATHLEN]; |
22 | 28 | ||
23 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x | 29 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x |
@@ -344,7 +350,7 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int | |||
344 | return -1; | 350 | return -1; |
345 | } | 351 | } |
346 | 352 | ||
347 | static int | 353 | static enum event_result |
348 | parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | 354 | parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) |
349 | { | 355 | { |
350 | const char *s = *str; | 356 | const char *s = *str; |
@@ -356,7 +362,7 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | |||
356 | * then bail out: | 362 | * then bail out: |
357 | */ | 363 | */ |
358 | if (cache_type == -1) | 364 | if (cache_type == -1) |
359 | return 0; | 365 | return EVT_FAILED; |
360 | 366 | ||
361 | while ((cache_op == -1 || cache_result == -1) && *s == '-') { | 367 | while ((cache_op == -1 || cache_result == -1) && *s == '-') { |
362 | ++s; | 368 | ++s; |
@@ -402,27 +408,112 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | |||
402 | attr->type = PERF_TYPE_HW_CACHE; | 408 | attr->type = PERF_TYPE_HW_CACHE; |
403 | 409 | ||
404 | *str = s; | 410 | *str = s; |
405 | return 1; | 411 | return EVT_HANDLED; |
412 | } | ||
413 | |||
414 | static enum event_result | ||
415 | parse_single_tracepoint_event(char *sys_name, | ||
416 | const char *evt_name, | ||
417 | unsigned int evt_length, | ||
418 | char *flags, | ||
419 | struct perf_counter_attr *attr, | ||
420 | const char **strp) | ||
421 | { | ||
422 | char evt_path[MAXPATHLEN]; | ||
423 | char id_buf[4]; | ||
424 | u64 id; | ||
425 | int fd; | ||
426 | |||
427 | if (flags) { | ||
428 | if (!strncmp(flags, "record", strlen(flags))) | ||
429 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
430 | } | ||
431 | |||
432 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | ||
433 | sys_name, evt_name); | ||
434 | |||
435 | fd = open(evt_path, O_RDONLY); | ||
436 | if (fd < 0) | ||
437 | return EVT_FAILED; | ||
438 | |||
439 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
440 | close(fd); | ||
441 | return EVT_FAILED; | ||
442 | } | ||
443 | |||
444 | close(fd); | ||
445 | id = atoll(id_buf); | ||
446 | attr->config = id; | ||
447 | attr->type = PERF_TYPE_TRACEPOINT; | ||
448 | *strp = evt_name + evt_length; | ||
449 | |||
450 | return EVT_HANDLED; | ||
406 | } | 451 | } |
407 | 452 | ||
408 | static int parse_tracepoint_event(const char **strp, | 453 | /* sys + ':' + event + ':' + flags*/ |
454 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) | ||
455 | static enum event_result | ||
456 | parse_subsystem_tracepoint_event(char *sys_name, char *flags) | ||
457 | { | ||
458 | char evt_path[MAXPATHLEN]; | ||
459 | struct dirent *evt_ent; | ||
460 | DIR *evt_dir; | ||
461 | |||
462 | snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name); | ||
463 | evt_dir = opendir(evt_path); | ||
464 | |||
465 | if (!evt_dir) { | ||
466 | perror("Can't open event dir"); | ||
467 | return EVT_FAILED; | ||
468 | } | ||
469 | |||
470 | while ((evt_ent = readdir(evt_dir))) { | ||
471 | char event_opt[MAX_EVOPT_LEN + 1]; | ||
472 | int len; | ||
473 | unsigned int rem = MAX_EVOPT_LEN; | ||
474 | |||
475 | if (!strcmp(evt_ent->d_name, ".") | ||
476 | || !strcmp(evt_ent->d_name, "..") | ||
477 | || !strcmp(evt_ent->d_name, "enable") | ||
478 | || !strcmp(evt_ent->d_name, "filter")) | ||
479 | continue; | ||
480 | |||
481 | len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, | ||
482 | evt_ent->d_name); | ||
483 | if (len < 0) | ||
484 | return EVT_FAILED; | ||
485 | |||
486 | rem -= len; | ||
487 | if (flags) { | ||
488 | if (rem < strlen(flags) + 1) | ||
489 | return EVT_FAILED; | ||
490 | |||
491 | strcat(event_opt, ":"); | ||
492 | strcat(event_opt, flags); | ||
493 | } | ||
494 | |||
495 | if (parse_events(NULL, event_opt, 0)) | ||
496 | return EVT_FAILED; | ||
497 | } | ||
498 | |||
499 | return EVT_HANDLED_ALL; | ||
500 | } | ||
501 | |||
502 | |||
503 | static enum event_result parse_tracepoint_event(const char **strp, | ||
409 | struct perf_counter_attr *attr) | 504 | struct perf_counter_attr *attr) |
410 | { | 505 | { |
411 | const char *evt_name; | 506 | const char *evt_name; |
412 | char *flags; | 507 | char *flags; |
413 | char sys_name[MAX_EVENT_LENGTH]; | 508 | char sys_name[MAX_EVENT_LENGTH]; |
414 | char id_buf[4]; | ||
415 | int fd; | ||
416 | unsigned int sys_length, evt_length; | 509 | unsigned int sys_length, evt_length; |
417 | u64 id; | ||
418 | char evt_path[MAXPATHLEN]; | ||
419 | 510 | ||
420 | if (valid_debugfs_mount(debugfs_path)) | 511 | if (valid_debugfs_mount(debugfs_path)) |
421 | return 0; | 512 | return 0; |
422 | 513 | ||
423 | evt_name = strchr(*strp, ':'); | 514 | evt_name = strchr(*strp, ':'); |
424 | if (!evt_name) | 515 | if (!evt_name) |
425 | return 0; | 516 | return EVT_FAILED; |
426 | 517 | ||
427 | sys_length = evt_name - *strp; | 518 | sys_length = evt_name - *strp; |
428 | if (sys_length >= MAX_EVENT_LENGTH) | 519 | if (sys_length >= MAX_EVENT_LENGTH) |
@@ -436,30 +527,19 @@ static int parse_tracepoint_event(const char **strp, | |||
436 | if (flags) { | 527 | if (flags) { |
437 | *flags = '\0'; | 528 | *flags = '\0'; |
438 | flags++; | 529 | flags++; |
439 | if (!strncmp(flags, "record", strlen(flags))) | ||
440 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
441 | } | 530 | } |
442 | 531 | ||
443 | evt_length = strlen(evt_name); | 532 | evt_length = strlen(evt_name); |
444 | if (evt_length >= MAX_EVENT_LENGTH) | 533 | if (evt_length >= MAX_EVENT_LENGTH) |
445 | return 0; | 534 | return EVT_FAILED; |
446 | 535 | ||
447 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | 536 | if (!strcmp(evt_name, "*")) { |
448 | sys_name, evt_name); | 537 | *strp = evt_name + evt_length; |
449 | fd = open(evt_path, O_RDONLY); | 538 | return parse_subsystem_tracepoint_event(sys_name, flags); |
450 | if (fd < 0) | 539 | } else |
451 | return 0; | 540 | return parse_single_tracepoint_event(sys_name, evt_name, |
452 | 541 | evt_length, flags, | |
453 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | 542 | attr, strp); |
454 | close(fd); | ||
455 | return 0; | ||
456 | } | ||
457 | close(fd); | ||
458 | id = atoll(id_buf); | ||
459 | attr->config = id; | ||
460 | attr->type = PERF_TYPE_TRACEPOINT; | ||
461 | *strp = evt_name + evt_length; | ||
462 | return 1; | ||
463 | } | 543 | } |
464 | 544 | ||
465 | static int check_events(const char *str, unsigned int i) | 545 | static int check_events(const char *str, unsigned int i) |
@@ -477,7 +557,7 @@ static int check_events(const char *str, unsigned int i) | |||
477 | return 0; | 557 | return 0; |
478 | } | 558 | } |
479 | 559 | ||
480 | static int | 560 | static enum event_result |
481 | parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) | 561 | parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) |
482 | { | 562 | { |
483 | const char *str = *strp; | 563 | const char *str = *strp; |
@@ -490,31 +570,32 @@ parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) | |||
490 | attr->type = event_symbols[i].type; | 570 | attr->type = event_symbols[i].type; |
491 | attr->config = event_symbols[i].config; | 571 | attr->config = event_symbols[i].config; |
492 | *strp = str + n; | 572 | *strp = str + n; |
493 | return 1; | 573 | return EVT_HANDLED; |
494 | } | 574 | } |
495 | } | 575 | } |
496 | return 0; | 576 | return EVT_FAILED; |
497 | } | 577 | } |
498 | 578 | ||
499 | static int parse_raw_event(const char **strp, struct perf_counter_attr *attr) | 579 | static enum event_result |
580 | parse_raw_event(const char **strp, struct perf_counter_attr *attr) | ||
500 | { | 581 | { |
501 | const char *str = *strp; | 582 | const char *str = *strp; |
502 | u64 config; | 583 | u64 config; |
503 | int n; | 584 | int n; |
504 | 585 | ||
505 | if (*str != 'r') | 586 | if (*str != 'r') |
506 | return 0; | 587 | return EVT_FAILED; |
507 | n = hex2u64(str + 1, &config); | 588 | n = hex2u64(str + 1, &config); |
508 | if (n > 0) { | 589 | if (n > 0) { |
509 | *strp = str + n + 1; | 590 | *strp = str + n + 1; |
510 | attr->type = PERF_TYPE_RAW; | 591 | attr->type = PERF_TYPE_RAW; |
511 | attr->config = config; | 592 | attr->config = config; |
512 | return 1; | 593 | return EVT_HANDLED; |
513 | } | 594 | } |
514 | return 0; | 595 | return EVT_FAILED; |
515 | } | 596 | } |
516 | 597 | ||
517 | static int | 598 | static enum event_result |
518 | parse_numeric_event(const char **strp, struct perf_counter_attr *attr) | 599 | parse_numeric_event(const char **strp, struct perf_counter_attr *attr) |
519 | { | 600 | { |
520 | const char *str = *strp; | 601 | const char *str = *strp; |
@@ -530,13 +611,13 @@ parse_numeric_event(const char **strp, struct perf_counter_attr *attr) | |||
530 | attr->type = type; | 611 | attr->type = type; |
531 | attr->config = config; | 612 | attr->config = config; |
532 | *strp = endp; | 613 | *strp = endp; |
533 | return 1; | 614 | return EVT_HANDLED; |
534 | } | 615 | } |
535 | } | 616 | } |
536 | return 0; | 617 | return EVT_FAILED; |
537 | } | 618 | } |
538 | 619 | ||
539 | static int | 620 | static enum event_result |
540 | parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | 621 | parse_event_modifier(const char **strp, struct perf_counter_attr *attr) |
541 | { | 622 | { |
542 | const char *str = *strp; | 623 | const char *str = *strp; |
@@ -569,37 +650,60 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | |||
569 | * Each event can have multiple symbolic names. | 650 | * Each event can have multiple symbolic names. |
570 | * Symbolic names are (almost) exactly matched. | 651 | * Symbolic names are (almost) exactly matched. |
571 | */ | 652 | */ |
572 | static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) | 653 | static enum event_result |
654 | parse_event_symbols(const char **str, struct perf_counter_attr *attr) | ||
573 | { | 655 | { |
574 | if (!(parse_tracepoint_event(str, attr) || | 656 | enum event_result ret; |
575 | parse_raw_event(str, attr) || | 657 | |
576 | parse_numeric_event(str, attr) || | 658 | ret = parse_tracepoint_event(str, attr); |
577 | parse_symbolic_event(str, attr) || | 659 | if (ret != EVT_FAILED) |
578 | parse_generic_hw_event(str, attr))) | 660 | goto modifier; |
579 | return 0; | 661 | |
662 | ret = parse_raw_event(str, attr); | ||
663 | if (ret != EVT_FAILED) | ||
664 | goto modifier; | ||
580 | 665 | ||
666 | ret = parse_numeric_event(str, attr); | ||
667 | if (ret != EVT_FAILED) | ||
668 | goto modifier; | ||
669 | |||
670 | ret = parse_symbolic_event(str, attr); | ||
671 | if (ret != EVT_FAILED) | ||
672 | goto modifier; | ||
673 | |||
674 | ret = parse_generic_hw_event(str, attr); | ||
675 | if (ret != EVT_FAILED) | ||
676 | goto modifier; | ||
677 | |||
678 | return EVT_FAILED; | ||
679 | |||
680 | modifier: | ||
581 | parse_event_modifier(str, attr); | 681 | parse_event_modifier(str, attr); |
582 | 682 | ||
583 | return 1; | 683 | return ret; |
584 | } | 684 | } |
585 | 685 | ||
586 | int parse_events(const struct option *opt __used, const char *str, int unset __used) | 686 | int parse_events(const struct option *opt __used, const char *str, int unset __used) |
587 | { | 687 | { |
588 | struct perf_counter_attr attr; | 688 | struct perf_counter_attr attr; |
689 | enum event_result ret; | ||
589 | 690 | ||
590 | for (;;) { | 691 | for (;;) { |
591 | if (nr_counters == MAX_COUNTERS) | 692 | if (nr_counters == MAX_COUNTERS) |
592 | return -1; | 693 | return -1; |
593 | 694 | ||
594 | memset(&attr, 0, sizeof(attr)); | 695 | memset(&attr, 0, sizeof(attr)); |
595 | if (!parse_event_symbols(&str, &attr)) | 696 | ret = parse_event_symbols(&str, &attr); |
697 | if (ret == EVT_FAILED) | ||
596 | return -1; | 698 | return -1; |
597 | 699 | ||
598 | if (!(*str == 0 || *str == ',' || isspace(*str))) | 700 | if (!(*str == 0 || *str == ',' || isspace(*str))) |
599 | return -1; | 701 | return -1; |
600 | 702 | ||
601 | attrs[nr_counters] = attr; | 703 | if (ret != EVT_HANDLED_ALL) { |
602 | nr_counters++; | 704 | attrs[nr_counters] = attr; |
705 | nr_counters++; | ||
706 | } | ||
603 | 707 | ||
604 | if (*str == 0) | 708 | if (*str == 0) |
605 | break; | 709 | break; |