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.c221
1 files changed, 158 insertions, 63 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 07f89b66b318..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,24 +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 hist_entry__snprintf(self, bf, sizeof(bf), pair_hists, 697 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
635 show_displacement, displacement, 698 show_displacement, displacement,
636 true, session_total); 699 true, session_total);
637 return fprintf(fp, "%s\n", bf); 700 return fprintf(fp, "%s\n", bf);
638} 701}
639 702
640static 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,
641 u64 session_total) 705 u64 session_total)
642{ 706{
643 int left_margin = 0; 707 int left_margin = 0;
@@ -645,7 +709,7 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
645 if (sort__first_dimension == SORT_COMM) { 709 if (sort__first_dimension == SORT_COMM) {
646 struct sort_entry *se = list_first_entry(&hist_entry__sort_list, 710 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
647 typeof(*se), list); 711 typeof(*se), list);
648 left_margin = se->se_width ? *se->se_width : 0; 712 left_margin = hists__col_len(hists, se->se_width_idx);
649 left_margin -= thread__comm_len(self->thread); 713 left_margin -= thread__comm_len(self->thread);
650 } 714 }
651 715
@@ -716,17 +780,17 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
716 continue; 780 continue;
717 } 781 }
718 width = strlen(se->se_header); 782 width = strlen(se->se_header);
719 if (se->se_width) { 783 if (symbol_conf.col_width_list_str) {
720 if (symbol_conf.col_width_list_str) { 784 if (col_width) {
721 if (col_width) { 785 hists__set_col_len(self, se->se_width_idx,
722 *se->se_width = atoi(col_width); 786 atoi(col_width));
723 col_width = strchr(col_width, ','); 787 col_width = strchr(col_width, ',');
724 if (col_width) 788 if (col_width)
725 ++col_width; 789 ++col_width;
726 }
727 } 790 }
728 width = *se->se_width = max(*se->se_width, width);
729 } 791 }
792 if (!hists__new_col_len(self, se->se_width_idx, width))
793 width = hists__col_len(self, se->se_width_idx);
730 fprintf(fp, " %*s", width, se->se_header); 794 fprintf(fp, " %*s", width, se->se_header);
731 } 795 }
732 fprintf(fp, "\n"); 796 fprintf(fp, "\n");
@@ -749,9 +813,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
749 continue; 813 continue;
750 814
751 fprintf(fp, " "); 815 fprintf(fp, " ");
752 if (se->se_width) 816 width = hists__col_len(self, se->se_width_idx);
753 width = *se->se_width; 817 if (width == 0)
754 else
755 width = strlen(se->se_header); 818 width = strlen(se->se_header);
756 for (i = 0; i < width; i++) 819 for (i = 0; i < width; i++)
757 fprintf(fp, "."); 820 fprintf(fp, ".");
@@ -771,12 +834,12 @@ print_entries:
771 displacement = 0; 834 displacement = 0;
772 ++position; 835 ++position;
773 } 836 }
774 ret += hist_entry__fprintf(h, pair, show_displacement, 837 ret += hist_entry__fprintf(h, self, pair, show_displacement,
775 displacement, fp, self->stats.total_period); 838 displacement, fp, self->stats.total_period);
776 839
777 if (symbol_conf.use_callchain) 840 if (symbol_conf.use_callchain)
778 ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period); 841 ret += hist_entry__fprintf_callchain(h, self, fp,
779 842 self->stats.total_period);
780 if (h->ms.map == NULL && verbose > 1) { 843 if (h->ms.map == NULL && verbose > 1) {
781 __map_groups__fprintf_maps(&h->thread->mg, 844 __map_groups__fprintf_maps(&h->thread->mg,
782 MAP__FUNCTION, verbose, fp); 845 MAP__FUNCTION, verbose, fp);
@@ -789,10 +852,52 @@ print_entries:
789 return ret; 852 return ret;
790} 853}
791 854
792enum hist_filter { 855/*
793 HIST_FILTER__DSO, 856 * See hists__fprintf to match the column widths
794 HIST_FILTER__THREAD, 857 */
795}; 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}
796 901
797void hists__filter_by_dso(struct hists *self, const struct dso *dso) 902void hists__filter_by_dso(struct hists *self, const struct dso *dso)
798{ 903{
@@ -800,7 +905,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
800 905
801 self->nr_entries = self->stats.total_period = 0; 906 self->nr_entries = self->stats.total_period = 0;
802 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 907 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
803 self->max_sym_namelen = 0; 908 hists__reset_col_len(self);
804 909
805 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 910 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
806 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);
@@ -813,15 +918,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
813 continue; 918 continue;
814 } 919 }
815 920
816 h->filtered &= ~(1 << HIST_FILTER__DSO); 921 hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
817 if (!h->filtered) {
818 ++self->nr_entries;
819 self->stats.total_period += h->period;
820 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
821 if (h->ms.sym &&
822 self->max_sym_namelen < h->ms.sym->namelen)
823 self->max_sym_namelen = h->ms.sym->namelen;
824 }
825 } 922 }
826} 923}
827 924
@@ -831,7 +928,7 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
831 928
832 self->nr_entries = self->stats.total_period = 0; 929 self->nr_entries = self->stats.total_period = 0;
833 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 930 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
834 self->max_sym_namelen = 0; 931 hists__reset_col_len(self);
835 932
836 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 933 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
837 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);
@@ -840,15 +937,8 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
840 h->filtered |= (1 << HIST_FILTER__THREAD); 937 h->filtered |= (1 << HIST_FILTER__THREAD);
841 continue; 938 continue;
842 } 939 }
843 h->filtered &= ~(1 << HIST_FILTER__THREAD); 940
844 if (!h->filtered) { 941 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
845 ++self->nr_entries;
846 self->stats.total_period += h->period;
847 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
848 if (h->ms.sym &&
849 self->max_sym_namelen < h->ms.sym->namelen)
850 self->max_sym_namelen = h->ms.sym->namelen;
851 }
852 } 942 }
853} 943}
854 944
@@ -893,9 +983,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
893 return 0; 983 return 0;
894} 984}
895 985
896static struct objdump_line *objdump_line__new(s64 offset, char *line) 986static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
897{ 987{
898 struct objdump_line *self = malloc(sizeof(*self)); 988 struct objdump_line *self = malloc(sizeof(*self) + privsize);
899 989
900 if (self != NULL) { 990 if (self != NULL) {
901 self->offset = offset; 991 self->offset = offset;
@@ -927,7 +1017,7 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
927} 1017}
928 1018
929static 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,
930 struct list_head *head) 1020 struct list_head *head, size_t privsize)
931{ 1021{
932 struct symbol *sym = self->ms.sym; 1022 struct symbol *sym = self->ms.sym;
933 struct objdump_line *objdump_line; 1023 struct objdump_line *objdump_line;
@@ -965,16 +1055,20 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
965 * Parse hexa addresses followed by ':' 1055 * Parse hexa addresses followed by ':'
966 */ 1056 */
967 line_ip = strtoull(tmp, &tmp2, 16); 1057 line_ip = strtoull(tmp, &tmp2, 16);
968 if (*tmp2 != ':' || tmp == tmp2) 1058 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
969 line_ip = -1; 1059 line_ip = -1;
970 } 1060 }
971 1061
972 if (line_ip != -1) { 1062 if (line_ip != -1) {
973 u64 start = map__rip_2objdump(self->ms.map, sym->start); 1063 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1064 end = map__rip_2objdump(self->ms.map, sym->end);
1065
974 offset = line_ip - start; 1066 offset = line_ip - start;
1067 if (offset < 0 || (u64)line_ip > end)
1068 offset = -1;
975 } 1069 }
976 1070
977 objdump_line = objdump_line__new(offset, line); 1071 objdump_line = objdump_line__new(offset, line, privsize);
978 if (objdump_line == NULL) { 1072 if (objdump_line == NULL) {
979 free(line); 1073 free(line);
980 return -1; 1074 return -1;
@@ -984,7 +1078,8 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
984 return 0; 1078 return 0;
985} 1079}
986 1080
987int 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)
988{ 1083{
989 struct symbol *sym = self->ms.sym; 1084 struct symbol *sym = self->ms.sym;
990 struct map *map = self->ms.map; 1085 struct map *map = self->ms.map;
@@ -1037,7 +1132,7 @@ fallback:
1037 dso, dso->long_name, sym, sym->name); 1132 dso, dso->long_name, sym, sym->name);
1038 1133
1039 snprintf(command, sizeof(command), 1134 snprintf(command, sizeof(command),
1040 "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",
1041 map__rip_2objdump(map, sym->start), 1136 map__rip_2objdump(map, sym->start),
1042 map__rip_2objdump(map, sym->end), 1137 map__rip_2objdump(map, sym->end),
1043 filename, filename); 1138 filename, filename);
@@ -1049,7 +1144,7 @@ fallback:
1049 goto out_free_filename; 1144 goto out_free_filename;
1050 1145
1051 while (!feof(file)) 1146 while (!feof(file))
1052 if (hist_entry__parse_objdump_line(self, file, head) < 0) 1147 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1053 break; 1148 break;
1054 1149
1055 pclose(file); 1150 pclose(file);