aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/hist.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r--tools/perf/util/hist.c230
1 files changed, 155 insertions, 75 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 784ee0bdda77..be22ae6ef055 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -5,11 +5,61 @@
5#include "sort.h" 5#include "sort.h"
6#include <math.h> 6#include <math.h>
7 7
8enum hist_filter {
9 HIST_FILTER__DSO,
10 HIST_FILTER__THREAD,
11 HIST_FILTER__PARENT,
12};
13
8struct callchain_param callchain_param = { 14struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL, 15 .mode = CHAIN_GRAPH_REL,
10 .min_percent = 0.5 16 .min_percent = 0.5
11}; 17};
12 18
19u16 hists__col_len(struct hists *self, enum hist_column col)
20{
21 return self->col_len[col];
22}
23
24void hists__set_col_len(struct hists *self, enum hist_column col, u16 len)
25{
26 self->col_len[col] = len;
27}
28
29bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len)
30{
31 if (len > hists__col_len(self, col)) {
32 hists__set_col_len(self, col, len);
33 return true;
34 }
35 return false;
36}
37
38static void hists__reset_col_len(struct hists *self)
39{
40 enum hist_column col;
41
42 for (col = 0; col < HISTC_NR_COLS; ++col)
43 hists__set_col_len(self, col, 0);
44}
45
46static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
47{
48 u16 len;
49
50 if (h->ms.sym)
51 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
52
53 len = thread__comm_len(h->thread);
54 if (hists__new_col_len(self, HISTC_COMM, len))
55 hists__set_col_len(self, HISTC_THREAD, len + 6);
56
57 if (h->ms.map) {
58 len = dso__name_len(h->ms.map->dso);
59 hists__new_col_len(self, HISTC_DSO, len);
60 }
61}
62
13static void hist_entry__add_cpumode_period(struct hist_entry *self, 63static void hist_entry__add_cpumode_period(struct hist_entry *self,
14 unsigned int cpumode, u64 period) 64 unsigned int cpumode, u64 period)
15{ 65{
@@ -43,6 +93,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
43 if (self != NULL) { 93 if (self != NULL) {
44 *self = *template; 94 *self = *template;
45 self->nr_events = 1; 95 self->nr_events = 1;
96 if (self->ms.map)
97 self->ms.map->referenced = true;
46 if (symbol_conf.use_callchain) 98 if (symbol_conf.use_callchain)
47 callchain_init(self->callchain); 99 callchain_init(self->callchain);
48 } 100 }
@@ -50,11 +102,19 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
50 return self; 102 return self;
51} 103}
52 104
53static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry) 105static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h)
54{ 106{
55 if (entry->ms.sym && self->max_sym_namelen < entry->ms.sym->namelen) 107 if (!h->filtered) {
56 self->max_sym_namelen = entry->ms.sym->namelen; 108 hists__calc_col_len(self, h);
57 ++self->nr_entries; 109 ++self->nr_entries;
110 }
111}
112
113static u8 symbol__parent_filter(const struct symbol *parent)
114{
115 if (symbol_conf.exclude_other && parent == NULL)
116 return 1 << HIST_FILTER__PARENT;
117 return 0;
58} 118}
59 119
60struct hist_entry *__hists__add_entry(struct hists *self, 120struct hist_entry *__hists__add_entry(struct hists *self,
@@ -70,10 +130,12 @@ struct hist_entry *__hists__add_entry(struct hists *self,
70 .map = al->map, 130 .map = al->map,
71 .sym = al->sym, 131 .sym = al->sym,
72 }, 132 },
133 .cpu = al->cpu,
73 .ip = al->addr, 134 .ip = al->addr,
74 .level = al->level, 135 .level = al->level,
75 .period = period, 136 .period = period,
76 .parent = sym_parent, 137 .parent = sym_parent,
138 .filtered = symbol__parent_filter(sym_parent),
77 }; 139 };
78 int cmp; 140 int cmp;
79 141
@@ -191,7 +253,7 @@ void hists__collapse_resort(struct hists *self)
191 tmp = RB_ROOT; 253 tmp = RB_ROOT;
192 next = rb_first(&self->entries); 254 next = rb_first(&self->entries);
193 self->nr_entries = 0; 255 self->nr_entries = 0;
194 self->max_sym_namelen = 0; 256 hists__reset_col_len(self);
195 257
196 while (next) { 258 while (next) {
197 n = rb_entry(next, struct hist_entry, rb_node); 259 n = rb_entry(next, struct hist_entry, rb_node);
@@ -248,7 +310,7 @@ void hists__output_resort(struct hists *self)
248 next = rb_first(&self->entries); 310 next = rb_first(&self->entries);
249 311
250 self->nr_entries = 0; 312 self->nr_entries = 0;
251 self->max_sym_namelen = 0; 313 hists__reset_col_len(self);
252 314
253 while (next) { 315 while (next) {
254 n = rb_entry(next, struct hist_entry, rb_node); 316 n = rb_entry(next, struct hist_entry, rb_node);
@@ -515,8 +577,9 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
515} 577}
516 578
517int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 579int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
518 struct hists *pair_hists, bool show_displacement, 580 struct hists *hists, struct hists *pair_hists,
519 long displacement, bool color, u64 session_total) 581 bool show_displacement, long displacement,
582 bool color, u64 session_total)
520{ 583{
521 struct sort_entry *se; 584 struct sort_entry *se;
522 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 585 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
@@ -620,29 +683,25 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
620 683
621 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 684 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
622 ret += se->se_snprintf(self, s + ret, size - ret, 685 ret += se->se_snprintf(self, s + ret, size - ret,
623 se->se_width ? *se->se_width : 0); 686 hists__col_len(hists, se->se_width_idx));
624 } 687 }
625 688
626 return ret; 689 return ret;
627} 690}
628 691
629int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists, 692int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
630 bool show_displacement, long displacement, FILE *fp, 693 struct hists *pair_hists, bool show_displacement,
631 u64 session_total) 694 long displacement, FILE *fp, u64 session_total)
632{ 695{
633 char bf[512]; 696 char bf[512];
634 int ret; 697 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
635 698 show_displacement, displacement,
636 ret = hist_entry__snprintf(self, bf, sizeof(bf), pair_hists, 699 true, session_total);
637 show_displacement, displacement,
638 true, session_total);
639 if (!ret)
640 return 0;
641
642 return fprintf(fp, "%s\n", bf); 700 return fprintf(fp, "%s\n", bf);
643} 701}
644 702
645static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp, 703static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
704 struct hists *hists, FILE *fp,
646 u64 session_total) 705 u64 session_total)
647{ 706{
648 int left_margin = 0; 707 int left_margin = 0;
@@ -650,7 +709,7 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
650 if (sort__first_dimension == SORT_COMM) { 709 if (sort__first_dimension == SORT_COMM) {
651 struct sort_entry *se = list_first_entry(&hist_entry__sort_list, 710 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
652 typeof(*se), list); 711 typeof(*se), list);
653 left_margin = se->se_width ? *se->se_width : 0; 712 left_margin = hists__col_len(hists, se->se_width_idx);
654 left_margin -= thread__comm_len(self->thread); 713 left_margin -= thread__comm_len(self->thread);
655 } 714 }
656 715
@@ -721,17 +780,17 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
721 continue; 780 continue;
722 } 781 }
723 width = strlen(se->se_header); 782 width = strlen(se->se_header);
724 if (se->se_width) { 783 if (symbol_conf.col_width_list_str) {
725 if (symbol_conf.col_width_list_str) { 784 if (col_width) {
726 if (col_width) { 785 hists__set_col_len(self, se->se_width_idx,
727 *se->se_width = atoi(col_width); 786 atoi(col_width));
728 col_width = strchr(col_width, ','); 787 col_width = strchr(col_width, ',');
729 if (col_width) 788 if (col_width)
730 ++col_width; 789 ++col_width;
731 }
732 } 790 }
733 width = *se->se_width = max(*se->se_width, width);
734 } 791 }
792 if (!hists__new_col_len(self, se->se_width_idx, width))
793 width = hists__col_len(self, se->se_width_idx);
735 fprintf(fp, " %*s", width, se->se_header); 794 fprintf(fp, " %*s", width, se->se_header);
736 } 795 }
737 fprintf(fp, "\n"); 796 fprintf(fp, "\n");
@@ -754,9 +813,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
754 continue; 813 continue;
755 814
756 fprintf(fp, " "); 815 fprintf(fp, " ");
757 if (se->se_width) 816 width = hists__col_len(self, se->se_width_idx);
758 width = *se->se_width; 817 if (width == 0)
759 else
760 width = strlen(se->se_header); 818 width = strlen(se->se_header);
761 for (i = 0; i < width; i++) 819 for (i = 0; i < width; i++)
762 fprintf(fp, "."); 820 fprintf(fp, ".");
@@ -767,7 +825,6 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
767print_entries: 825print_entries:
768 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 826 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
769 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 827 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
770 int cnt;
771 828
772 if (show_displacement) { 829 if (show_displacement) {
773 if (h->pair != NULL) 830 if (h->pair != NULL)
@@ -777,17 +834,12 @@ print_entries:
777 displacement = 0; 834 displacement = 0;
778 ++position; 835 ++position;
779 } 836 }
780 cnt = hist_entry__fprintf(h, pair, show_displacement, 837 ret += hist_entry__fprintf(h, self, pair, show_displacement,
781 displacement, fp, self->stats.total_period); 838 displacement, fp, self->stats.total_period);
782 /* Ignore those that didn't match the parent filter */
783 if (!cnt)
784 continue;
785
786 ret += cnt;
787 839
788 if (symbol_conf.use_callchain) 840 if (symbol_conf.use_callchain)
789 ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period); 841 ret += hist_entry__fprintf_callchain(h, self, fp,
790 842 self->stats.total_period);
791 if (h->ms.map == NULL && verbose > 1) { 843 if (h->ms.map == NULL && verbose > 1) {
792 __map_groups__fprintf_maps(&h->thread->mg, 844 __map_groups__fprintf_maps(&h->thread->mg,
793 MAP__FUNCTION, verbose, fp); 845 MAP__FUNCTION, verbose, fp);
@@ -800,10 +852,52 @@ print_entries:
800 return ret; 852 return ret;
801} 853}
802 854
803enum hist_filter { 855/*
804 HIST_FILTER__DSO, 856 * See hists__fprintf to match the column widths
805 HIST_FILTER__THREAD, 857 */
806}; 858unsigned int hists__sort_list_width(struct hists *self)
859{
860 struct sort_entry *se;
861 int ret = 9; /* total % */
862
863 if (symbol_conf.show_cpu_utilization) {
864 ret += 7; /* count_sys % */
865 ret += 6; /* count_us % */
866 if (perf_guest) {
867 ret += 13; /* count_guest_sys % */
868 ret += 12; /* count_guest_us % */
869 }
870 }
871
872 if (symbol_conf.show_nr_samples)
873 ret += 11;
874
875 list_for_each_entry(se, &hist_entry__sort_list, list)
876 if (!se->elide)
877 ret += 2 + hists__col_len(self, se->se_width_idx);
878
879 if (verbose) /* Addr + origin */
880 ret += 3 + BITS_PER_LONG / 4;
881
882 return ret;
883}
884
885static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
886 enum hist_filter filter)
887{
888 h->filtered &= ~(1 << filter);
889 if (h->filtered)
890 return;
891
892 ++self->nr_entries;
893 if (h->ms.unfolded)
894 self->nr_entries += h->nr_rows;
895 h->row_offset = 0;
896 self->stats.total_period += h->period;
897 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
898
899 hists__calc_col_len(self, h);
900}
807 901
808void hists__filter_by_dso(struct hists *self, const struct dso *dso) 902void hists__filter_by_dso(struct hists *self, const struct dso *dso)
809{ 903{
@@ -811,7 +905,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
811 905
812 self->nr_entries = self->stats.total_period = 0; 906 self->nr_entries = self->stats.total_period = 0;
813 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 907 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
814 self->max_sym_namelen = 0; 908 hists__reset_col_len(self);
815 909
816 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 910 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
817 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 911 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -824,15 +918,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
824 continue; 918 continue;
825 } 919 }
826 920
827 h->filtered &= ~(1 << HIST_FILTER__DSO); 921 hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
828 if (!h->filtered) {
829 ++self->nr_entries;
830 self->stats.total_period += h->period;
831 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
832 if (h->ms.sym &&
833 self->max_sym_namelen < h->ms.sym->namelen)
834 self->max_sym_namelen = h->ms.sym->namelen;
835 }
836 } 922 }
837} 923}
838 924
@@ -842,7 +928,7 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
842 928
843 self->nr_entries = self->stats.total_period = 0; 929 self->nr_entries = self->stats.total_period = 0;
844 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 930 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
845 self->max_sym_namelen = 0; 931 hists__reset_col_len(self);
846 932
847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 933 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 934 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -851,15 +937,8 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
851 h->filtered |= (1 << HIST_FILTER__THREAD); 937 h->filtered |= (1 << HIST_FILTER__THREAD);
852 continue; 938 continue;
853 } 939 }
854 h->filtered &= ~(1 << HIST_FILTER__THREAD); 940
855 if (!h->filtered) { 941 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
856 ++self->nr_entries;
857 self->stats.total_period += h->period;
858 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
859 if (h->ms.sym &&
860 self->max_sym_namelen < h->ms.sym->namelen)
861 self->max_sym_namelen = h->ms.sym->namelen;
862 }
863 } 942 }
864} 943}
865 944
@@ -904,9 +983,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
904 return 0; 983 return 0;
905} 984}
906 985
907static struct objdump_line *objdump_line__new(s64 offset, char *line) 986static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
908{ 987{
909 struct objdump_line *self = malloc(sizeof(*self)); 988 struct objdump_line *self = malloc(sizeof(*self) + privsize);
910 989
911 if (self != NULL) { 990 if (self != NULL) {
912 self->offset = offset; 991 self->offset = offset;
@@ -938,7 +1017,7 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
938} 1017}
939 1018
940static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, 1019static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
941 struct list_head *head) 1020 struct list_head *head, size_t privsize)
942{ 1021{
943 struct symbol *sym = self->ms.sym; 1022 struct symbol *sym = self->ms.sym;
944 struct objdump_line *objdump_line; 1023 struct objdump_line *objdump_line;
@@ -989,7 +1068,7 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
989 offset = -1; 1068 offset = -1;
990 } 1069 }
991 1070
992 objdump_line = objdump_line__new(offset, line); 1071 objdump_line = objdump_line__new(offset, line, privsize);
993 if (objdump_line == NULL) { 1072 if (objdump_line == NULL) {
994 free(line); 1073 free(line);
995 return -1; 1074 return -1;
@@ -999,7 +1078,8 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
999 return 0; 1078 return 0;
1000} 1079}
1001 1080
1002int hist_entry__annotate(struct hist_entry *self, struct list_head *head) 1081int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
1082 size_t privsize)
1003{ 1083{
1004 struct symbol *sym = self->ms.sym; 1084 struct symbol *sym = self->ms.sym;
1005 struct map *map = self->ms.map; 1085 struct map *map = self->ms.map;
@@ -1052,7 +1132,7 @@ fallback:
1052 dso, dso->long_name, sym, sym->name); 1132 dso, dso->long_name, sym, sym->name);
1053 1133
1054 snprintf(command, sizeof(command), 1134 snprintf(command, sizeof(command),
1055 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand", 1135 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1056 map__rip_2objdump(map, sym->start), 1136 map__rip_2objdump(map, sym->start),
1057 map__rip_2objdump(map, sym->end), 1137 map__rip_2objdump(map, sym->end),
1058 filename, filename); 1138 filename, filename);
@@ -1064,7 +1144,7 @@ fallback:
1064 goto out_free_filename; 1144 goto out_free_filename;
1065 1145
1066 while (!feof(file)) 1146 while (!feof(file))
1067 if (hist_entry__parse_objdump_line(self, file, head) < 0) 1147 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1068 break; 1148 break;
1069 1149
1070 pclose(file); 1150 pclose(file);