diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-annotate.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 13 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 3 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 153 |
4 files changed, 125 insertions, 46 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index fd20670ce986..1478dc64bf15 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -285,7 +285,7 @@ static int hist_entry__tty_annotate(struct hist_entry *he) | |||
285 | LIST_HEAD(head); | 285 | LIST_HEAD(head); |
286 | struct objdump_line *pos, *n; | 286 | struct objdump_line *pos, *n; |
287 | 287 | ||
288 | if (hist_entry__annotate(he, &head) < 0) | 288 | if (hist_entry__annotate(he, &head, 0) < 0) |
289 | return -1; | 289 | return -1; |
290 | 290 | ||
291 | if (full_paths) | 291 | if (full_paths) |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 62ec9b0e4b9a..be22ae6ef055 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -983,9 +983,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip) | |||
983 | return 0; | 983 | return 0; |
984 | } | 984 | } |
985 | 985 | ||
986 | static struct objdump_line *objdump_line__new(s64 offset, char *line) | 986 | static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) |
987 | { | 987 | { |
988 | struct objdump_line *self = malloc(sizeof(*self)); | 988 | struct objdump_line *self = malloc(sizeof(*self) + privsize); |
989 | 989 | ||
990 | if (self != NULL) { | 990 | if (self != NULL) { |
991 | self->offset = offset; | 991 | self->offset = offset; |
@@ -1017,7 +1017,7 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head, | |||
1017 | } | 1017 | } |
1018 | 1018 | ||
1019 | static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, | 1019 | static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, |
1020 | struct list_head *head) | 1020 | struct list_head *head, size_t privsize) |
1021 | { | 1021 | { |
1022 | struct symbol *sym = self->ms.sym; | 1022 | struct symbol *sym = self->ms.sym; |
1023 | struct objdump_line *objdump_line; | 1023 | struct objdump_line *objdump_line; |
@@ -1068,7 +1068,7 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, | |||
1068 | offset = -1; | 1068 | offset = -1; |
1069 | } | 1069 | } |
1070 | 1070 | ||
1071 | objdump_line = objdump_line__new(offset, line); | 1071 | objdump_line = objdump_line__new(offset, line, privsize); |
1072 | if (objdump_line == NULL) { | 1072 | if (objdump_line == NULL) { |
1073 | free(line); | 1073 | free(line); |
1074 | return -1; | 1074 | return -1; |
@@ -1078,7 +1078,8 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, | |||
1078 | return 0; | 1078 | return 0; |
1079 | } | 1079 | } |
1080 | 1080 | ||
1081 | int hist_entry__annotate(struct hist_entry *self, struct list_head *head) | 1081 | int hist_entry__annotate(struct hist_entry *self, struct list_head *head, |
1082 | size_t privsize) | ||
1082 | { | 1083 | { |
1083 | struct symbol *sym = self->ms.sym; | 1084 | struct symbol *sym = self->ms.sym; |
1084 | struct map *map = self->ms.map; | 1085 | struct map *map = self->ms.map; |
@@ -1143,7 +1144,7 @@ fallback: | |||
1143 | goto out_free_filename; | 1144 | goto out_free_filename; |
1144 | 1145 | ||
1145 | while (!feof(file)) | 1146 | while (!feof(file)) |
1146 | if (hist_entry__parse_objdump_line(self, file, head) < 0) | 1147 | if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0) |
1147 | break; | 1148 | break; |
1148 | 1149 | ||
1149 | pclose(file); | 1150 | pclose(file); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 65a48db46a29..587d375d3430 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -101,7 +101,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, | |||
101 | bool show_displacement, FILE *fp); | 101 | bool show_displacement, FILE *fp); |
102 | 102 | ||
103 | int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip); | 103 | int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip); |
104 | int hist_entry__annotate(struct hist_entry *self, struct list_head *head); | 104 | int hist_entry__annotate(struct hist_entry *self, struct list_head *head, |
105 | size_t privsize); | ||
105 | 106 | ||
106 | void hists__filter_by_dso(struct hists *self, const struct dso *dso); | 107 | void hists__filter_by_dso(struct hists *self, const struct dso *dso); |
107 | void hists__filter_by_thread(struct hists *self, const struct thread *thread); | 108 | void hists__filter_by_thread(struct hists *self, const struct thread *thread); |
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 5b01df633f9a..763592b09d74 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
@@ -14,6 +14,23 @@ static void ui__error_window(const char *fmt, ...) | |||
14 | va_end(ap); | 14 | va_end(ap); |
15 | } | 15 | } |
16 | 16 | ||
17 | struct annotate_browser { | ||
18 | struct ui_browser b; | ||
19 | struct rb_root entries; | ||
20 | }; | ||
21 | |||
22 | struct objdump_line_rb_node { | ||
23 | struct rb_node rb_node; | ||
24 | double percent; | ||
25 | u32 idx; | ||
26 | }; | ||
27 | |||
28 | static inline | ||
29 | struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) | ||
30 | { | ||
31 | return (struct objdump_line_rb_node *)(self + 1); | ||
32 | } | ||
33 | |||
17 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) | 34 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) |
18 | { | 35 | { |
19 | struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); | 36 | struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); |
@@ -21,17 +38,41 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro | |||
21 | int width = self->width; | 38 | int width = self->width; |
22 | 39 | ||
23 | if (ol->offset != -1) { | 40 | if (ol->offset != -1) { |
24 | struct hist_entry *he = self->priv; | 41 | struct objdump_line_rb_node *olrb = objdump_line__rb(ol); |
25 | struct symbol *sym = he->ms.sym; | 42 | int color = ui_browser__percent_color(olrb->percent, current_entry); |
26 | int len = he->ms.sym->end - he->ms.sym->start; | 43 | SLsmg_set_color(color); |
44 | slsmg_printf(" %7.2f ", olrb->percent); | ||
45 | if (!current_entry) | ||
46 | SLsmg_set_color(HE_COLORSET_CODE); | ||
47 | } else { | ||
48 | int color = ui_browser__percent_color(0, current_entry); | ||
49 | SLsmg_set_color(color); | ||
50 | slsmg_write_nstring(" ", 9); | ||
51 | } | ||
52 | |||
53 | SLsmg_write_char(':'); | ||
54 | slsmg_write_nstring(" ", 8); | ||
55 | if (!*ol->line) | ||
56 | slsmg_write_nstring(" ", width - 18); | ||
57 | else | ||
58 | slsmg_write_nstring(ol->line, width - 18); | ||
59 | } | ||
60 | |||
61 | static double objdump_line__calc_percent(struct objdump_line *self, | ||
62 | struct list_head *head, | ||
63 | struct symbol *sym) | ||
64 | { | ||
65 | double percent = 0.0; | ||
66 | |||
67 | if (self->offset != -1) { | ||
68 | int len = sym->end - sym->start; | ||
27 | unsigned int hits = 0; | 69 | unsigned int hits = 0; |
28 | double percent = 0.0; | ||
29 | int color; | ||
30 | struct sym_priv *priv = symbol__priv(sym); | 70 | struct sym_priv *priv = symbol__priv(sym); |
31 | struct sym_ext *sym_ext = priv->ext; | 71 | struct sym_ext *sym_ext = priv->ext; |
32 | struct sym_hist *h = priv->hist; | 72 | struct sym_hist *h = priv->hist; |
33 | s64 offset = ol->offset; | 73 | s64 offset = self->offset; |
34 | struct objdump_line *next = objdump__get_next_ip_line(self->entries, ol); | 74 | struct objdump_line *next = objdump__get_next_ip_line(head, self); |
75 | |||
35 | 76 | ||
36 | while (offset < (s64)len && | 77 | while (offset < (s64)len && |
37 | (next == NULL || offset < next->offset)) { | 78 | (next == NULL || offset < next->offset)) { |
@@ -45,37 +86,45 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro | |||
45 | 86 | ||
46 | if (sym_ext == NULL && h->sum) | 87 | if (sym_ext == NULL && h->sum) |
47 | percent = 100.0 * hits / h->sum; | 88 | percent = 100.0 * hits / h->sum; |
48 | |||
49 | color = ui_browser__percent_color(percent, current_entry); | ||
50 | SLsmg_set_color(color); | ||
51 | slsmg_printf(" %7.2f ", percent); | ||
52 | if (!current_entry) | ||
53 | SLsmg_set_color(HE_COLORSET_CODE); | ||
54 | } else { | ||
55 | int color = ui_browser__percent_color(0, current_entry); | ||
56 | SLsmg_set_color(color); | ||
57 | slsmg_write_nstring(" ", 9); | ||
58 | } | 89 | } |
59 | 90 | ||
60 | SLsmg_write_char(':'); | 91 | return percent; |
61 | slsmg_write_nstring(" ", 8); | 92 | } |
62 | if (!*ol->line) | 93 | |
63 | slsmg_write_nstring(" ", width - 18); | 94 | static void objdump__insert_line(struct rb_root *self, |
64 | else | 95 | struct objdump_line_rb_node *line) |
65 | slsmg_write_nstring(ol->line, width - 18); | 96 | { |
97 | struct rb_node **p = &self->rb_node; | ||
98 | struct rb_node *parent = NULL; | ||
99 | struct objdump_line_rb_node *l; | ||
100 | |||
101 | while (*p != NULL) { | ||
102 | parent = *p; | ||
103 | l = rb_entry(parent, struct objdump_line_rb_node, rb_node); | ||
104 | if (line->percent < l->percent) | ||
105 | p = &(*p)->rb_left; | ||
106 | else | ||
107 | p = &(*p)->rb_right; | ||
108 | } | ||
109 | rb_link_node(&line->rb_node, parent, p); | ||
110 | rb_insert_color(&line->rb_node, self); | ||
66 | } | 111 | } |
67 | 112 | ||
68 | int hist_entry__tui_annotate(struct hist_entry *self) | 113 | int hist_entry__tui_annotate(struct hist_entry *self) |
69 | { | 114 | { |
70 | struct newtExitStruct es; | 115 | struct newtExitStruct es; |
71 | struct objdump_line *pos, *n; | 116 | struct objdump_line *pos, *n; |
117 | struct objdump_line_rb_node *rbpos; | ||
118 | struct rb_node *nd; | ||
72 | LIST_HEAD(head); | 119 | LIST_HEAD(head); |
73 | struct ui_browser browser = { | 120 | struct annotate_browser browser = { |
74 | .entries = &head, | 121 | .b = { |
75 | .refresh = ui_browser__list_head_refresh, | 122 | .entries = &head, |
76 | .seek = ui_browser__list_head_seek, | 123 | .refresh = ui_browser__list_head_refresh, |
77 | .write = annotate_browser__write, | 124 | .seek = ui_browser__list_head_seek, |
78 | .priv = self, | 125 | .write = annotate_browser__write, |
126 | .priv = self, | ||
127 | }, | ||
79 | }; | 128 | }; |
80 | int ret; | 129 | int ret; |
81 | 130 | ||
@@ -85,7 +134,7 @@ int hist_entry__tui_annotate(struct hist_entry *self) | |||
85 | if (self->ms.map->dso->annotate_warned) | 134 | if (self->ms.map->dso->annotate_warned) |
86 | return -1; | 135 | return -1; |
87 | 136 | ||
88 | if (hist_entry__annotate(self, &head) < 0) { | 137 | if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { |
89 | ui__error_window(ui_helpline__last_msg); | 138 | ui__error_window(ui_helpline__last_msg); |
90 | return -1; | 139 | return -1; |
91 | } | 140 | } |
@@ -94,16 +143,44 @@ int hist_entry__tui_annotate(struct hist_entry *self) | |||
94 | 143 | ||
95 | list_for_each_entry(pos, &head, node) { | 144 | list_for_each_entry(pos, &head, node) { |
96 | size_t line_len = strlen(pos->line); | 145 | size_t line_len = strlen(pos->line); |
97 | if (browser.width < line_len) | 146 | if (browser.b.width < line_len) |
98 | browser.width = line_len; | 147 | browser.b.width = line_len; |
99 | ++browser.nr_entries; | 148 | rbpos = objdump_line__rb(pos); |
149 | rbpos->idx = browser.b.nr_entries++; | ||
150 | rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym); | ||
151 | if (rbpos->percent < 0.01) | ||
152 | continue; | ||
153 | objdump__insert_line(&browser.entries, rbpos); | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Position the browser at the hottest line. | ||
158 | */ | ||
159 | nd = rb_last(&browser.entries); | ||
160 | if (nd != NULL) { | ||
161 | unsigned back; | ||
162 | |||
163 | ui_browser__refresh_dimensions(&browser.b); | ||
164 | back = browser.b.height / 2; | ||
165 | rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node); | ||
166 | pos = ((struct objdump_line *)rbpos) - 1; | ||
167 | browser.b.top_idx = browser.b.index = rbpos->idx; | ||
168 | |||
169 | while (browser.b.top_idx != 0 && back != 0) { | ||
170 | pos = list_entry(pos->node.prev, struct objdump_line, node); | ||
171 | |||
172 | --browser.b.top_idx; | ||
173 | --back; | ||
174 | } | ||
175 | |||
176 | browser.b.top = pos; | ||
100 | } | 177 | } |
101 | 178 | ||
102 | browser.width += 18; /* Percentage */ | 179 | browser.b.width += 18; /* Percentage */ |
103 | ui_browser__show(&browser, self->ms.sym->name); | 180 | ui_browser__show(&browser.b, self->ms.sym->name); |
104 | newtFormAddHotKey(browser.form, ' '); | 181 | newtFormAddHotKey(browser.b.form, ' '); |
105 | ret = ui_browser__run(&browser, &es); | 182 | ret = ui_browser__run(&browser.b, &es); |
106 | newtFormDestroy(browser.form); | 183 | newtFormDestroy(browser.b.form); |
107 | newtPopWindow(); | 184 | newtPopWindow(); |
108 | list_for_each_entry_safe(pos, n, &head, node) { | 185 | list_for_each_entry_safe(pos, n, &head, node) { |
109 | list_del(&pos->node); | 186 | list_del(&pos->node); |