aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-10-05 18:30:22 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-10-07 15:59:59 -0400
commit19d4ac3c1039fb952f4c073fd0898e9295a836c8 (patch)
tree56acd6c60a518297713a5392acd8813cf4ef768a /tools/perf/builtin-top.c
parentab81f3fd350c510730adb1ca40ef55c2b2952121 (diff)
perf top: Add callgraph support
Just like in 'perf report', but live. Still needs to decay the callchains, but already somewhat useful as-is. Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-cj3rmaf5jpsvi3v0tf7t4uvp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r--tools/perf/builtin-top.c146
1 files changed, 144 insertions, 2 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 2cf5e50a6997..b9b7fe085895 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -76,6 +76,12 @@ static bool system_wide = false;
76 76
77static bool use_tui, use_stdio; 77static bool use_tui, use_stdio;
78 78
79static bool sort_has_symbols;
80
81static bool dont_use_callchains;
82static char callchain_default_opt[] = "fractal,0.5,callee";
83
84
79static int default_interval = 0; 85static int default_interval = 0;
80 86
81static bool kptr_restrict_warned; 87static bool kptr_restrict_warned;
@@ -648,9 +654,11 @@ static void perf_event__process_sample(const union perf_event *event,
648 struct perf_sample *sample, 654 struct perf_sample *sample,
649 struct perf_session *session) 655 struct perf_session *session)
650{ 656{
657 struct symbol *parent = NULL;
651 u64 ip = event->ip.ip; 658 u64 ip = event->ip.ip;
652 struct addr_location al; 659 struct addr_location al;
653 struct machine *machine; 660 struct machine *machine;
661 int err;
654 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 662 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
655 663
656 ++top.samples; 664 ++top.samples;
@@ -748,13 +756,29 @@ static void perf_event__process_sample(const union perf_event *event,
748 evsel = perf_evlist__id2evsel(top.evlist, sample->id); 756 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
749 assert(evsel != NULL); 757 assert(evsel != NULL);
750 758
759 if ((sort__has_parent || symbol_conf.use_callchain) &&
760 sample->callchain) {
761 err = perf_session__resolve_callchain(session, al.thread,
762 sample->callchain, &parent);
763 if (err)
764 return;
765 }
766
751 he = perf_session__add_hist_entry(session, &al, sample, evsel); 767 he = perf_session__add_hist_entry(session, &al, sample, evsel);
752 if (he == NULL) { 768 if (he == NULL) {
753 pr_err("Problem incrementing symbol period, skipping event\n"); 769 pr_err("Problem incrementing symbol period, skipping event\n");
754 return; 770 return;
755 } 771 }
756 772
757 record_precise_ip(he, evsel->idx, ip); 773 if (symbol_conf.use_callchain) {
774 err = callchain_append(he->callchain, &session->callchain_cursor,
775 sample->period);
776 if (err)
777 return;
778 }
779
780 if (sort_has_symbols)
781 record_precise_ip(he, evsel->idx, ip);
758 } 782 }
759 783
760 return; 784 return;
@@ -808,6 +832,9 @@ static void start_counters(struct perf_evlist *evlist)
808 attr->read_format |= PERF_FORMAT_ID; 832 attr->read_format |= PERF_FORMAT_ID;
809 } 833 }
810 834
835 if (symbol_conf.use_callchain)
836 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
837
811 attr->mmap = 1; 838 attr->mmap = 1;
812 attr->comm = 1; 839 attr->comm = 1;
813 attr->inherit = inherit; 840 attr->inherit = inherit;
@@ -864,10 +891,27 @@ out_err:
864 exit(0); 891 exit(0);
865} 892}
866 893
894static int setup_sample_type(void)
895{
896 if (!sort_has_symbols) {
897 if (symbol_conf.use_callchain) {
898 ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
899 return -EINVAL;
900 }
901 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
902 if (callchain_register_param(&callchain_param) < 0) {
903 ui__warning("Can't register callchain params.\n");
904 return -EINVAL;
905 }
906 }
907
908 return 0;
909}
910
867static int __cmd_top(void) 911static int __cmd_top(void)
868{ 912{
869 pthread_t thread; 913 pthread_t thread;
870 int ret __used; 914 int ret;
871 /* 915 /*
872 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 916 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
873 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 917 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -876,6 +920,10 @@ static int __cmd_top(void)
876 if (top.session == NULL) 920 if (top.session == NULL)
877 return -ENOMEM; 921 return -ENOMEM;
878 922
923 ret = setup_sample_type();
924 if (ret)
925 goto out_delete;
926
879 if (top.target_tid != -1) 927 if (top.target_tid != -1)
880 perf_event__synthesize_thread_map(top.evlist->threads, 928 perf_event__synthesize_thread_map(top.evlist->threads,
881 perf_event__process, top.session); 929 perf_event__process, top.session);
@@ -916,6 +964,90 @@ static int __cmd_top(void)
916 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 964 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
917 } 965 }
918 966
967out_delete:
968 perf_session__delete(top.session);
969 top.session = NULL;
970
971 return 0;
972}
973
974static int
975parse_callchain_opt(const struct option *opt __used, const char *arg,
976 int unset)
977{
978 char *tok, *tok2;
979 char *endptr;
980
981 /*
982 * --no-call-graph
983 */
984 if (unset) {
985 dont_use_callchains = true;
986 return 0;
987 }
988
989 symbol_conf.use_callchain = true;
990
991 if (!arg)
992 return 0;
993
994 tok = strtok((char *)arg, ",");
995 if (!tok)
996 return -1;
997
998 /* get the output mode */
999 if (!strncmp(tok, "graph", strlen(arg)))
1000 callchain_param.mode = CHAIN_GRAPH_ABS;
1001
1002 else if (!strncmp(tok, "flat", strlen(arg)))
1003 callchain_param.mode = CHAIN_FLAT;
1004
1005 else if (!strncmp(tok, "fractal", strlen(arg)))
1006 callchain_param.mode = CHAIN_GRAPH_REL;
1007
1008 else if (!strncmp(tok, "none", strlen(arg))) {
1009 callchain_param.mode = CHAIN_NONE;
1010 symbol_conf.use_callchain = false;
1011
1012 return 0;
1013 }
1014
1015 else
1016 return -1;
1017
1018 /* get the min percentage */
1019 tok = strtok(NULL, ",");
1020 if (!tok)
1021 goto setup;
1022
1023 callchain_param.min_percent = strtod(tok, &endptr);
1024 if (tok == endptr)
1025 return -1;
1026
1027 /* get the print limit */
1028 tok2 = strtok(NULL, ",");
1029 if (!tok2)
1030 goto setup;
1031
1032 if (tok2[0] != 'c') {
1033 callchain_param.print_limit = strtod(tok2, &endptr);
1034 tok2 = strtok(NULL, ",");
1035 if (!tok2)
1036 goto setup;
1037 }
1038
1039 /* get the call chain order */
1040 if (!strcmp(tok2, "caller"))
1041 callchain_param.order = ORDER_CALLER;
1042 else if (!strcmp(tok2, "callee"))
1043 callchain_param.order = ORDER_CALLEE;
1044 else
1045 return -1;
1046setup:
1047 if (callchain_register_param(&callchain_param) < 0) {
1048 fprintf(stderr, "Can't register callchain params\n");
1049 return -1;
1050 }
919 return 0; 1051 return 0;
920} 1052}
921 1053
@@ -973,6 +1105,10 @@ static const struct option options[] = {
973 "sort by key(s): pid, comm, dso, symbol, parent"), 1105 "sort by key(s): pid, comm, dso, symbol, parent"),
974 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1106 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
975 "Show a column with the number of samples"), 1107 "Show a column with the number of samples"),
1108 OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order",
1109 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1110 "Default: fractal,0.5,callee", &parse_callchain_opt,
1111 callchain_default_opt),
976 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 1112 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
977 "Show a column with the sum of periods"), 1113 "Show a column with the sum of periods"),
978 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 1114 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1082,6 +1218,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1082 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 1218 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1083 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); 1219 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1084 1220
1221 /*
1222 * Avoid annotation data structures overhead when symbols aren't on the
1223 * sort list.
1224 */
1225 sort_has_symbols = sort_sym.list.next != NULL;
1226
1085 get_term_dimensions(&winsize); 1227 get_term_dimensions(&winsize);
1086 if (top.print_entries == 0) { 1228 if (top.print_entries == 0) {
1087 update_print_entries(&winsize); 1229 update_print_entries(&winsize);