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.c215
1 files changed, 171 insertions, 44 deletions
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 0229723aceb3..0575905d1205 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -1,31 +1,31 @@
1#include "../../util.h"
1#include "../browser.h" 2#include "../browser.h"
2#include "../helpline.h" 3#include "../helpline.h"
3#include "../libslang.h" 4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
4#include "../../annotate.h" 7#include "../../annotate.h"
5#include "../../hist.h" 8#include "../../hist.h"
6#include "../../sort.h" 9#include "../../sort.h"
7#include "../../symbol.h" 10#include "../../symbol.h"
8#include <pthread.h> 11#include <pthread.h>
9 12#include <newt.h>
10static void ui__error_window(const char *fmt, ...)
11{
12 va_list ap;
13
14 va_start(ap, fmt);
15 newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap);
16 va_end(ap);
17}
18 13
19struct annotate_browser { 14struct annotate_browser {
20 struct ui_browser b; 15 struct ui_browser b;
21 struct rb_root entries; 16 struct rb_root entries;
22 struct rb_node *curr_hot; 17 struct rb_node *curr_hot;
18 struct objdump_line *selection;
19 int nr_asm_entries;
20 int nr_entries;
21 bool hide_src_code;
23}; 22};
24 23
25struct objdump_line_rb_node { 24struct objdump_line_rb_node {
26 struct rb_node rb_node; 25 struct rb_node rb_node;
27 double percent; 26 double percent;
28 u32 idx; 27 u32 idx;
28 int idx_asm;
29}; 29};
30 30
31static inline 31static inline
@@ -34,9 +34,22 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
34 return (struct objdump_line_rb_node *)(self + 1); 34 return (struct objdump_line_rb_node *)(self + 1);
35} 35}
36 36
37static bool objdump_line__filter(struct ui_browser *browser, void *entry)
38{
39 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
40
41 if (ab->hide_src_code) {
42 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
43 return ol->offset == -1;
44 }
45
46 return false;
47}
48
37static void annotate_browser__write(struct ui_browser *self, void *entry, int row) 49static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
38{ 50{
39 struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); 51 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
52 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
40 bool current_entry = ui_browser__is_current_entry(self, row); 53 bool current_entry = ui_browser__is_current_entry(self, row);
41 int width = self->width; 54 int width = self->width;
42 55
@@ -51,6 +64,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
51 64
52 SLsmg_write_char(':'); 65 SLsmg_write_char(':');
53 slsmg_write_nstring(" ", 8); 66 slsmg_write_nstring(" ", 8);
67
68 /* The scroll bar isn't being used */
69 if (!self->navkeypressed)
70 width += 1;
71
54 if (!*ol->line) 72 if (!*ol->line)
55 slsmg_write_nstring(" ", width - 18); 73 slsmg_write_nstring(" ", width - 18);
56 else 74 else
@@ -58,6 +76,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
58 76
59 if (!current_entry) 77 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE); 78 ui_browser__set_color(self, HE_COLORSET_CODE);
79 else
80 ab->selection = ol;
61} 81}
62 82
63static double objdump_line__calc_percent(struct objdump_line *self, 83static double objdump_line__calc_percent(struct objdump_line *self,
@@ -141,7 +161,8 @@ static void annotate_browser__set_top(struct annotate_browser *self,
141static void annotate_browser__calc_percent(struct annotate_browser *browser, 161static void annotate_browser__calc_percent(struct annotate_browser *browser,
142 int evidx) 162 int evidx)
143{ 163{
144 struct symbol *sym = browser->b.priv; 164 struct map_symbol *ms = browser->b.priv;
165 struct symbol *sym = ms->sym;
145 struct annotation *notes = symbol__annotation(sym); 166 struct annotation *notes = symbol__annotation(sym);
146 struct objdump_line *pos; 167 struct objdump_line *pos;
147 168
@@ -163,25 +184,60 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
163 browser->curr_hot = rb_last(&browser->entries); 184 browser->curr_hot = rb_last(&browser->entries);
164} 185}
165 186
187static bool annotate_browser__toggle_source(struct annotate_browser *browser)
188{
189 struct objdump_line *ol;
190 struct objdump_line_rb_node *olrb;
191 off_t offset = browser->b.index - browser->b.top_idx;
192
193 browser->b.seek(&browser->b, offset, SEEK_CUR);
194 ol = list_entry(browser->b.top, struct objdump_line, node);
195 olrb = objdump_line__rb(ol);
196
197 if (browser->hide_src_code) {
198 if (olrb->idx_asm < offset)
199 offset = olrb->idx;
200
201 browser->b.nr_entries = browser->nr_entries;
202 browser->hide_src_code = false;
203 browser->b.seek(&browser->b, -offset, SEEK_CUR);
204 browser->b.top_idx = olrb->idx - offset;
205 browser->b.index = olrb->idx;
206 } else {
207 if (olrb->idx_asm < 0) {
208 ui_helpline__puts("Only available for assembly lines.");
209 browser->b.seek(&browser->b, -offset, SEEK_CUR);
210 return false;
211 }
212
213 if (olrb->idx_asm < offset)
214 offset = olrb->idx_asm;
215
216 browser->b.nr_entries = browser->nr_asm_entries;
217 browser->hide_src_code = true;
218 browser->b.seek(&browser->b, -offset, SEEK_CUR);
219 browser->b.top_idx = olrb->idx_asm - offset;
220 browser->b.index = olrb->idx_asm;
221 }
222
223 return true;
224}
225
166static int annotate_browser__run(struct annotate_browser *self, int evidx, 226static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh) 227 int nr_events, void(*timer)(void *arg),
228 void *arg, int delay_secs)
168{ 229{
169 struct rb_node *nd = NULL; 230 struct rb_node *nd = NULL;
170 struct symbol *sym = self->b.priv; 231 struct map_symbol *ms = self->b.priv;
171 /* 232 struct symbol *sym = ms->sym;
172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by 233 const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
173 * examining the exit key for this function. 234 "H: Hottest, -> Line action, S -> Toggle source "
174 */ 235 "code view";
175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 };
177 int key; 236 int key;
178 237
179 if (ui_browser__show(&self->b, sym->name, 238 if (ui_browser__show(&self->b, sym->name, help) < 0)
180 "<-, -> or ESC: exit, TAB/shift+TAB: "
181 "cycle hottest lines, H: Hottest") < 0)
182 return -1; 239 return -1;
183 240
184 ui_browser__add_exit_keys(&self->b, exit_keys);
185 annotate_browser__calc_percent(self, evidx); 241 annotate_browser__calc_percent(self, evidx);
186 242
187 if (self->curr_hot) 243 if (self->curr_hot)
@@ -189,13 +245,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
189 245
190 nd = self->curr_hot; 246 nd = self->curr_hot;
191 247
192 if (refresh != 0)
193 newtFormSetTimer(self->b.form, refresh);
194
195 while (1) { 248 while (1) {
196 key = ui_browser__run(&self->b); 249 key = ui_browser__run(&self->b, delay_secs);
197 250
198 if (refresh != 0) { 251 if (delay_secs != 0) {
199 annotate_browser__calc_percent(self, evidx); 252 annotate_browser__calc_percent(self, evidx);
200 /* 253 /*
201 * Current line focus got out of the list of most active 254 * Current line focus got out of the list of most active
@@ -207,15 +260,14 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
207 } 260 }
208 261
209 switch (key) { 262 switch (key) {
210 case -1: 263 case K_TIMER:
211 /* 264 if (timer != NULL)
212 * FIXME we need to check if it was 265 timer(arg);
213 * es.reason == NEWT_EXIT_TIMER 266
214 */ 267 if (delay_secs != 0)
215 if (refresh != 0)
216 symbol__annotate_decay_histogram(sym, evidx); 268 symbol__annotate_decay_histogram(sym, evidx);
217 continue; 269 continue;
218 case NEWT_KEY_TAB: 270 case K_TAB:
219 if (nd != NULL) { 271 if (nd != NULL) {
220 nd = rb_prev(nd); 272 nd = rb_prev(nd);
221 if (nd == NULL) 273 if (nd == NULL)
@@ -223,7 +275,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
223 } else 275 } else
224 nd = self->curr_hot; 276 nd = self->curr_hot;
225 break; 277 break;
226 case NEWT_KEY_UNTAB: 278 case K_UNTAB:
227 if (nd != NULL) 279 if (nd != NULL)
228 nd = rb_next(nd); 280 nd = rb_next(nd);
229 if (nd == NULL) 281 if (nd == NULL)
@@ -234,8 +286,68 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
234 case 'H': 286 case 'H':
235 nd = self->curr_hot; 287 nd = self->curr_hot;
236 break; 288 break;
237 default: 289 case 'S':
290 if (annotate_browser__toggle_source(self))
291 ui_helpline__puts(help);
292 continue;
293 case K_ENTER:
294 case K_RIGHT:
295 if (self->selection == NULL) {
296 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
297 continue;
298 }
299
300 if (self->selection->offset == -1) {
301 ui_helpline__puts("Actions are only available for assembly lines.");
302 continue;
303 } else {
304 char *s = strstr(self->selection->line, "callq ");
305 struct annotation *notes;
306 struct symbol *target;
307 u64 ip;
308
309 if (s == NULL) {
310 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
311 continue;
312 }
313
314 s = strchr(s, ' ');
315 if (s++ == NULL) {
316 ui_helpline__puts("Invallid callq instruction.");
317 continue;
318 }
319
320 ip = strtoull(s, NULL, 16);
321 ip = ms->map->map_ip(ms->map, ip);
322 target = map__find_symbol(ms->map, ip, NULL);
323 if (target == NULL) {
324 ui_helpline__puts("The called function was not found.");
325 continue;
326 }
327
328 notes = symbol__annotation(target);
329 pthread_mutex_lock(&notes->lock);
330
331 if (notes->src == NULL &&
332 symbol__alloc_hist(target, nr_events) < 0) {
333 pthread_mutex_unlock(&notes->lock);
334 ui__warning("Not enough memory for annotating '%s' symbol!\n",
335 target->name);
336 continue;
337 }
338
339 pthread_mutex_unlock(&notes->lock);
340 symbol__tui_annotate(target, ms->map, evidx, nr_events,
341 timer, arg, delay_secs);
342 }
343 continue;
344 case K_LEFT:
345 case K_ESC:
346 case 'q':
347 case CTRL('c'):
238 goto out; 348 goto out;
349 default:
350 continue;
239 } 351 }
240 352
241 if (nd != NULL) 353 if (nd != NULL)
@@ -246,22 +358,31 @@ out:
246 return key; 358 return key;
247} 359}
248 360
249int hist_entry__tui_annotate(struct hist_entry *he, int evidx) 361int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
362 void(*timer)(void *arg), void *arg, int delay_secs)
250{ 363{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); 364 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events,
365 timer, arg, delay_secs);
252} 366}
253 367
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 368int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh) 369 int nr_events, void(*timer)(void *arg), void *arg,
370 int delay_secs)
256{ 371{
257 struct objdump_line *pos, *n; 372 struct objdump_line *pos, *n;
258 struct annotation *notes; 373 struct annotation *notes;
374 struct map_symbol ms = {
375 .map = map,
376 .sym = sym,
377 };
259 struct annotate_browser browser = { 378 struct annotate_browser browser = {
260 .b = { 379 .b = {
261 .refresh = ui_browser__list_head_refresh, 380 .refresh = ui_browser__list_head_refresh,
262 .seek = ui_browser__list_head_seek, 381 .seek = ui_browser__list_head_seek,
263 .write = annotate_browser__write, 382 .write = annotate_browser__write,
264 .priv = sym, 383 .filter = objdump_line__filter,
384 .priv = &ms,
385 .use_navkeypressed = true,
265 }, 386 },
266 }; 387 };
267 int ret; 388 int ret;
@@ -273,7 +394,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
273 return -1; 394 return -1;
274 395
275 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { 396 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
276 ui__error_window(ui_helpline__last_msg); 397 ui__error("%s", ui_helpline__last_msg);
277 return -1; 398 return -1;
278 } 399 }
279 400
@@ -288,12 +409,18 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
288 if (browser.b.width < line_len) 409 if (browser.b.width < line_len)
289 browser.b.width = line_len; 410 browser.b.width = line_len;
290 rbpos = objdump_line__rb(pos); 411 rbpos = objdump_line__rb(pos);
291 rbpos->idx = browser.b.nr_entries++; 412 rbpos->idx = browser.nr_entries++;
413 if (pos->offset != -1)
414 rbpos->idx_asm = browser.nr_asm_entries++;
415 else
416 rbpos->idx_asm = -1;
292 } 417 }
293 418
419 browser.b.nr_entries = browser.nr_entries;
294 browser.b.entries = &notes->src->source, 420 browser.b.entries = &notes->src->source,
295 browser.b.width += 18; /* Percentage */ 421 browser.b.width += 18; /* Percentage */
296 ret = annotate_browser__run(&browser, evidx, refresh); 422 ret = annotate_browser__run(&browser, evidx, nr_events,
423 timer, arg, delay_secs);
297 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 424 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
298 list_del(&pos->node); 425 list_del(&pos->node);
299 objdump_line__free(pos); 426 objdump_line__free(pos);