aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r--tools/perf/builtin-record.c152
1 files changed, 121 insertions, 31 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 227b6ae9978..be4e1eee782 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -44,6 +44,7 @@ struct perf_record {
44 struct perf_evlist *evlist; 44 struct perf_evlist *evlist;
45 struct perf_session *session; 45 struct perf_session *session;
46 const char *progname; 46 const char *progname;
47 const char *uid_str;
47 int output; 48 int output;
48 unsigned int page_size; 49 unsigned int page_size;
49 int realtime_prio; 50 int realtime_prio;
@@ -208,7 +209,7 @@ fallback_missing_features:
208 if (opts->exclude_guest_missing) 209 if (opts->exclude_guest_missing)
209 attr->exclude_guest = attr->exclude_host = 0; 210 attr->exclude_guest = attr->exclude_host = 0;
210retry_sample_id: 211retry_sample_id:
211 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; 212 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
212try_again: 213try_again:
213 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, 214 if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
214 opts->group, group_fd) < 0) { 215 opts->group, group_fd) < 0) {
@@ -227,11 +228,11 @@ try_again:
227 "guest or host samples.\n"); 228 "guest or host samples.\n");
228 opts->exclude_guest_missing = true; 229 opts->exclude_guest_missing = true;
229 goto fallback_missing_features; 230 goto fallback_missing_features;
230 } else if (opts->sample_id_all_avail) { 231 } else if (!opts->sample_id_all_missing) {
231 /* 232 /*
232 * Old kernel, no attr->sample_id_type_all field 233 * Old kernel, no attr->sample_id_type_all field
233 */ 234 */
234 opts->sample_id_all_avail = false; 235 opts->sample_id_all_missing = true;
235 if (!opts->sample_time && !opts->raw_samples && !time_needed) 236 if (!opts->sample_time && !opts->raw_samples && !time_needed)
236 attr->sample_type &= ~PERF_SAMPLE_TIME; 237 attr->sample_type &= ~PERF_SAMPLE_TIME;
237 238
@@ -396,7 +397,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
396{ 397{
397 struct stat st; 398 struct stat st;
398 int flags; 399 int flags;
399 int err, output; 400 int err, output, feat;
400 unsigned long waking = 0; 401 unsigned long waking = 0;
401 const bool forks = argc > 0; 402 const bool forks = argc > 0;
402 struct machine *machine; 403 struct machine *machine;
@@ -463,8 +464,17 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
463 464
464 rec->session = session; 465 rec->session = session;
465 466
466 if (!rec->no_buildid) 467 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
467 perf_header__set_feat(&session->header, HEADER_BUILD_ID); 468 perf_header__set_feat(&session->header, feat);
469
470 if (rec->no_buildid)
471 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
472
473 if (!have_tracepoints(&evsel_list->entries))
474 perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
475
476 if (!rec->opts.branch_stack)
477 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
468 478
469 if (!rec->file_new) { 479 if (!rec->file_new) {
470 err = perf_session__read_header(session, output); 480 err = perf_session__read_header(session, output);
@@ -472,22 +482,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
472 goto out_delete_session; 482 goto out_delete_session;
473 } 483 }
474 484
475 if (have_tracepoints(&evsel_list->entries))
476 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
477
478 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
479 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
480 perf_header__set_feat(&session->header, HEADER_ARCH);
481 perf_header__set_feat(&session->header, HEADER_CPUDESC);
482 perf_header__set_feat(&session->header, HEADER_NRCPUS);
483 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
484 perf_header__set_feat(&session->header, HEADER_CMDLINE);
485 perf_header__set_feat(&session->header, HEADER_VERSION);
486 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
487 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
488 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
489 perf_header__set_feat(&session->header, HEADER_CPUID);
490
491 if (forks) { 485 if (forks) {
492 err = perf_evlist__prepare_workload(evsel_list, opts, argv); 486 err = perf_evlist__prepare_workload(evsel_list, opts, argv);
493 if (err < 0) { 487 if (err < 0) {
@@ -647,6 +641,90 @@ out_delete_session:
647 return err; 641 return err;
648} 642}
649 643
644#define BRANCH_OPT(n, m) \
645 { .name = n, .mode = (m) }
646
647#define BRANCH_END { .name = NULL }
648
649struct branch_mode {
650 const char *name;
651 int mode;
652};
653
654static const struct branch_mode branch_modes[] = {
655 BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
656 BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
657 BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
658 BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
659 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
660 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
661 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
662 BRANCH_END
663};
664
665static int
666parse_branch_stack(const struct option *opt, const char *str, int unset)
667{
668#define ONLY_PLM \
669 (PERF_SAMPLE_BRANCH_USER |\
670 PERF_SAMPLE_BRANCH_KERNEL |\
671 PERF_SAMPLE_BRANCH_HV)
672
673 uint64_t *mode = (uint64_t *)opt->value;
674 const struct branch_mode *br;
675 char *s, *os = NULL, *p;
676 int ret = -1;
677
678 if (unset)
679 return 0;
680
681 /*
682 * cannot set it twice, -b + --branch-filter for instance
683 */
684 if (*mode)
685 return -1;
686
687 /* str may be NULL in case no arg is passed to -b */
688 if (str) {
689 /* because str is read-only */
690 s = os = strdup(str);
691 if (!s)
692 return -1;
693
694 for (;;) {
695 p = strchr(s, ',');
696 if (p)
697 *p = '\0';
698
699 for (br = branch_modes; br->name; br++) {
700 if (!strcasecmp(s, br->name))
701 break;
702 }
703 if (!br->name) {
704 ui__warning("unknown branch filter %s,"
705 " check man page\n", s);
706 goto error;
707 }
708
709 *mode |= br->mode;
710
711 if (!p)
712 break;
713
714 s = p + 1;
715 }
716 }
717 ret = 0;
718
719 /* default to any branch */
720 if ((*mode & ~ONLY_PLM) == 0) {
721 *mode = PERF_SAMPLE_BRANCH_ANY;
722 }
723error:
724 free(os);
725 return ret;
726}
727
650static const char * const record_usage[] = { 728static const char * const record_usage[] = {
651 "perf record [<options>] [<command>]", 729 "perf record [<options>] [<command>]",
652 "perf record [<options>] -- <command> [<options>]", 730 "perf record [<options>] -- <command> [<options>]",
@@ -665,13 +743,10 @@ static const char * const record_usage[] = {
665 */ 743 */
666static struct perf_record record = { 744static struct perf_record record = {
667 .opts = { 745 .opts = {
668 .target_pid = -1,
669 .target_tid = -1,
670 .mmap_pages = UINT_MAX, 746 .mmap_pages = UINT_MAX,
671 .user_freq = UINT_MAX, 747 .user_freq = UINT_MAX,
672 .user_interval = ULLONG_MAX, 748 .user_interval = ULLONG_MAX,
673 .freq = 1000, 749 .freq = 1000,
674 .sample_id_all_avail = true,
675 }, 750 },
676 .write_mode = WRITE_FORCE, 751 .write_mode = WRITE_FORCE,
677 .file_new = true, 752 .file_new = true,
@@ -690,9 +765,9 @@ const struct option record_options[] = {
690 parse_events_option), 765 parse_events_option),
691 OPT_CALLBACK(0, "filter", &record.evlist, "filter", 766 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
692 "event filter", parse_filter), 767 "event filter", parse_filter),
693 OPT_INTEGER('p', "pid", &record.opts.target_pid, 768 OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
694 "record events on existing process id"), 769 "record events on existing process id"),
695 OPT_INTEGER('t', "tid", &record.opts.target_tid, 770 OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
696 "record events on existing thread id"), 771 "record events on existing thread id"),
697 OPT_INTEGER('r', "realtime", &record.realtime_prio, 772 OPT_INTEGER('r', "realtime", &record.realtime_prio,
698 "collect data with this RT SCHED_FIFO priority"), 773 "collect data with this RT SCHED_FIFO priority"),
@@ -738,6 +813,15 @@ const struct option record_options[] = {
738 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 813 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
739 "monitor event in cgroup name only", 814 "monitor event in cgroup name only",
740 parse_cgroups), 815 parse_cgroups),
816 OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
817
818 OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
819 "branch any", "sample any taken branches",
820 parse_branch_stack),
821
822 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
823 "branch filter mask", "branch stack filter modes",
824 parse_branch_stack),
741 OPT_END() 825 OPT_END()
742}; 826};
743 827
@@ -758,8 +842,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
758 842
759 argc = parse_options(argc, argv, record_options, record_usage, 843 argc = parse_options(argc, argv, record_options, record_usage,
760 PARSE_OPT_STOP_AT_NON_OPTION); 844 PARSE_OPT_STOP_AT_NON_OPTION);
761 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 && 845 if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
762 !rec->opts.system_wide && !rec->opts.cpu_list) 846 !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
763 usage_with_options(record_usage, record_options); 847 usage_with_options(record_usage, record_options);
764 848
765 if (rec->force && rec->append_file) { 849 if (rec->force && rec->append_file) {
@@ -799,11 +883,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
799 goto out_symbol_exit; 883 goto out_symbol_exit;
800 } 884 }
801 885
802 if (rec->opts.target_pid != -1) 886 rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
887 rec->opts.target_pid);
888 if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
889 goto out_free_fd;
890
891 if (rec->opts.target_pid)
803 rec->opts.target_tid = rec->opts.target_pid; 892 rec->opts.target_tid = rec->opts.target_pid;
804 893
805 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, 894 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
806 rec->opts.target_tid, rec->opts.cpu_list) < 0) 895 rec->opts.target_tid, rec->opts.uid,
896 rec->opts.cpu_list) < 0)
807 usage_with_options(record_usage, record_options); 897 usage_with_options(record_usage, record_options);
808 898
809 list_for_each_entry(pos, &evsel_list->entries, node) { 899 list_for_each_entry(pos, &evsel_list->entries, node) {