aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Makefile5
-rw-r--r--tools/perf/builtin-annotate.c198
-rw-r--r--tools/perf/builtin-report.c19
-rw-r--r--tools/perf/util/hist.c184
-rw-r--r--tools/perf/util/hist.h29
-rw-r--r--tools/perf/util/newt.c352
-rw-r--r--tools/perf/util/sort.h6
7 files changed, 544 insertions, 249 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0797786aa72a..9c4dc30cdc13 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -560,6 +560,8 @@ ifneq ($(shell sh -c "(echo '\#include <newt.h>'; echo 'int main(void) { newtIni
560 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); 560 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
561 BASIC_CFLAGS += -DNO_NEWT_SUPPORT 561 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
562else 562else
563 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
564 BASIC_CFLAGS += -I/usr/include/slang
563 EXTLIBS += -lnewt 565 EXTLIBS += -lnewt
564 LIB_OBJS += $(OUTPUT)util/newt.o 566 LIB_OBJS += $(OUTPUT)util/newt.o
565endif 567endif
@@ -948,6 +950,9 @@ $(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS
948$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 950$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
949 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 951 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
950 952
953$(OUTPUT)util/newt.o: util/newt.c $(OUTPUT)PERF-CFLAGS
954 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
955
951$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 956$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
952 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 957 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
953 958
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 3940964161b3..fd1b786c8f35 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -34,68 +34,8 @@ static bool full_paths;
34 34
35static bool print_line; 35static bool print_line;
36 36
37struct sym_hist {
38 u64 sum;
39 u64 ip[0];
40};
41
42struct sym_ext {
43 struct rb_node node;
44 double percent;
45 char *path;
46};
47
48struct sym_priv {
49 struct sym_hist *hist;
50 struct sym_ext *ext;
51};
52
53static const char *sym_hist_filter; 37static const char *sym_hist_filter;
54 38
55static int sym__alloc_hist(struct symbol *self)
56{
57 struct sym_priv *priv = symbol__priv(self);
58 const int size = (sizeof(*priv->hist) +
59 (self->end - self->start) * sizeof(u64));
60
61 priv->hist = zalloc(size);
62 return priv->hist == NULL ? -1 : 0;
63}
64
65/*
66 * collect histogram counts
67 */
68static int annotate__hist_hit(struct hist_entry *he, u64 ip)
69{
70 unsigned int sym_size, offset;
71 struct symbol *sym = he->ms.sym;
72 struct sym_priv *priv;
73 struct sym_hist *h;
74
75 if (!sym || !he->ms.map)
76 return 0;
77
78 priv = symbol__priv(sym);
79 if (priv->hist == NULL && sym__alloc_hist(sym) < 0)
80 return -ENOMEM;
81
82 sym_size = sym->end - sym->start;
83 offset = ip - sym->start;
84
85 pr_debug3("%s: ip=%#Lx\n", __func__, he->ms.map->unmap_ip(he->ms.map, ip));
86
87 if (offset >= sym_size)
88 return 0;
89
90 h = priv->hist;
91 h->sum++;
92 h->ip[offset]++;
93
94 pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->ms.sym->start,
95 he->ms.sym->name, ip, ip - he->ms.sym->start, h->ip[offset]);
96 return 0;
97}
98
99static int hists__add_entry(struct hists *self, struct addr_location *al) 39static int hists__add_entry(struct hists *self, struct addr_location *al)
100{ 40{
101 struct hist_entry *he; 41 struct hist_entry *he;
@@ -115,7 +55,7 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
115 if (he == NULL) 55 if (he == NULL)
116 return -ENOMEM; 56 return -ENOMEM;
117 57
118 return annotate__hist_hit(he, al->addr); 58 return hist_entry__inc_addr_samples(he, al->addr);
119} 59}
120 60
121static int process_sample_event(event_t *event, struct perf_session *session) 61static int process_sample_event(event_t *event, struct perf_session *session)
@@ -140,101 +80,6 @@ static int process_sample_event(event_t *event, struct perf_session *session)
140 return 0; 80 return 0;
141} 81}
142 82
143struct objdump_line {
144 struct list_head node;
145 s64 offset;
146 char *line;
147};
148
149static struct objdump_line *objdump_line__new(s64 offset, char *line)
150{
151 struct objdump_line *self = malloc(sizeof(*self));
152
153 if (self != NULL) {
154 self->offset = offset;
155 self->line = line;
156 }
157
158 return self;
159}
160
161static void objdump_line__free(struct objdump_line *self)
162{
163 free(self->line);
164 free(self);
165}
166
167static void objdump__add_line(struct list_head *head, struct objdump_line *line)
168{
169 list_add_tail(&line->node, head);
170}
171
172static struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
173 struct objdump_line *pos)
174{
175 list_for_each_entry_continue(pos, head, node)
176 if (pos->offset >= 0)
177 return pos;
178
179 return NULL;
180}
181
182static int parse_line(FILE *file, struct hist_entry *he,
183 struct list_head *head)
184{
185 struct symbol *sym = he->ms.sym;
186 struct objdump_line *objdump_line;
187 char *line = NULL, *tmp, *tmp2;
188 size_t line_len;
189 s64 line_ip, offset = -1;
190 char *c;
191
192 if (getline(&line, &line_len, file) < 0)
193 return -1;
194
195 if (!line)
196 return -1;
197
198 c = strchr(line, '\n');
199 if (c)
200 *c = 0;
201
202 line_ip = -1;
203
204 /*
205 * Strip leading spaces:
206 */
207 tmp = line;
208 while (*tmp) {
209 if (*tmp != ' ')
210 break;
211 tmp++;
212 }
213
214 if (*tmp) {
215 /*
216 * Parse hexa addresses followed by ':'
217 */
218 line_ip = strtoull(tmp, &tmp2, 16);
219 if (*tmp2 != ':')
220 line_ip = -1;
221 }
222
223 if (line_ip != -1) {
224 u64 start = map__rip_2objdump(he->ms.map, sym->start);
225 offset = line_ip - start;
226 }
227
228 objdump_line = objdump_line__new(offset, line);
229 if (objdump_line == NULL) {
230 free(line);
231 return -1;
232 }
233 objdump__add_line(head, objdump_line);
234
235 return 0;
236}
237
238static int objdump_line__print(struct objdump_line *self, 83static int objdump_line__print(struct objdump_line *self,
239 struct list_head *head, 84 struct list_head *head,
240 struct hist_entry *he, u64 len) 85 struct hist_entry *he, u64 len)
@@ -439,27 +284,11 @@ static void annotate_sym(struct hist_entry *he)
439 struct symbol *sym = he->ms.sym; 284 struct symbol *sym = he->ms.sym;
440 const char *filename = dso->long_name, *d_filename; 285 const char *filename = dso->long_name, *d_filename;
441 u64 len; 286 u64 len;
442 char command[PATH_MAX*2];
443 FILE *file;
444 LIST_HEAD(head); 287 LIST_HEAD(head);
445 struct objdump_line *pos, *n; 288 struct objdump_line *pos, *n;
446 289
447 if (!filename) 290 if (hist_entry__annotate(he, &head) < 0)
448 return;
449
450 if (dso->origin == DSO__ORIG_KERNEL) {
451 if (dso->annotate_warned)
452 return;
453 dso->annotate_warned = 1;
454 pr_err("Can't annotate %s: No vmlinux file was found in the "
455 "path:\n", sym->name);
456 vmlinux_path__fprintf(stderr);
457 return; 291 return;
458 }
459
460 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
461 filename, sym->name, map->unmap_ip(map, sym->start),
462 map->unmap_ip(map, sym->end));
463 292
464 if (full_paths) 293 if (full_paths)
465 d_filename = filename; 294 d_filename = filename;
@@ -477,29 +306,6 @@ static void annotate_sym(struct hist_entry *he)
477 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 306 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
478 printf("------------------------------------------------\n"); 307 printf("------------------------------------------------\n");
479 308
480 if (verbose >= 2)
481 printf("annotating [%p] %30s : [%p] %30s\n",
482 dso, dso->long_name, sym, sym->name);
483
484 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
485 map__rip_2objdump(map, sym->start),
486 map__rip_2objdump(map, sym->end),
487 filename, filename);
488
489 if (verbose >= 3)
490 printf("doing: %s\n", command);
491
492 file = popen(command, "r");
493 if (!file)
494 return;
495
496 while (!feof(file)) {
497 if (parse_line(file, he, &head) < 0)
498 break;
499 }
500
501 pclose(file);
502
503 if (verbose) 309 if (verbose)
504 hist_entry__print_hits(he); 310 hist_entry__print_hits(he);
505 311
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3d67d6bf22cf..04de3387de3f 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -106,8 +106,18 @@ static int perf_session__add_hist_entry(struct perf_session *self,
106 if (he == NULL) 106 if (he == NULL)
107 goto out_free_syms; 107 goto out_free_syms;
108 err = 0; 108 err = 0;
109 if (symbol_conf.use_callchain) 109 if (symbol_conf.use_callchain) {
110 err = append_chain(he->callchain, data->callchain, syms); 110 err = append_chain(he->callchain, data->callchain, syms);
111 if (err)
112 goto out_free_syms;
113 }
114 /*
115 * Only in the newt browser we are doing integrated annotation,
116 * so we don't allocated the extra space needed because the stdio
117 * code will not use it.
118 */
119 if (use_browser)
120 err = hist_entry__inc_addr_samples(he, al->addr);
111out_free_syms: 121out_free_syms:
112 free(syms); 122 free(syms);
113 return err; 123 return err;
@@ -458,6 +468,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
458 468
459 if (strcmp(input_name, "-") != 0) 469 if (strcmp(input_name, "-") != 0)
460 setup_browser(); 470 setup_browser();
471 /*
472 * Only in the newt browser we are doing integrated annotation,
473 * so don't allocate extra space that won't be used in the stdio
474 * implementation.
475 */
476 if (use_browser)
477 symbol_conf.priv_size = sizeof(struct sym_priv);
461 478
462 if (symbol__init() < 0) 479 if (symbol__init() < 0)
463 return -1; 480 return -1;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index baa55be64d9e..451d2e45d843 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -843,3 +843,187 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
843 } 843 }
844 } 844 }
845} 845}
846
847static int symbol__alloc_hist(struct symbol *self)
848{
849 struct sym_priv *priv = symbol__priv(self);
850 const int size = (sizeof(*priv->hist) +
851 (self->end - self->start) * sizeof(u64));
852
853 priv->hist = zalloc(size);
854 return priv->hist == NULL ? -1 : 0;
855}
856
857int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
858{
859 unsigned int sym_size, offset;
860 struct symbol *sym = self->ms.sym;
861 struct sym_priv *priv;
862 struct sym_hist *h;
863
864 if (!sym || !self->ms.map)
865 return 0;
866
867 priv = symbol__priv(sym);
868 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
869 return -ENOMEM;
870
871 sym_size = sym->end - sym->start;
872 offset = ip - sym->start;
873
874 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
875
876 if (offset >= sym_size)
877 return 0;
878
879 h = priv->hist;
880 h->sum++;
881 h->ip[offset]++;
882
883 pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
884 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
885 return 0;
886}
887
888static struct objdump_line *objdump_line__new(s64 offset, char *line)
889{
890 struct objdump_line *self = malloc(sizeof(*self));
891
892 if (self != NULL) {
893 self->offset = offset;
894 self->line = line;
895 }
896
897 return self;
898}
899
900void objdump_line__free(struct objdump_line *self)
901{
902 free(self->line);
903 free(self);
904}
905
906static void objdump__add_line(struct list_head *head, struct objdump_line *line)
907{
908 list_add_tail(&line->node, head);
909}
910
911struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
912 struct objdump_line *pos)
913{
914 list_for_each_entry_continue(pos, head, node)
915 if (pos->offset >= 0)
916 return pos;
917
918 return NULL;
919}
920
921static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
922 struct list_head *head)
923{
924 struct symbol *sym = self->ms.sym;
925 struct objdump_line *objdump_line;
926 char *line = NULL, *tmp, *tmp2, *c;
927 size_t line_len;
928 s64 line_ip, offset = -1;
929
930 if (getline(&line, &line_len, file) < 0)
931 return -1;
932
933 if (!line)
934 return -1;
935
936 while (line_len != 0 && isspace(line[line_len - 1]))
937 line[--line_len] = '\0';
938
939 c = strchr(line, '\n');
940 if (c)
941 *c = 0;
942
943 line_ip = -1;
944
945 /*
946 * Strip leading spaces:
947 */
948 tmp = line;
949 while (*tmp) {
950 if (*tmp != ' ')
951 break;
952 tmp++;
953 }
954
955 if (*tmp) {
956 /*
957 * Parse hexa addresses followed by ':'
958 */
959 line_ip = strtoull(tmp, &tmp2, 16);
960 if (*tmp2 != ':')
961 line_ip = -1;
962 }
963
964 if (line_ip != -1) {
965 u64 start = map__rip_2objdump(self->ms.map, sym->start);
966 offset = line_ip - start;
967 }
968
969 objdump_line = objdump_line__new(offset, line);
970 if (objdump_line == NULL) {
971 free(line);
972 return -1;
973 }
974 objdump__add_line(head, objdump_line);
975
976 return 0;
977}
978
979int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
980{
981 struct symbol *sym = self->ms.sym;
982 struct map *map = self->ms.map;
983 struct dso *dso = map->dso;
984 const char *filename = dso->long_name;
985 char command[PATH_MAX * 2];
986 FILE *file;
987 u64 len;
988
989 if (!filename)
990 return -1;
991
992 if (dso->origin == DSO__ORIG_KERNEL) {
993 if (dso->annotate_warned)
994 return 0;
995 dso->annotate_warned = 1;
996 pr_err("Can't annotate %s: No vmlinux file was found in the "
997 "path:\n", sym->name);
998 vmlinux_path__fprintf(stderr);
999 return -1;
1000 }
1001
1002 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1003 filename, sym->name, map->unmap_ip(map, sym->start),
1004 map->unmap_ip(map, sym->end));
1005
1006 len = sym->end - sym->start;
1007
1008 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1009 dso, dso->long_name, sym, sym->name);
1010
1011 snprintf(command, sizeof(command),
1012 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand",
1013 map__rip_2objdump(map, sym->start),
1014 map__rip_2objdump(map, sym->end),
1015 filename, filename);
1016
1017 pr_debug("Executing: %s\n", command);
1018
1019 file = popen(command, "r");
1020 if (!file)
1021 return -1;
1022
1023 while (!feof(file))
1024 if (hist_entry__parse_objdump_line(self, file, head) < 0)
1025 break;
1026
1027 pclose(file);
1028 return 0;
1029}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 1c5f93ac5ab7..ed9c06734965 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -11,6 +11,32 @@ struct addr_location;
11struct symbol; 11struct symbol;
12struct rb_root; 12struct rb_root;
13 13
14struct objdump_line {
15 struct list_head node;
16 s64 offset;
17 char *line;
18};
19
20void objdump_line__free(struct objdump_line *self);
21struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
22 struct objdump_line *pos);
23
24struct sym_hist {
25 u64 sum;
26 u64 ip[0];
27};
28
29struct sym_ext {
30 struct rb_node node;
31 double percent;
32 char *path;
33};
34
35struct sym_priv {
36 struct sym_hist *hist;
37 struct sym_ext *ext;
38};
39
14struct events_stats { 40struct events_stats {
15 u64 total; 41 u64 total;
16 u64 lost; 42 u64 lost;
@@ -45,6 +71,9 @@ void hists__collapse_resort(struct hists *self);
45size_t hists__fprintf(struct hists *self, struct hists *pair, 71size_t hists__fprintf(struct hists *self, struct hists *pair,
46 bool show_displacement, FILE *fp); 72 bool show_displacement, FILE *fp);
47 73
74int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip);
75int hist_entry__annotate(struct hist_entry *self, struct list_head *head);
76
48void hists__filter_by_dso(struct hists *self, const struct dso *dso); 77void hists__filter_by_dso(struct hists *self, const struct dso *dso);
49void hists__filter_by_thread(struct hists *self, const struct thread *thread); 78void hists__filter_by_thread(struct hists *self, const struct thread *thread);
50 79
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index daa86efffce6..ba6acd04c082 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -2,6 +2,7 @@
2#include <stdio.h> 2#include <stdio.h>
3#undef _GNU_SOURCE 3#undef _GNU_SOURCE
4 4
5#include <slang.h>
5#include <stdlib.h> 6#include <stdlib.h>
6#include <newt.h> 7#include <newt.h>
7#include <sys/ttydefaults.h> 8#include <sys/ttydefaults.h>
@@ -171,6 +172,254 @@ static bool dialog_yesno(const char *msg)
171 return newtWinChoice(NULL, yes, no, (char *)msg) == 1; 172 return newtWinChoice(NULL, yes, no, (char *)msg) == 1;
172} 173}
173 174
175#define HE_COLORSET_TOP 50
176#define HE_COLORSET_MEDIUM 51
177#define HE_COLORSET_NORMAL 52
178#define HE_COLORSET_SELECTED 53
179#define HE_COLORSET_CODE 54
180
181static int ui_browser__percent_color(double percent, bool current)
182{
183 if (current)
184 return HE_COLORSET_SELECTED;
185 if (percent >= MIN_RED)
186 return HE_COLORSET_TOP;
187 if (percent >= MIN_GREEN)
188 return HE_COLORSET_MEDIUM;
189 return HE_COLORSET_NORMAL;
190}
191
192struct ui_browser {
193 newtComponent form, sb;
194 u64 index, first_visible_entry_idx;
195 void *first_visible_entry, *entries;
196 u16 top, left, width, height;
197 void *priv;
198 u32 nr_entries;
199};
200
201static void ui_browser__refresh_dimensions(struct ui_browser *self)
202{
203 int cols, rows;
204 newtGetScreenSize(&cols, &rows);
205
206 if (self->width > cols - 4)
207 self->width = cols - 4;
208 self->height = rows - 5;
209 if (self->height > self->nr_entries)
210 self->height = self->nr_entries;
211 self->top = (rows - self->height) / 2;
212 self->left = (cols - self->width) / 2;
213}
214
215static void ui_browser__reset_index(struct ui_browser *self)
216{
217 self->index = self->first_visible_entry_idx = 0;
218 self->first_visible_entry = NULL;
219}
220
221static int objdump_line__show(struct objdump_line *self, struct list_head *head,
222 int width, struct hist_entry *he, int len,
223 bool current_entry)
224{
225 if (self->offset != -1) {
226 struct symbol *sym = he->ms.sym;
227 unsigned int hits = 0;
228 double percent = 0.0;
229 int color;
230 struct sym_priv *priv = symbol__priv(sym);
231 struct sym_ext *sym_ext = priv->ext;
232 struct sym_hist *h = priv->hist;
233 s64 offset = self->offset;
234 struct objdump_line *next = objdump__get_next_ip_line(head, self);
235
236 while (offset < (s64)len &&
237 (next == NULL || offset < next->offset)) {
238 if (sym_ext) {
239 percent += sym_ext[offset].percent;
240 } else
241 hits += h->ip[offset];
242
243 ++offset;
244 }
245
246 if (sym_ext == NULL && h->sum)
247 percent = 100.0 * hits / h->sum;
248
249 color = ui_browser__percent_color(percent, current_entry);
250 SLsmg_set_color(color);
251 SLsmg_printf(" %7.2f ", percent);
252 if (!current_entry)
253 SLsmg_set_color(HE_COLORSET_CODE);
254 } else {
255 int color = ui_browser__percent_color(0, current_entry);
256 SLsmg_set_color(color);
257 SLsmg_write_nstring(" ", 9);
258 }
259
260 SLsmg_write_char(':');
261 SLsmg_write_nstring(" ", 8);
262 if (!*self->line)
263 SLsmg_write_nstring(" ", width - 18);
264 else
265 SLsmg_write_nstring(self->line, width - 18);
266
267 return 0;
268}
269
270static int ui_browser__refresh_entries(struct ui_browser *self)
271{
272 struct objdump_line *pos;
273 struct list_head *head = self->entries;
274 struct hist_entry *he = self->priv;
275 int row = 0;
276 int len = he->ms.sym->end - he->ms.sym->start;
277
278 if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
279 self->first_visible_entry = head->next;
280
281 pos = list_entry(self->first_visible_entry, struct objdump_line, node);
282
283 list_for_each_entry_from(pos, head, node) {
284 bool current_entry = (self->first_visible_entry_idx + row) == self->index;
285 SLsmg_gotorc(self->top + row, self->left);
286 objdump_line__show(pos, head, self->width,
287 he, len, current_entry);
288 if (++row == self->height)
289 break;
290 }
291
292 SLsmg_set_color(HE_COLORSET_NORMAL);
293 SLsmg_fill_region(self->top + row, self->left,
294 self->height - row, self->width, ' ');
295
296 return 0;
297}
298
299static int ui_browser__run(struct ui_browser *self, const char *title,
300 struct newtExitStruct *es)
301{
302 if (self->form) {
303 newtFormDestroy(self->form);
304 newtPopWindow();
305 }
306
307 ui_browser__refresh_dimensions(self);
308 newtCenteredWindow(self->width + 2, self->height, title);
309 self->form = newt_form__new();
310 if (self->form == NULL)
311 return -1;
312
313 self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height,
314 HE_COLORSET_NORMAL,
315 HE_COLORSET_SELECTED);
316 if (self->sb == NULL)
317 return -1;
318
319 newtFormAddHotKey(self->form, NEWT_KEY_UP);
320 newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
321 newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
322 newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
323 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
324 newtFormAddHotKey(self->form, NEWT_KEY_END);
325
326 if (ui_browser__refresh_entries(self) < 0)
327 return -1;
328 newtFormAddComponent(self->form, self->sb);
329
330 while (1) {
331 unsigned int offset;
332
333 newtFormRun(self->form, es);
334
335 if (es->reason != NEWT_EXIT_HOTKEY)
336 break;
337 switch (es->u.key) {
338 case NEWT_KEY_DOWN:
339 if (self->index == self->nr_entries - 1)
340 break;
341 ++self->index;
342 if (self->index == self->first_visible_entry_idx + self->height) {
343 struct list_head *pos = self->first_visible_entry;
344 ++self->first_visible_entry_idx;
345 self->first_visible_entry = pos->next;
346 }
347 break;
348 case NEWT_KEY_UP:
349 if (self->index == 0)
350 break;
351 --self->index;
352 if (self->index < self->first_visible_entry_idx) {
353 struct list_head *pos = self->first_visible_entry;
354 --self->first_visible_entry_idx;
355 self->first_visible_entry = pos->prev;
356 }
357 break;
358 case NEWT_KEY_PGDN:
359 if (self->first_visible_entry_idx + self->height > self->nr_entries - 1)
360 break;
361
362 offset = self->height;
363 if (self->index + offset > self->nr_entries - 1)
364 offset = self->nr_entries - 1 - self->index;
365 self->index += offset;
366 self->first_visible_entry_idx += offset;
367
368 while (offset--) {
369 struct list_head *pos = self->first_visible_entry;
370 self->first_visible_entry = pos->next;
371 }
372
373 break;
374 case NEWT_KEY_PGUP:
375 if (self->first_visible_entry_idx == 0)
376 break;
377
378 if (self->first_visible_entry_idx < self->height)
379 offset = self->first_visible_entry_idx;
380 else
381 offset = self->height;
382
383 self->index -= offset;
384 self->first_visible_entry_idx -= offset;
385
386 while (offset--) {
387 struct list_head *pos = self->first_visible_entry;
388 self->first_visible_entry = pos->prev;
389 }
390 break;
391 case NEWT_KEY_HOME:
392 ui_browser__reset_index(self);
393 break;
394 case NEWT_KEY_END: {
395 struct list_head *head = self->entries;
396 offset = self->height - 1;
397
398 if (offset > self->nr_entries)
399 offset = self->nr_entries;
400
401 self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset;
402 self->first_visible_entry = head->prev;
403 while (offset-- != 0) {
404 struct list_head *pos = self->first_visible_entry;
405 self->first_visible_entry = pos->prev;
406 }
407 }
408 break;
409 case NEWT_KEY_ESCAPE:
410 case CTRL('c'):
411 case 'Q':
412 case 'q':
413 return 0;
414 default:
415 continue;
416 }
417 if (ui_browser__refresh_entries(self) < 0)
418 return -1;
419 }
420 return 0;
421}
422
174/* 423/*
175 * When debugging newt problems it was useful to be able to "unroll" 424 * When debugging newt problems it was useful to be able to "unroll"
176 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate 425 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
@@ -353,62 +602,40 @@ static size_t hist_entry__append_browser(struct hist_entry *self,
353 return ret; 602 return ret;
354} 603}
355 604
356static void map_symbol__annotate_browser(const struct map_symbol *self, 605static void hist_entry__annotate_browser(struct hist_entry *self)
357 const char *input_name)
358{ 606{
359 FILE *fp; 607 struct ui_browser browser;
360 int cols, rows;
361 newtComponent form, tree;
362 struct newtExitStruct es; 608 struct newtExitStruct es;
363 char *str; 609 struct objdump_line *pos, *n;
364 size_t line_len, max_line_len = 0; 610 LIST_HEAD(head);
365 size_t max_usable_width;
366 char *line = NULL;
367 611
368 if (self->sym == NULL) 612 if (self->ms.sym == NULL)
369 return; 613 return;
370 614
371 if (asprintf(&str, "perf annotate -i \"%s\" -d \"%s\" %s 2>&1 | expand", 615 if (hist_entry__annotate(self, &head) < 0)
372 input_name, self->map->dso->name, self->sym->name) < 0)
373 return; 616 return;
374 617
375 fp = popen(str, "r");
376 if (fp == NULL)
377 goto out_free_str;
378
379 ui_helpline__push("Press ESC to exit"); 618 ui_helpline__push("Press ESC to exit");
380 newtGetScreenSize(&cols, &rows);
381 tree = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL);
382
383 while (!feof(fp)) {
384 if (getline(&line, &line_len, fp) < 0 || !line_len)
385 break;
386 while (line_len != 0 && isspace(line[line_len - 1]))
387 line[--line_len] = '\0';
388 619
389 if (line_len > max_line_len) 620 memset(&browser, 0, sizeof(browser));
390 max_line_len = line_len; 621 browser.entries = &head;
391 newtListboxAppendEntry(tree, line, NULL); 622 browser.priv = self;
623 list_for_each_entry(pos, &head, node) {
624 size_t line_len = strlen(pos->line);
625 if (browser.width < line_len)
626 browser.width = line_len;
627 ++browser.nr_entries;
392 } 628 }
393 fclose(fp);
394 free(line);
395
396 max_usable_width = cols - 22;
397 if (max_line_len > max_usable_width)
398 max_line_len = max_usable_width;
399
400 newtListboxSetWidth(tree, max_line_len);
401 629
402 newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name); 630 browser.width += 18; /* Percentage */
403 form = newt_form__new(); 631 ui_browser__run(&browser, self->ms.sym->name, &es);
404 newtFormAddComponent(form, tree); 632 newtFormDestroy(browser.form);
405
406 newtFormRun(form, &es);
407 newtFormDestroy(form);
408 newtPopWindow(); 633 newtPopWindow();
634 list_for_each_entry_safe(pos, n, &head, node) {
635 list_del(&pos->node);
636 objdump_line__free(pos);
637 }
409 ui_helpline__pop(); 638 ui_helpline__pop();
410out_free_str:
411 free(str);
412} 639}
413 640
414static const void *newt__symbol_tree_get_current(newtComponent self) 641static const void *newt__symbol_tree_get_current(newtComponent self)
@@ -527,7 +754,7 @@ static int hist_browser__populate(struct hist_browser *self, struct hists *hists
527 return 0; 754 return 0;
528} 755}
529 756
530static struct thread *hist_browser__selected_thread(struct hist_browser *self) 757static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
531{ 758{
532 int *indexes; 759 int *indexes;
533 760
@@ -543,7 +770,13 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
543 } 770 }
544 return NULL; 771 return NULL;
545out: 772out:
546 return *(struct thread **)(self->selection + 1); 773 return container_of(self->selection, struct hist_entry, ms);
774}
775
776static struct thread *hist_browser__selected_thread(struct hist_browser *self)
777{
778 struct hist_entry *he = hist_browser__selected_entry(self);
779 return he ? he->thread : NULL;
547} 780}
548 781
549static int hist_browser__title(char *bf, size_t size, const char *input_name, 782static int hist_browser__title(char *bf, size_t size, const char *input_name,
@@ -637,13 +870,20 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na
637 continue; 870 continue;
638do_annotate: 871do_annotate:
639 if (choice == annotate) { 872 if (choice == annotate) {
873 struct hist_entry *he;
874
640 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { 875 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
641 ui_helpline__puts("No vmlinux file found, can't " 876 ui_helpline__puts("No vmlinux file found, can't "
642 "annotate with just a " 877 "annotate with just a "
643 "kallsyms file"); 878 "kallsyms file");
644 continue; 879 continue;
645 } 880 }
646 map_symbol__annotate_browser(browser->selection, input_name); 881
882 he = hist_browser__selected_entry(browser);
883 if (he == NULL)
884 continue;
885
886 hist_entry__annotate_browser(he);
647 } else if (choice == zoom_dso) { 887 } else if (choice == zoom_dso) {
648 if (dso_filter) { 888 if (dso_filter) {
649 ui_helpline__pop(); 889 ui_helpline__pop();
@@ -681,8 +921,23 @@ out:
681 return err; 921 return err;
682} 922}
683 923
924static struct newtPercentTreeColors {
925 const char *topColorFg, *topColorBg;
926 const char *mediumColorFg, *mediumColorBg;
927 const char *normalColorFg, *normalColorBg;
928 const char *selColorFg, *selColorBg;
929 const char *codeColorFg, *codeColorBg;
930} defaultPercentTreeColors = {
931 "red", "lightgray",
932 "green", "lightgray",
933 "black", "lightgray",
934 "lightgray", "magenta",
935 "blue", "lightgray",
936};
937
684void setup_browser(void) 938void setup_browser(void)
685{ 939{
940 struct newtPercentTreeColors *c = &defaultPercentTreeColors;
686 if (!isatty(1)) 941 if (!isatty(1))
687 return; 942 return;
688 943
@@ -690,6 +945,11 @@ void setup_browser(void)
690 newtInit(); 945 newtInit();
691 newtCls(); 946 newtCls();
692 ui_helpline__puts(" "); 947 ui_helpline__puts(" ");
948 SLtt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
949 SLtt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
950 SLtt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg);
951 SLtt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg);
952 SLtt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
693} 953}
694 954
695void exit_browser(bool wait_for_ok) 955void exit_browser(bool wait_for_ok)
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index b7c54eeed9c9..af301acc461c 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -48,12 +48,6 @@ struct hist_entry {
48 u64 count_us; 48 u64 count_us;
49 u64 count_guest_sys; 49 u64 count_guest_sys;
50 u64 count_guest_us; 50 u64 count_guest_us;
51
52 /*
53 * XXX WARNING!
54 * thread _has_ to come after ms, see
55 * hist_browser__selected_thread in util/newt.c
56 */
57 struct map_symbol ms; 51 struct map_symbol ms;
58 struct thread *thread; 52 struct thread *thread;
59 u64 ip; 53 u64 ip;