aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/ui/browsers/annotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/ui/browsers/annotate.c')
-rw-r--r--tools/perf/util/ui/browsers/annotate.c195
1 files changed, 128 insertions, 67 deletions
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index a90273e63f4f..0229723aceb3 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -1,9 +1,11 @@
1#include "../browser.h" 1#include "../browser.h"
2#include "../helpline.h" 2#include "../helpline.h"
3#include "../libslang.h" 3#include "../libslang.h"
4#include "../../annotate.h"
4#include "../../hist.h" 5#include "../../hist.h"
5#include "../../sort.h" 6#include "../../sort.h"
6#include "../../symbol.h" 7#include "../../symbol.h"
8#include <pthread.h>
7 9
8static void ui__error_window(const char *fmt, ...) 10static void ui__error_window(const char *fmt, ...)
9{ 11{
@@ -40,14 +42,10 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
40 42
41 if (ol->offset != -1) { 43 if (ol->offset != -1) {
42 struct objdump_line_rb_node *olrb = objdump_line__rb(ol); 44 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
43 int color = ui_browser__percent_color(olrb->percent, current_entry); 45 ui_browser__set_percent_color(self, olrb->percent, current_entry);
44 SLsmg_set_color(color);
45 slsmg_printf(" %7.2f ", olrb->percent); 46 slsmg_printf(" %7.2f ", olrb->percent);
46 if (!current_entry)
47 SLsmg_set_color(HE_COLORSET_CODE);
48 } else { 47 } else {
49 int color = ui_browser__percent_color(0, current_entry); 48 ui_browser__set_percent_color(self, 0, current_entry);
50 SLsmg_set_color(color);
51 slsmg_write_nstring(" ", 9); 49 slsmg_write_nstring(" ", 9);
52 } 50 }
53 51
@@ -57,35 +55,40 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
57 slsmg_write_nstring(" ", width - 18); 55 slsmg_write_nstring(" ", width - 18);
58 else 56 else
59 slsmg_write_nstring(ol->line, width - 18); 57 slsmg_write_nstring(ol->line, width - 18);
58
59 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE);
60} 61}
61 62
62static double objdump_line__calc_percent(struct objdump_line *self, 63static double objdump_line__calc_percent(struct objdump_line *self,
63 struct list_head *head, 64 struct symbol *sym, int evidx)
64 struct symbol *sym)
65{ 65{
66 double percent = 0.0; 66 double percent = 0.0;
67 67
68 if (self->offset != -1) { 68 if (self->offset != -1) {
69 int len = sym->end - sym->start; 69 int len = sym->end - sym->start;
70 unsigned int hits = 0; 70 unsigned int hits = 0;
71 struct sym_priv *priv = symbol__priv(sym); 71 struct annotation *notes = symbol__annotation(sym);
72 struct sym_ext *sym_ext = priv->ext; 72 struct source_line *src_line = notes->src->lines;
73 struct sym_hist *h = priv->hist; 73 struct sym_hist *h = annotation__histogram(notes, evidx);
74 s64 offset = self->offset; 74 s64 offset = self->offset;
75 struct objdump_line *next = objdump__get_next_ip_line(head, self); 75 struct objdump_line *next;
76
77 76
77 next = objdump__get_next_ip_line(&notes->src->source, self);
78 while (offset < (s64)len && 78 while (offset < (s64)len &&
79 (next == NULL || offset < next->offset)) { 79 (next == NULL || offset < next->offset)) {
80 if (sym_ext) { 80 if (src_line) {
81 percent += sym_ext[offset].percent; 81 percent += src_line[offset].percent;
82 } else 82 } else
83 hits += h->ip[offset]; 83 hits += h->addr[offset];
84 84
85 ++offset; 85 ++offset;
86 } 86 }
87 87 /*
88 if (sym_ext == NULL && h->sum) 88 * If the percentage wasn't already calculated in
89 * symbol__get_source_line, do it now:
90 */
91 if (src_line == NULL && h->sum)
89 percent = 100.0 * hits / h->sum; 92 percent = 100.0 * hits / h->sum;
90 } 93 }
91 94
@@ -135,105 +138,163 @@ static void annotate_browser__set_top(struct annotate_browser *self,
135 self->curr_hot = nd; 138 self->curr_hot = nd;
136} 139}
137 140
138static int annotate_browser__run(struct annotate_browser *self, 141static void annotate_browser__calc_percent(struct annotate_browser *browser,
139 struct newtExitStruct *es) 142 int evidx)
143{
144 struct symbol *sym = browser->b.priv;
145 struct annotation *notes = symbol__annotation(sym);
146 struct objdump_line *pos;
147
148 browser->entries = RB_ROOT;
149
150 pthread_mutex_lock(&notes->lock);
151
152 list_for_each_entry(pos, &notes->src->source, node) {
153 struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
154 rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
155 if (rbpos->percent < 0.01) {
156 RB_CLEAR_NODE(&rbpos->rb_node);
157 continue;
158 }
159 objdump__insert_line(&browser->entries, rbpos);
160 }
161 pthread_mutex_unlock(&notes->lock);
162
163 browser->curr_hot = rb_last(&browser->entries);
164}
165
166static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh)
140{ 168{
141 struct rb_node *nd; 169 struct rb_node *nd = NULL;
142 struct hist_entry *he = self->b.priv; 170 struct symbol *sym = self->b.priv;
171 /*
172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by
173 * examining the exit key for this function.
174 */
175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 };
177 int key;
143 178
144 if (ui_browser__show(&self->b, he->ms.sym->name, 179 if (ui_browser__show(&self->b, sym->name,
145 "<- or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) 180 "<-, -> or ESC: exit, TAB/shift+TAB: "
181 "cycle hottest lines, H: Hottest") < 0)
146 return -1; 182 return -1;
147 183
148 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT); 184 ui_browser__add_exit_keys(&self->b, exit_keys);
149 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT); 185 annotate_browser__calc_percent(self, evidx);
186
187 if (self->curr_hot)
188 annotate_browser__set_top(self, self->curr_hot);
150 189
151 nd = self->curr_hot; 190 nd = self->curr_hot;
152 if (nd) {
153 newtFormAddHotKey(self->b.form, NEWT_KEY_TAB);
154 newtFormAddHotKey(self->b.form, NEWT_KEY_UNTAB);
155 }
156 191
157 while (1) { 192 if (refresh != 0)
158 ui_browser__run(&self->b, es); 193 newtFormSetTimer(self->b.form, refresh);
159 194
160 if (es->reason != NEWT_EXIT_HOTKEY) 195 while (1) {
161 break; 196 key = ui_browser__run(&self->b);
197
198 if (refresh != 0) {
199 annotate_browser__calc_percent(self, evidx);
200 /*
201 * Current line focus got out of the list of most active
202 * lines, NULL it so that if TAB|UNTAB is pressed, we
203 * move to curr_hot (current hottest line).
204 */
205 if (nd != NULL && RB_EMPTY_NODE(nd))
206 nd = NULL;
207 }
162 208
163 switch (es->u.key) { 209 switch (key) {
210 case -1:
211 /*
212 * FIXME we need to check if it was
213 * es.reason == NEWT_EXIT_TIMER
214 */
215 if (refresh != 0)
216 symbol__annotate_decay_histogram(sym, evidx);
217 continue;
164 case NEWT_KEY_TAB: 218 case NEWT_KEY_TAB:
165 nd = rb_prev(nd); 219 if (nd != NULL) {
166 if (nd == NULL) 220 nd = rb_prev(nd);
167 nd = rb_last(&self->entries); 221 if (nd == NULL)
168 annotate_browser__set_top(self, nd); 222 nd = rb_last(&self->entries);
223 } else
224 nd = self->curr_hot;
169 break; 225 break;
170 case NEWT_KEY_UNTAB: 226 case NEWT_KEY_UNTAB:
171 nd = rb_next(nd); 227 if (nd != NULL)
172 if (nd == NULL) 228 nd = rb_next(nd);
173 nd = rb_first(&self->entries); 229 if (nd == NULL)
174 annotate_browser__set_top(self, nd); 230 nd = rb_first(&self->entries);
231 else
232 nd = self->curr_hot;
233 break;
234 case 'H':
235 nd = self->curr_hot;
175 break; 236 break;
176 default: 237 default:
177 goto out; 238 goto out;
178 } 239 }
240
241 if (nd != NULL)
242 annotate_browser__set_top(self, nd);
179 } 243 }
180out: 244out:
181 ui_browser__hide(&self->b); 245 ui_browser__hide(&self->b);
182 return es->u.key; 246 return key;
183} 247}
184 248
185int hist_entry__tui_annotate(struct hist_entry *self) 249int hist_entry__tui_annotate(struct hist_entry *he, int evidx)
250{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0);
252}
253
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh)
186{ 256{
187 struct newtExitStruct es;
188 struct objdump_line *pos, *n; 257 struct objdump_line *pos, *n;
189 struct objdump_line_rb_node *rbpos; 258 struct annotation *notes;
190 LIST_HEAD(head);
191 struct annotate_browser browser = { 259 struct annotate_browser browser = {
192 .b = { 260 .b = {
193 .entries = &head,
194 .refresh = ui_browser__list_head_refresh, 261 .refresh = ui_browser__list_head_refresh,
195 .seek = ui_browser__list_head_seek, 262 .seek = ui_browser__list_head_seek,
196 .write = annotate_browser__write, 263 .write = annotate_browser__write,
197 .priv = self, 264 .priv = sym,
198 }, 265 },
199 }; 266 };
200 int ret; 267 int ret;
201 268
202 if (self->ms.sym == NULL) 269 if (sym == NULL)
203 return -1; 270 return -1;
204 271
205 if (self->ms.map->dso->annotate_warned) 272 if (map->dso->annotate_warned)
206 return -1; 273 return -1;
207 274
208 if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { 275 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
209 ui__error_window(ui_helpline__last_msg); 276 ui__error_window(ui_helpline__last_msg);
210 return -1; 277 return -1;
211 } 278 }
212 279
213 ui_helpline__push("Press <- or ESC to exit"); 280 ui_helpline__push("Press <- or ESC to exit");
214 281
215 list_for_each_entry(pos, &head, node) { 282 notes = symbol__annotation(sym);
283
284 list_for_each_entry(pos, &notes->src->source, node) {
285 struct objdump_line_rb_node *rbpos;
216 size_t line_len = strlen(pos->line); 286 size_t line_len = strlen(pos->line);
287
217 if (browser.b.width < line_len) 288 if (browser.b.width < line_len)
218 browser.b.width = line_len; 289 browser.b.width = line_len;
219 rbpos = objdump_line__rb(pos); 290 rbpos = objdump_line__rb(pos);
220 rbpos->idx = browser.b.nr_entries++; 291 rbpos->idx = browser.b.nr_entries++;
221 rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym);
222 if (rbpos->percent < 0.01)
223 continue;
224 objdump__insert_line(&browser.entries, rbpos);
225 } 292 }
226 293
227 /* 294 browser.b.entries = &notes->src->source,
228 * Position the browser at the hottest line.
229 */
230 browser.curr_hot = rb_last(&browser.entries);
231 if (browser.curr_hot)
232 annotate_browser__set_top(&browser, browser.curr_hot);
233
234 browser.b.width += 18; /* Percentage */ 295 browser.b.width += 18; /* Percentage */
235 ret = annotate_browser__run(&browser, &es); 296 ret = annotate_browser__run(&browser, evidx, refresh);
236 list_for_each_entry_safe(pos, n, &head, node) { 297 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
237 list_del(&pos->node); 298 list_del(&pos->node);
238 objdump_line__free(pos); 299 objdump_line__free(pos);
239 } 300 }