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.c146
1 files changed, 31 insertions, 115 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4869050e7194..44c6f3d55ce7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -65,8 +65,9 @@ static int process_synthesized_event(struct perf_tool *tool,
65 return record__write(rec, event, event->header.size); 65 return record__write(rec, event, event->header.size);
66} 66}
67 67
68static int record__mmap_read(struct record *rec, struct perf_mmap *md) 68static int record__mmap_read(struct record *rec, int idx)
69{ 69{
70 struct perf_mmap *md = &rec->evlist->mmap[idx];
70 unsigned int head = perf_mmap__read_head(md); 71 unsigned int head = perf_mmap__read_head(md);
71 unsigned int old = md->prev; 72 unsigned int old = md->prev;
72 unsigned char *data = md->base + page_size; 73 unsigned char *data = md->base + page_size;
@@ -102,8 +103,7 @@ static int record__mmap_read(struct record *rec, struct perf_mmap *md)
102 } 103 }
103 104
104 md->prev = old; 105 md->prev = old;
105 perf_mmap__write_tail(md, old); 106 perf_evlist__mmap_consume(rec->evlist, idx);
106
107out: 107out:
108 return rc; 108 return rc;
109} 109}
@@ -161,7 +161,7 @@ try_again:
161 161
162 if (perf_evlist__apply_filters(evlist)) { 162 if (perf_evlist__apply_filters(evlist)) {
163 error("failed to set filter with %d (%s)\n", errno, 163 error("failed to set filter with %d (%s)\n", errno,
164 strerror(errno)); 164 strerror_r(errno, msg, sizeof(msg)));
165 rc = -1; 165 rc = -1;
166 goto out; 166 goto out;
167 } 167 }
@@ -175,7 +175,8 @@ try_again:
175 "(current value: %u)\n", opts->mmap_pages); 175 "(current value: %u)\n", opts->mmap_pages);
176 rc = -errno; 176 rc = -errno;
177 } else { 177 } else {
178 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 178 pr_err("failed to mmap with %d (%s)\n", errno,
179 strerror_r(errno, msg, sizeof(msg)));
179 rc = -errno; 180 rc = -errno;
180 } 181 }
181 goto out; 182 goto out;
@@ -244,7 +245,7 @@ static int record__mmap_read_all(struct record *rec)
244 245
245 for (i = 0; i < rec->evlist->nr_mmaps; i++) { 246 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
246 if (rec->evlist->mmap[i].base) { 247 if (rec->evlist->mmap[i].base) {
247 if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { 248 if (record__mmap_read(rec, i) != 0) {
248 rc = -1; 249 rc = -1;
249 goto out; 250 goto out;
250 } 251 }
@@ -307,7 +308,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
307 struct record_opts *opts = &rec->opts; 308 struct record_opts *opts = &rec->opts;
308 struct perf_data_file *file = &rec->file; 309 struct perf_data_file *file = &rec->file;
309 struct perf_session *session; 310 struct perf_session *session;
310 bool disabled = false; 311 bool disabled = false, draining = false;
311 312
312 rec->progname = argv[0]; 313 rec->progname = argv[0];
313 314
@@ -456,9 +457,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
456 } 457 }
457 458
458 if (hits == rec->samples) { 459 if (hits == rec->samples) {
459 if (done) 460 if (done || draining)
460 break; 461 break;
461 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); 462 err = perf_evlist__poll(rec->evlist, -1);
462 /* 463 /*
463 * Propagate error, only if there's any. Ignore positive 464 * Propagate error, only if there's any. Ignore positive
464 * number of returned events and interrupt error. 465 * number of returned events and interrupt error.
@@ -466,6 +467,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
466 if (err > 0 || (err < 0 && errno == EINTR)) 467 if (err > 0 || (err < 0 && errno == EINTR))
467 err = 0; 468 err = 0;
468 waking++; 469 waking++;
470
471 if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
472 draining = true;
469 } 473 }
470 474
471 /* 475 /*
@@ -480,7 +484,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
480 } 484 }
481 485
482 if (forks && workload_exec_errno) { 486 if (forks && workload_exec_errno) {
483 char msg[512]; 487 char msg[STRERR_BUFSIZE];
484 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); 488 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
485 pr_err("Workload failed: %s\n", emsg); 489 pr_err("Workload failed: %s\n", emsg);
486 err = -1; 490 err = -1;
@@ -620,145 +624,56 @@ error:
620 return ret; 624 return ret;
621} 625}
622 626
623#ifdef HAVE_DWARF_UNWIND_SUPPORT 627static void callchain_debug(void)
624static int get_stack_size(char *str, unsigned long *_size)
625{
626 char *endptr;
627 unsigned long size;
628 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
629
630 size = strtoul(str, &endptr, 0);
631
632 do {
633 if (*endptr)
634 break;
635
636 size = round_up(size, sizeof(u64));
637 if (!size || size > max_size)
638 break;
639
640 *_size = size;
641 return 0;
642
643 } while (0);
644
645 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
646 max_size, str);
647 return -1;
648}
649#endif /* HAVE_DWARF_UNWIND_SUPPORT */
650
651int record_parse_callchain(const char *arg, struct record_opts *opts)
652{
653 char *tok, *name, *saveptr = NULL;
654 char *buf;
655 int ret = -1;
656
657 /* We need buffer that we know we can write to. */
658 buf = malloc(strlen(arg) + 1);
659 if (!buf)
660 return -ENOMEM;
661
662 strcpy(buf, arg);
663
664 tok = strtok_r((char *)buf, ",", &saveptr);
665 name = tok ? : (char *)buf;
666
667 do {
668 /* Framepointer style */
669 if (!strncmp(name, "fp", sizeof("fp"))) {
670 if (!strtok_r(NULL, ",", &saveptr)) {
671 opts->call_graph = CALLCHAIN_FP;
672 ret = 0;
673 } else
674 pr_err("callchain: No more arguments "
675 "needed for -g fp\n");
676 break;
677
678#ifdef HAVE_DWARF_UNWIND_SUPPORT
679 /* Dwarf style */
680 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
681 const unsigned long default_stack_dump_size = 8192;
682
683 ret = 0;
684 opts->call_graph = CALLCHAIN_DWARF;
685 opts->stack_dump_size = default_stack_dump_size;
686
687 tok = strtok_r(NULL, ",", &saveptr);
688 if (tok) {
689 unsigned long size = 0;
690
691 ret = get_stack_size(tok, &size);
692 opts->stack_dump_size = size;
693 }
694#endif /* HAVE_DWARF_UNWIND_SUPPORT */
695 } else {
696 pr_err("callchain: Unknown --call-graph option "
697 "value: %s\n", arg);
698 break;
699 }
700
701 } while (0);
702
703 free(buf);
704 return ret;
705}
706
707static void callchain_debug(struct record_opts *opts)
708{ 628{
709 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; 629 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
710 630
711 pr_debug("callchain: type %s\n", str[opts->call_graph]); 631 pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
712 632
713 if (opts->call_graph == CALLCHAIN_DWARF) 633 if (callchain_param.record_mode == CALLCHAIN_DWARF)
714 pr_debug("callchain: stack dump size %d\n", 634 pr_debug("callchain: stack dump size %d\n",
715 opts->stack_dump_size); 635 callchain_param.dump_size);
716} 636}
717 637
718int record_parse_callchain_opt(const struct option *opt, 638int record_parse_callchain_opt(const struct option *opt __maybe_unused,
719 const char *arg, 639 const char *arg,
720 int unset) 640 int unset)
721{ 641{
722 struct record_opts *opts = opt->value;
723 int ret; 642 int ret;
724 643
725 opts->call_graph_enabled = !unset; 644 callchain_param.enabled = !unset;
726 645
727 /* --no-call-graph */ 646 /* --no-call-graph */
728 if (unset) { 647 if (unset) {
729 opts->call_graph = CALLCHAIN_NONE; 648 callchain_param.record_mode = CALLCHAIN_NONE;
730 pr_debug("callchain: disabled\n"); 649 pr_debug("callchain: disabled\n");
731 return 0; 650 return 0;
732 } 651 }
733 652
734 ret = record_parse_callchain(arg, opts); 653 ret = parse_callchain_record_opt(arg);
735 if (!ret) 654 if (!ret)
736 callchain_debug(opts); 655 callchain_debug();
737 656
738 return ret; 657 return ret;
739} 658}
740 659
741int record_callchain_opt(const struct option *opt, 660int record_callchain_opt(const struct option *opt __maybe_unused,
742 const char *arg __maybe_unused, 661 const char *arg __maybe_unused,
743 int unset __maybe_unused) 662 int unset __maybe_unused)
744{ 663{
745 struct record_opts *opts = opt->value; 664 callchain_param.enabled = true;
746 665
747 opts->call_graph_enabled = !unset; 666 if (callchain_param.record_mode == CALLCHAIN_NONE)
667 callchain_param.record_mode = CALLCHAIN_FP;
748 668
749 if (opts->call_graph == CALLCHAIN_NONE) 669 callchain_debug();
750 opts->call_graph = CALLCHAIN_FP;
751
752 callchain_debug(opts);
753 return 0; 670 return 0;
754} 671}
755 672
756static int perf_record_config(const char *var, const char *value, void *cb) 673static int perf_record_config(const char *var, const char *value, void *cb)
757{ 674{
758 struct record *rec = cb;
759
760 if (!strcmp(var, "record.call-graph")) 675 if (!strcmp(var, "record.call-graph"))
761 return record_parse_callchain(value, &rec->opts); 676 var = "call-graph.record-mode"; /* fall-through */
762 677
763 return perf_default_config(var, value, cb); 678 return perf_default_config(var, value, cb);
764} 679}
@@ -781,6 +696,7 @@ static const char * const record_usage[] = {
781 */ 696 */
782static struct record record = { 697static struct record record = {
783 .opts = { 698 .opts = {
699 .sample_time = true,
784 .mmap_pages = UINT_MAX, 700 .mmap_pages = UINT_MAX,
785 .user_freq = UINT_MAX, 701 .user_freq = UINT_MAX,
786 .user_interval = ULLONG_MAX, 702 .user_interval = ULLONG_MAX,
@@ -907,7 +823,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
907 usage_with_options(record_usage, record_options); 823 usage_with_options(record_usage, record_options);
908 } 824 }
909 825
910 symbol__init(); 826 symbol__init(NULL);
911 827
912 if (symbol_conf.kptr_restrict) 828 if (symbol_conf.kptr_restrict)
913 pr_warning( 829 pr_warning(