aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-09-27 03:15:48 -0400
committerIngo Molnar <mingo@kernel.org>2014-09-27 03:15:48 -0400
commit07394b5f13a04f86b27e0ddd96a36c7d9bfe1a4f (patch)
tree684f1103022db370242cc21199ca3cd5985eaac1
parentcf8102f64c8d23f0bd4af0659bbd94d0c1d8d1c7 (diff)
parent49757c9cc7887bc79f742eb8aacf16e464ca5f0b (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: o Restore "--callchain graph" output, broken in recent cset to end up being the same as "fractal" (Namhyung Kim) o Allow profiling when kptr_restrict == 1 for non root users, kernel samples will just remain unresolved (Andi Kleen) o Allow configuring default options for callchains in config file (Namhyung Kim) o Fix line number in the config file error message (Jiri Olsa) o Fix --per-core on multi socket systems (Andi Kleen) Cleanups: o Use ACCESS_ONCE() instead of volatile cast. (Pranith Kumar) o Modify error code for when perf_session__new() fails (Taeung Song) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-evlist.c2
-rw-r--r--tools/perf/builtin-inject.c2
-rw-r--r--tools/perf/builtin-kmem.c2
-rw-r--r--tools/perf/builtin-kvm.c4
-rw-r--r--tools/perf/builtin-lock.c2
-rw-r--r--tools/perf/builtin-mem.c2
-rw-r--r--tools/perf/builtin-record.c119
-rw-r--r--tools/perf/builtin-report.c2
-rw-r--r--tools/perf/builtin-script.c2
-rw-r--r--tools/perf/builtin-stat.c9
-rw-r--r--tools/perf/builtin-timechart.c2
-rw-r--r--tools/perf/builtin-top.c6
-rw-r--r--tools/perf/builtin-trace.c2
-rw-r--r--tools/perf/perf.h3
-rw-r--r--tools/perf/ui/browsers/hists.c3
-rw-r--r--tools/perf/util/callchain.c193
-rw-r--r--tools/perf/util/callchain.h6
-rw-r--r--tools/perf/util/config.c16
-rw-r--r--tools/perf/util/event.c8
-rw-r--r--tools/perf/util/evsel.c11
-rw-r--r--tools/perf/util/session.c2
-rw-r--r--tools/perf/util/session.h2
24 files changed, 241 insertions, 163 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index d4da6929597f..be5939418425 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -340,7 +340,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
340 340
341 annotate.session = perf_session__new(&file, false, &annotate.tool); 341 annotate.session = perf_session__new(&file, false, &annotate.tool);
342 if (annotate.session == NULL) 342 if (annotate.session == NULL)
343 return -ENOMEM; 343 return -1;
344 344
345 symbol_conf.priv_size = sizeof(struct annotation); 345 symbol_conf.priv_size = sizeof(struct annotation);
346 symbol_conf.try_vmlinux_path = true; 346 symbol_conf.try_vmlinux_path = true;
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 190d0b6b28cc..a3ce19f7aebd 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -683,7 +683,7 @@ static int __cmd_diff(void)
683 d->session = perf_session__new(&d->file, false, &tool); 683 d->session = perf_session__new(&d->file, false, &tool);
684 if (!d->session) { 684 if (!d->session) {
685 pr_err("Failed to open %s\n", d->file.path); 685 pr_err("Failed to open %s\n", d->file.path);
686 ret = -ENOMEM; 686 ret = -1;
687 goto out_delete; 687 goto out_delete;
688 } 688 }
689 689
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 66e12f55c052..0f93f859b782 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -28,7 +28,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
28 28
29 session = perf_session__new(&file, 0, NULL); 29 session = perf_session__new(&file, 0, NULL);
30 if (session == NULL) 30 if (session == NULL)
31 return -ENOMEM; 31 return -1;
32 32
33 evlist__for_each(session->evlist, pos) 33 evlist__for_each(session->evlist, pos)
34 perf_evsel__fprintf(pos, details, stdout); 34 perf_evsel__fprintf(pos, details, stdout);
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 3a62b6b3c8fd..de99ca1bb942 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -460,7 +460,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
460 file.path = inject.input_name; 460 file.path = inject.input_name;
461 inject.session = perf_session__new(&file, true, &inject.tool); 461 inject.session = perf_session__new(&file, true, &inject.tool);
462 if (inject.session == NULL) 462 if (inject.session == NULL)
463 return -ENOMEM; 463 return -1;
464 464
465 if (symbol__init(&inject.session->header.env) < 0) 465 if (symbol__init(&inject.session->header.env) < 0)
466 return -1; 466 return -1;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 23762187a219..f295141025bc 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -698,7 +698,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
698 698
699 session = perf_session__new(&file, false, &perf_kmem); 699 session = perf_session__new(&file, false, &perf_kmem);
700 if (session == NULL) 700 if (session == NULL)
701 return -ENOMEM; 701 return -1;
702 702
703 symbol__init(&session->header.env); 703 symbol__init(&session->header.env);
704 704
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 1e639d6265cc..d8bf2271f4ea 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1058,7 +1058,7 @@ static int read_events(struct perf_kvm_stat *kvm)
1058 kvm->session = perf_session__new(&file, false, &kvm->tool); 1058 kvm->session = perf_session__new(&file, false, &kvm->tool);
1059 if (!kvm->session) { 1059 if (!kvm->session) {
1060 pr_err("Initializing perf session failed\n"); 1060 pr_err("Initializing perf session failed\n");
1061 return -EINVAL; 1061 return -1;
1062 } 1062 }
1063 1063
1064 symbol__init(&kvm->session->header.env); 1064 symbol__init(&kvm->session->header.env);
@@ -1361,7 +1361,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1361 */ 1361 */
1362 kvm->session = perf_session__new(&file, false, &kvm->tool); 1362 kvm->session = perf_session__new(&file, false, &kvm->tool);
1363 if (kvm->session == NULL) { 1363 if (kvm->session == NULL) {
1364 err = -ENOMEM; 1364 err = -1;
1365 goto out; 1365 goto out;
1366 } 1366 }
1367 kvm->session->evlist = kvm->evlist; 1367 kvm->session->evlist = kvm->evlist;
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 92790ed7af45..e7ec71589da6 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -862,7 +862,7 @@ static int __cmd_report(bool display_info)
862 session = perf_session__new(&file, false, &eops); 862 session = perf_session__new(&file, false, &eops);
863 if (!session) { 863 if (!session) {
864 pr_err("Initializing perf session failed\n"); 864 pr_err("Initializing perf session failed\n");
865 return -ENOMEM; 865 return -1;
866 } 866 }
867 867
868 symbol__init(&session->header.env); 868 symbol__init(&session->header.env);
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 8b4a87fe3858..24db6ffe2957 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -124,7 +124,7 @@ static int report_raw_events(struct perf_mem *mem)
124 &mem->tool); 124 &mem->tool);
125 125
126 if (session == NULL) 126 if (session == NULL)
127 return -ENOMEM; 127 return -1;
128 128
129 if (mem->cpu_list) { 129 if (mem->cpu_list) {
130 ret = perf_session__cpu_bitmap(session, mem->cpu_list, 130 ret = perf_session__cpu_bitmap(session, mem->cpu_list,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 320b198b54dd..44c6f3d55ce7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -624,145 +624,56 @@ error:
624 return ret; 624 return ret;
625} 625}
626 626
627#ifdef HAVE_DWARF_UNWIND_SUPPORT 627static void callchain_debug(void)
628static int get_stack_size(char *str, unsigned long *_size)
629{
630 char *endptr;
631 unsigned long size;
632 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
633
634 size = strtoul(str, &endptr, 0);
635
636 do {
637 if (*endptr)
638 break;
639
640 size = round_up(size, sizeof(u64));
641 if (!size || size > max_size)
642 break;
643
644 *_size = size;
645 return 0;
646
647 } while (0);
648
649 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
650 max_size, str);
651 return -1;
652}
653#endif /* HAVE_DWARF_UNWIND_SUPPORT */
654
655int record_parse_callchain(const char *arg, struct record_opts *opts)
656{
657 char *tok, *name, *saveptr = NULL;
658 char *buf;
659 int ret = -1;
660
661 /* We need buffer that we know we can write to. */
662 buf = malloc(strlen(arg) + 1);
663 if (!buf)
664 return -ENOMEM;
665
666 strcpy(buf, arg);
667
668 tok = strtok_r((char *)buf, ",", &saveptr);
669 name = tok ? : (char *)buf;
670
671 do {
672 /* Framepointer style */
673 if (!strncmp(name, "fp", sizeof("fp"))) {
674 if (!strtok_r(NULL, ",", &saveptr)) {
675 opts->call_graph = CALLCHAIN_FP;
676 ret = 0;
677 } else
678 pr_err("callchain: No more arguments "
679 "needed for -g fp\n");
680 break;
681
682#ifdef HAVE_DWARF_UNWIND_SUPPORT
683 /* Dwarf style */
684 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
685 const unsigned long default_stack_dump_size = 8192;
686
687 ret = 0;
688 opts->call_graph = CALLCHAIN_DWARF;
689 opts->stack_dump_size = default_stack_dump_size;
690
691 tok = strtok_r(NULL, ",", &saveptr);
692 if (tok) {
693 unsigned long size = 0;
694
695 ret = get_stack_size(tok, &size);
696 opts->stack_dump_size = size;
697 }
698#endif /* HAVE_DWARF_UNWIND_SUPPORT */
699 } else {
700 pr_err("callchain: Unknown --call-graph option "
701 "value: %s\n", arg);
702 break;
703 }
704
705 } while (0);
706
707 free(buf);
708 return ret;
709}
710
711static void callchain_debug(struct record_opts *opts)
712{ 628{
713 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; 629 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
714 630
715 pr_debug("callchain: type %s\n", str[opts->call_graph]); 631 pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
716 632
717 if (opts->call_graph == CALLCHAIN_DWARF) 633 if (callchain_param.record_mode == CALLCHAIN_DWARF)
718 pr_debug("callchain: stack dump size %d\n", 634 pr_debug("callchain: stack dump size %d\n",
719 opts->stack_dump_size); 635 callchain_param.dump_size);
720} 636}
721 637
722int record_parse_callchain_opt(const struct option *opt, 638int record_parse_callchain_opt(const struct option *opt __maybe_unused,
723 const char *arg, 639 const char *arg,
724 int unset) 640 int unset)
725{ 641{
726 struct record_opts *opts = opt->value;
727 int ret; 642 int ret;
728 643
729 opts->call_graph_enabled = !unset; 644 callchain_param.enabled = !unset;
730 645
731 /* --no-call-graph */ 646 /* --no-call-graph */
732 if (unset) { 647 if (unset) {
733 opts->call_graph = CALLCHAIN_NONE; 648 callchain_param.record_mode = CALLCHAIN_NONE;
734 pr_debug("callchain: disabled\n"); 649 pr_debug("callchain: disabled\n");
735 return 0; 650 return 0;
736 } 651 }
737 652
738 ret = record_parse_callchain(arg, opts); 653 ret = parse_callchain_record_opt(arg);
739 if (!ret) 654 if (!ret)
740 callchain_debug(opts); 655 callchain_debug();
741 656
742 return ret; 657 return ret;
743} 658}
744 659
745int record_callchain_opt(const struct option *opt, 660int record_callchain_opt(const struct option *opt __maybe_unused,
746 const char *arg __maybe_unused, 661 const char *arg __maybe_unused,
747 int unset __maybe_unused) 662 int unset __maybe_unused)
748{ 663{
749 struct record_opts *opts = opt->value; 664 callchain_param.enabled = true;
750 665
751 opts->call_graph_enabled = !unset; 666 if (callchain_param.record_mode == CALLCHAIN_NONE)
667 callchain_param.record_mode = CALLCHAIN_FP;
752 668
753 if (opts->call_graph == CALLCHAIN_NONE) 669 callchain_debug();
754 opts->call_graph = CALLCHAIN_FP;
755
756 callchain_debug(opts);
757 return 0; 670 return 0;
758} 671}
759 672
760static 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)
761{ 674{
762 struct record *rec = cb;
763
764 if (!strcmp(var, "record.call-graph")) 675 if (!strcmp(var, "record.call-graph"))
765 return record_parse_callchain(value, &rec->opts); 676 var = "call-graph.record-mode"; /* fall-through */
766 677
767 return perf_default_config(var, value, cb); 678 return perf_default_config(var, value, cb);
768} 679}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8c0b3f22412a..ac145fae0521 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -720,7 +720,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
720repeat: 720repeat:
721 session = perf_session__new(&file, false, &report.tool); 721 session = perf_session__new(&file, false, &report.tool);
722 if (session == NULL) 722 if (session == NULL)
723 return -ENOMEM; 723 return -1;
724 724
725 if (report.queue_size) { 725 if (report.queue_size) {
726 ordered_events__set_alloc_size(&session->ordered_events, 726 ordered_events__set_alloc_size(&session->ordered_events,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 02dce9295e2c..b9b9e58a6c39 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1744,7 +1744,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1744 1744
1745 session = perf_session__new(&file, false, &script.tool); 1745 session = perf_session__new(&file, false, &script.tool);
1746 if (session == NULL) 1746 if (session == NULL)
1747 return -ENOMEM; 1747 return -1;
1748 1748
1749 if (header || header_only) { 1749 if (header || header_only) {
1750 perf_session__fprintf_info(session, stdout, show_full_info); 1750 perf_session__fprintf_info(session, stdout, show_full_info);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 5fe0edb1de5d..b22c62f80078 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -732,7 +732,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
732 } 732 }
733} 733}
734 734
735static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 735static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
736{ 736{
737 double msecs = avg / 1e6; 737 double msecs = avg / 1e6;
738 const char *fmt_v, *fmt_n; 738 const char *fmt_v, *fmt_n;
@@ -741,7 +741,7 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
741 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; 741 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s";
742 fmt_n = csv_output ? "%s" : "%-25s"; 742 fmt_n = csv_output ? "%s" : "%-25s";
743 743
744 aggr_printout(evsel, cpu, nr); 744 aggr_printout(evsel, id, nr);
745 745
746 scnprintf(name, sizeof(name), "%s%s", 746 scnprintf(name, sizeof(name), "%s%s",
747 perf_evsel__name(evsel), csv_output ? "" : " (msec)"); 747 perf_evsel__name(evsel), csv_output ? "" : " (msec)");
@@ -947,11 +947,12 @@ static void print_ll_cache_misses(int cpu,
947 fprintf(output, " of all LL-cache hits "); 947 fprintf(output, " of all LL-cache hits ");
948} 948}
949 949
950static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 950static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
951{ 951{
952 double total, ratio = 0.0, total2; 952 double total, ratio = 0.0, total2;
953 double sc = evsel->scale; 953 double sc = evsel->scale;
954 const char *fmt; 954 const char *fmt;
955 int cpu = cpu_map__id_to_cpu(id);
955 956
956 if (csv_output) { 957 if (csv_output) {
957 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; 958 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s";
@@ -962,7 +963,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
962 fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; 963 fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s";
963 } 964 }
964 965
965 aggr_printout(evsel, cpu, nr); 966 aggr_printout(evsel, id, nr);
966 967
967 if (aggr_mode == AGGR_GLOBAL) 968 if (aggr_mode == AGGR_GLOBAL)
968 cpu = 0; 969 cpu = 0;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 48eea6cd2f5b..35b425b6293f 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1605,7 +1605,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
1605 int ret = -EINVAL; 1605 int ret = -EINVAL;
1606 1606
1607 if (session == NULL) 1607 if (session == NULL)
1608 return -ENOMEM; 1608 return -1;
1609 1609
1610 symbol__init(&session->header.env); 1610 symbol__init(&session->header.env);
1611 1611
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 832fb527ed90..fc3d55f832ac 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -929,7 +929,7 @@ static int __cmd_top(struct perf_top *top)
929 929
930 top->session = perf_session__new(NULL, false, NULL); 930 top->session = perf_session__new(NULL, false, NULL);
931 if (top->session == NULL) 931 if (top->session == NULL)
932 return -ENOMEM; 932 return -1;
933 933
934 machines__set_symbol_filter(&top->session->machines, symbol_filter); 934 machines__set_symbol_filter(&top->session->machines, symbol_filter);
935 935
@@ -1020,10 +1020,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1020 1020
1021static int perf_top_config(const char *var, const char *value, void *cb) 1021static int perf_top_config(const char *var, const char *value, void *cb)
1022{ 1022{
1023 struct perf_top *top = cb;
1024
1025 if (!strcmp(var, "top.call-graph")) 1023 if (!strcmp(var, "top.call-graph"))
1026 return record_parse_callchain(value, &top->record_opts); 1024 var = "call-graph.record-mode"; /* fall-through */
1027 if (!strcmp(var, "top.children")) { 1025 if (!strcmp(var, "top.children")) {
1028 symbol_conf.cumulate_callchain = perf_config_bool(var, value); 1026 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
1029 return 0; 1027 return 0;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index fe39dc620179..c70e69ea1c5d 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -2250,7 +2250,7 @@ static int trace__replay(struct trace *trace)
2250 2250
2251 session = perf_session__new(&file, false, &trace->tool); 2251 session = perf_session__new(&file, false, &trace->tool);
2252 if (session == NULL) 2252 if (session == NULL)
2253 return -ENOMEM; 2253 return -1;
2254 2254
2255 if (symbol__init(&session->header.env) < 0) 2255 if (symbol__init(&session->header.env) < 0)
2256 goto out; 2256 goto out;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 510c65f72858..220d44e44c1b 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -41,8 +41,6 @@ void pthread__unblock_sigwinch(void);
41 41
42struct record_opts { 42struct record_opts {
43 struct target target; 43 struct target target;
44 int call_graph;
45 bool call_graph_enabled;
46 bool group; 44 bool group;
47 bool inherit_stat; 45 bool inherit_stat;
48 bool no_buffering; 46 bool no_buffering;
@@ -60,7 +58,6 @@ struct record_opts {
60 u64 branch_stack; 58 u64 branch_stack;
61 u64 default_interval; 59 u64 default_interval;
62 u64 user_interval; 60 u64 user_interval;
63 u16 stack_dump_size;
64 bool sample_transaction; 61 bool sample_transaction;
65 unsigned initial_delay; 62 unsigned initial_delay;
66}; 63};
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index d4cef68176da..8f60a970404f 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -804,9 +804,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
804 .is_current_entry = current_entry, 804 .is_current_entry = current_entry,
805 }; 805 };
806 806
807 if (symbol_conf.cumulate_callchain)
808 total = entry->stat_acc->period;
809
810 printed += hist_browser__show_callchain(browser, 807 printed += hist_browser__show_callchain(browser,
811 &entry->sorted_chain, 1, row, total, 808 &entry->sorted_chain, 1, row, total,
812 hist_browser__show_callchain_entry, &arg, 809 hist_browser__show_callchain_entry, &arg,
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 08f0fbf5527c..c84d3f8dcb75 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -25,6 +25,133 @@
25 25
26__thread struct callchain_cursor callchain_cursor; 26__thread struct callchain_cursor callchain_cursor;
27 27
28#ifdef HAVE_DWARF_UNWIND_SUPPORT
29static int get_stack_size(const char *str, unsigned long *_size)
30{
31 char *endptr;
32 unsigned long size;
33 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
34
35 size = strtoul(str, &endptr, 0);
36
37 do {
38 if (*endptr)
39 break;
40
41 size = round_up(size, sizeof(u64));
42 if (!size || size > max_size)
43 break;
44
45 *_size = size;
46 return 0;
47
48 } while (0);
49
50 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
51 max_size, str);
52 return -1;
53}
54#endif /* HAVE_DWARF_UNWIND_SUPPORT */
55
56int parse_callchain_record_opt(const char *arg)
57{
58 char *tok, *name, *saveptr = NULL;
59 char *buf;
60 int ret = -1;
61
62 /* We need buffer that we know we can write to. */
63 buf = malloc(strlen(arg) + 1);
64 if (!buf)
65 return -ENOMEM;
66
67 strcpy(buf, arg);
68
69 tok = strtok_r((char *)buf, ",", &saveptr);
70 name = tok ? : (char *)buf;
71
72 do {
73 /* Framepointer style */
74 if (!strncmp(name, "fp", sizeof("fp"))) {
75 if (!strtok_r(NULL, ",", &saveptr)) {
76 callchain_param.record_mode = CALLCHAIN_FP;
77 ret = 0;
78 } else
79 pr_err("callchain: No more arguments "
80 "needed for -g fp\n");
81 break;
82
83#ifdef HAVE_DWARF_UNWIND_SUPPORT
84 /* Dwarf style */
85 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
86 const unsigned long default_stack_dump_size = 8192;
87
88 ret = 0;
89 callchain_param.record_mode = CALLCHAIN_DWARF;
90 callchain_param.dump_size = default_stack_dump_size;
91
92 tok = strtok_r(NULL, ",", &saveptr);
93 if (tok) {
94 unsigned long size = 0;
95
96 ret = get_stack_size(tok, &size);
97 callchain_param.dump_size = size;
98 }
99#endif /* HAVE_DWARF_UNWIND_SUPPORT */
100 } else {
101 pr_err("callchain: Unknown --call-graph option "
102 "value: %s\n", arg);
103 break;
104 }
105
106 } while (0);
107
108 free(buf);
109 return ret;
110}
111
112static int parse_callchain_mode(const char *value)
113{
114 if (!strncmp(value, "graph", strlen(value))) {
115 callchain_param.mode = CHAIN_GRAPH_ABS;
116 return 0;
117 }
118 if (!strncmp(value, "flat", strlen(value))) {
119 callchain_param.mode = CHAIN_FLAT;
120 return 0;
121 }
122 if (!strncmp(value, "fractal", strlen(value))) {
123 callchain_param.mode = CHAIN_GRAPH_REL;
124 return 0;
125 }
126 return -1;
127}
128
129static int parse_callchain_order(const char *value)
130{
131 if (!strncmp(value, "caller", strlen(value))) {
132 callchain_param.order = ORDER_CALLER;
133 return 0;
134 }
135 if (!strncmp(value, "callee", strlen(value))) {
136 callchain_param.order = ORDER_CALLEE;
137 return 0;
138 }
139 return -1;
140}
141
142static int parse_callchain_sort_key(const char *value)
143{
144 if (!strncmp(value, "function", strlen(value))) {
145 callchain_param.key = CCKEY_FUNCTION;
146 return 0;
147 }
148 if (!strncmp(value, "address", strlen(value))) {
149 callchain_param.key = CCKEY_ADDRESS;
150 return 0;
151 }
152 return -1;
153}
154
28int 155int
29parse_callchain_report_opt(const char *arg) 156parse_callchain_report_opt(const char *arg)
30{ 157{
@@ -44,25 +171,12 @@ parse_callchain_report_opt(const char *arg)
44 return 0; 171 return 0;
45 } 172 }
46 173
47 /* try to get the output mode */ 174 if (!parse_callchain_mode(tok) ||
48 if (!strncmp(tok, "graph", strlen(tok))) 175 !parse_callchain_order(tok) ||
49 callchain_param.mode = CHAIN_GRAPH_ABS; 176 !parse_callchain_sort_key(tok)) {
50 else if (!strncmp(tok, "flat", strlen(tok))) 177 /* parsing ok - move on to the next */
51 callchain_param.mode = CHAIN_FLAT; 178 } else if (!minpcnt_set) {
52 else if (!strncmp(tok, "fractal", strlen(tok))) 179 /* try to get the min percent */
53 callchain_param.mode = CHAIN_GRAPH_REL;
54 /* try to get the call chain order */
55 else if (!strncmp(tok, "caller", strlen(tok)))
56 callchain_param.order = ORDER_CALLER;
57 else if (!strncmp(tok, "callee", strlen(tok)))
58 callchain_param.order = ORDER_CALLEE;
59 /* try to get the sort key */
60 else if (!strncmp(tok, "function", strlen(tok)))
61 callchain_param.key = CCKEY_FUNCTION;
62 else if (!strncmp(tok, "address", strlen(tok)))
63 callchain_param.key = CCKEY_ADDRESS;
64 /* try to get the min percent */
65 else if (!minpcnt_set) {
66 callchain_param.min_percent = strtod(tok, &endptr); 180 callchain_param.min_percent = strtod(tok, &endptr);
67 if (tok == endptr) 181 if (tok == endptr)
68 return -1; 182 return -1;
@@ -84,6 +198,47 @@ parse_callchain_report_opt(const char *arg)
84 return 0; 198 return 0;
85} 199}
86 200
201int perf_callchain_config(const char *var, const char *value)
202{
203 char *endptr;
204
205 if (prefixcmp(var, "call-graph."))
206 return 0;
207 var += sizeof("call-graph.") - 1;
208
209 if (!strcmp(var, "record-mode"))
210 return parse_callchain_record_opt(value);
211#ifdef HAVE_DWARF_UNWIND_SUPPORT
212 if (!strcmp(var, "dump-size")) {
213 unsigned long size = 0;
214 int ret;
215
216 ret = get_stack_size(value, &size);
217 callchain_param.dump_size = size;
218
219 return ret;
220 }
221#endif
222 if (!strcmp(var, "print-type"))
223 return parse_callchain_mode(value);
224 if (!strcmp(var, "order"))
225 return parse_callchain_order(value);
226 if (!strcmp(var, "sort-key"))
227 return parse_callchain_sort_key(value);
228 if (!strcmp(var, "threshold")) {
229 callchain_param.min_percent = strtod(value, &endptr);
230 if (value == endptr)
231 return -1;
232 }
233 if (!strcmp(var, "print-limit")) {
234 callchain_param.print_limit = strtod(value, &endptr);
235 if (value == endptr)
236 return -1;
237 }
238
239 return 0;
240}
241
87static void 242static void
88rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 243rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
89 enum chain_mode mode) 244 enum chain_mode mode)
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index da43619d6173..2a1f5a46543a 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -54,6 +54,9 @@ enum chain_key {
54}; 54};
55 55
56struct callchain_param { 56struct callchain_param {
57 bool enabled;
58 enum perf_call_graph_mode record_mode;
59 u32 dump_size;
57 enum chain_mode mode; 60 enum chain_mode mode;
58 u32 print_limit; 61 u32 print_limit;
59 double min_percent; 62 double min_percent;
@@ -154,7 +157,6 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
154struct option; 157struct option;
155struct hist_entry; 158struct hist_entry;
156 159
157int record_parse_callchain(const char *arg, struct record_opts *opts);
158int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); 160int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
159int record_callchain_opt(const struct option *opt, const char *arg, int unset); 161int record_callchain_opt(const struct option *opt, const char *arg, int unset);
160 162
@@ -166,7 +168,9 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
166 bool hide_unresolved); 168 bool hide_unresolved);
167 169
168extern const char record_callchain_help[]; 170extern const char record_callchain_help[];
171int parse_callchain_record_opt(const char *arg);
169int parse_callchain_report_opt(const char *arg); 172int parse_callchain_report_opt(const char *arg);
173int perf_callchain_config(const char *var, const char *value);
170 174
171static inline void callchain_cursor_snapshot(struct callchain_cursor *dest, 175static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
172 struct callchain_cursor *src) 176 struct callchain_cursor *src)
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 9970b8b0190b..57ff826f150b 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -222,7 +222,8 @@ static int perf_parse_file(config_fn_t fn, void *data)
222 const unsigned char *bomptr = utf8_bom; 222 const unsigned char *bomptr = utf8_bom;
223 223
224 for (;;) { 224 for (;;) {
225 int c = get_next_char(); 225 int line, c = get_next_char();
226
226 if (bomptr && *bomptr) { 227 if (bomptr && *bomptr) {
227 /* We are at the file beginning; skip UTF8-encoded BOM 228 /* We are at the file beginning; skip UTF8-encoded BOM
228 * if present. Sane editors won't put this in on their 229 * if present. Sane editors won't put this in on their
@@ -261,8 +262,16 @@ static int perf_parse_file(config_fn_t fn, void *data)
261 if (!isalpha(c)) 262 if (!isalpha(c))
262 break; 263 break;
263 var[baselen] = tolower(c); 264 var[baselen] = tolower(c);
264 if (get_value(fn, data, var, baselen+1) < 0) 265
266 /*
267 * The get_value function might or might not reach the '\n',
268 * so saving the current line number for error reporting.
269 */
270 line = config_linenr;
271 if (get_value(fn, data, var, baselen+1) < 0) {
272 config_linenr = line;
265 break; 273 break;
274 }
266 } 275 }
267 die("bad config file line %d in %s", config_linenr, config_file_name); 276 die("bad config file line %d in %s", config_linenr, config_file_name);
268} 277}
@@ -396,6 +405,9 @@ int perf_default_config(const char *var, const char *value,
396 if (!prefixcmp(var, "ui.")) 405 if (!prefixcmp(var, "ui."))
397 return perf_ui_config(var, value); 406 return perf_ui_config(var, value);
398 407
408 if (!prefixcmp(var, "call-graph."))
409 return perf_callchain_config(var, value);
410
399 /* Add other config variables here. */ 411 /* Add other config variables here. */
400 return 0; 412 return 0;
401} 413}
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index ed558191c0b3..4af6b279e34a 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -558,13 +558,17 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
558 struct map *map; 558 struct map *map;
559 struct kmap *kmap; 559 struct kmap *kmap;
560 int err; 560 int err;
561 union perf_event *event;
562
563 if (machine->vmlinux_maps[0] == NULL)
564 return -1;
565
561 /* 566 /*
562 * We should get this from /sys/kernel/sections/.text, but till that is 567 * We should get this from /sys/kernel/sections/.text, but till that is
563 * available use this, and after it is use this as a fallback for older 568 * available use this, and after it is use this as a fallback for older
564 * kernels. 569 * kernels.
565 */ 570 */
566 union perf_event *event = zalloc((sizeof(event->mmap) + 571 event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
567 machine->id_hdr_size));
568 if (event == NULL) { 572 if (event == NULL) {
569 pr_debug("Not enough memory synthesizing mmap event " 573 pr_debug("Not enough memory synthesizing mmap event "
570 "for kernel modules\n"); 574 "for kernel modules\n");
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index b38de5819323..e0868a901c4a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -503,20 +503,19 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
503} 503}
504 504
505static void 505static void
506perf_evsel__config_callgraph(struct perf_evsel *evsel, 506perf_evsel__config_callgraph(struct perf_evsel *evsel)
507 struct record_opts *opts)
508{ 507{
509 bool function = perf_evsel__is_function_event(evsel); 508 bool function = perf_evsel__is_function_event(evsel);
510 struct perf_event_attr *attr = &evsel->attr; 509 struct perf_event_attr *attr = &evsel->attr;
511 510
512 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 511 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
513 512
514 if (opts->call_graph == CALLCHAIN_DWARF) { 513 if (callchain_param.record_mode == CALLCHAIN_DWARF) {
515 if (!function) { 514 if (!function) {
516 perf_evsel__set_sample_bit(evsel, REGS_USER); 515 perf_evsel__set_sample_bit(evsel, REGS_USER);
517 perf_evsel__set_sample_bit(evsel, STACK_USER); 516 perf_evsel__set_sample_bit(evsel, STACK_USER);
518 attr->sample_regs_user = PERF_REGS_MASK; 517 attr->sample_regs_user = PERF_REGS_MASK;
519 attr->sample_stack_user = opts->stack_dump_size; 518 attr->sample_stack_user = callchain_param.dump_size;
520 attr->exclude_callchain_user = 1; 519 attr->exclude_callchain_user = 1;
521 } else { 520 } else {
522 pr_info("Cannot use DWARF unwind for function trace event," 521 pr_info("Cannot use DWARF unwind for function trace event,"
@@ -625,8 +624,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
625 attr->mmap_data = track; 624 attr->mmap_data = track;
626 } 625 }
627 626
628 if (opts->call_graph_enabled && !evsel->no_aux_samples) 627 if (callchain_param.enabled && !evsel->no_aux_samples)
629 perf_evsel__config_callgraph(evsel, opts); 628 perf_evsel__config_callgraph(evsel);
630 629
631 if (target__has_cpu(&opts->target)) 630 if (target__has_cpu(&opts->target))
632 perf_evsel__set_sample_bit(evsel, CPU); 631 perf_evsel__set_sample_bit(evsel, CPU);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 6d2d50dea1d8..883406f4b381 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -119,7 +119,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
119 * kernel MMAP event, in perf_event__process_mmap(). 119 * kernel MMAP event, in perf_event__process_mmap().
120 */ 120 */
121 if (perf_session__create_kernel_maps(session) < 0) 121 if (perf_session__create_kernel_maps(session) < 0)
122 goto out_delete; 122 pr_warning("Cannot read kernel map\n");
123 } 123 }
124 124
125 if (tool && tool->ordering_requires_timestamps && 125 if (tool && tool->ordering_requires_timestamps &&
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 8dd41cad2d59..ffb440462008 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -126,5 +126,5 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
126 126
127extern volatile int session_done; 127extern volatile int session_done;
128 128
129#define session_done() (*(volatile int *)(&session_done)) 129#define session_done() ACCESS_ONCE(session_done)
130#endif /* __PERF_SESSION_H */ 130#endif /* __PERF_SESSION_H */