diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 75d230fef202..1c49d4e8767c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -638,6 +638,77 @@ out_delete_session: | |||
638 | return err; | 638 | return err; |
639 | } | 639 | } |
640 | 640 | ||
641 | #define BRANCH_OPT(n, m) \ | ||
642 | { .name = n, .mode = (m) } | ||
643 | |||
644 | #define BRANCH_END { .name = NULL } | ||
645 | |||
646 | struct branch_mode { | ||
647 | const char *name; | ||
648 | int mode; | ||
649 | }; | ||
650 | |||
651 | static const struct branch_mode branch_modes[] = { | ||
652 | BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER), | ||
653 | BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL), | ||
654 | BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV), | ||
655 | BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY), | ||
656 | BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), | ||
657 | BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), | ||
658 | BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), | ||
659 | BRANCH_END | ||
660 | }; | ||
661 | |||
662 | static int | ||
663 | parse_branch_stack(const struct option *opt, const char *str, int unset __used) | ||
664 | { | ||
665 | #define ONLY_PLM \ | ||
666 | (PERF_SAMPLE_BRANCH_USER |\ | ||
667 | PERF_SAMPLE_BRANCH_KERNEL |\ | ||
668 | PERF_SAMPLE_BRANCH_HV) | ||
669 | |||
670 | uint64_t *mode = (uint64_t *)opt->value; | ||
671 | const struct branch_mode *br; | ||
672 | char *s, *os, *p; | ||
673 | int ret = -1; | ||
674 | |||
675 | *mode = 0; | ||
676 | |||
677 | /* because str is read-only */ | ||
678 | s = os = strdup(str); | ||
679 | if (!s) | ||
680 | return -1; | ||
681 | |||
682 | for (;;) { | ||
683 | p = strchr(s, ','); | ||
684 | if (p) | ||
685 | *p = '\0'; | ||
686 | |||
687 | for (br = branch_modes; br->name; br++) { | ||
688 | if (!strcasecmp(s, br->name)) | ||
689 | break; | ||
690 | } | ||
691 | if (!br->name) | ||
692 | goto error; | ||
693 | |||
694 | *mode |= br->mode; | ||
695 | |||
696 | if (!p) | ||
697 | break; | ||
698 | |||
699 | s = p + 1; | ||
700 | } | ||
701 | ret = 0; | ||
702 | |||
703 | if ((*mode & ~ONLY_PLM) == 0) { | ||
704 | error("need at least one branch type with -b\n"); | ||
705 | ret = -1; | ||
706 | } | ||
707 | error: | ||
708 | free(os); | ||
709 | return ret; | ||
710 | } | ||
711 | |||
641 | static const char * const record_usage[] = { | 712 | static const char * const record_usage[] = { |
642 | "perf record [<options>] [<command>]", | 713 | "perf record [<options>] [<command>]", |
643 | "perf record [<options>] -- <command> [<options>]", | 714 | "perf record [<options>] -- <command> [<options>]", |
@@ -727,6 +798,9 @@ const struct option record_options[] = { | |||
727 | "monitor event in cgroup name only", | 798 | "monitor event in cgroup name only", |
728 | parse_cgroups), | 799 | parse_cgroups), |
729 | OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"), | 800 | OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"), |
801 | OPT_CALLBACK('b', "branch-stack", &record.opts.branch_stack, | ||
802 | "branch mode mask", "branch stack sampling modes", | ||
803 | parse_branch_stack), | ||
730 | OPT_END() | 804 | OPT_END() |
731 | }; | 805 | }; |
732 | 806 | ||