1 #include "../../util/util.h"
2 #include "../browser.h"
3 #include "../helpline.h"
6 #include "../../util/annotate.h"
7 #include "../../util/hist.h"
8 #include "../../util/sort.h"
9 #include "../../util/symbol.h"
10 #include "../../util/evsel.h"
11 #include "../../util/config.h"
14 #include <linux/kernel.h>
15 #include <sys/ttydefaults.h>
17 struct disasm_line_samples
{
23 #define CYCLES_WIDTH 6
25 struct browser_disasm_line
{
26 struct rb_node rb_node
;
31 * actual length of this array is saved on the nr_events field
32 * of the struct annotate_browser
34 struct disasm_line_samples samples
[1];
37 static struct annotate_browser_opt
{
44 } annotate_browser__opts
= {
49 struct annotate_browser
{
51 struct rb_root entries
;
52 struct rb_node
*curr_hot
;
53 struct disasm_line
*selection
;
54 struct disasm_line
**offsets
;
61 bool searching_backwards
;
71 static inline struct browser_disasm_line
*disasm_line__browser(struct disasm_line
*dl
)
73 return (struct browser_disasm_line
*)(dl
+ 1);
76 static bool disasm_line__filter(struct ui_browser
*browser __maybe_unused
,
79 if (annotate_browser__opts
.hide_src_code
) {
80 struct disasm_line
*dl
= list_entry(entry
, struct disasm_line
, node
);
81 return dl
->offset
== -1;
87 static int annotate_browser__jumps_percent_color(struct annotate_browser
*browser
,
90 if (current
&& (!browser
->b
.use_navkeypressed
|| browser
->b
.navkeypressed
))
91 return HE_COLORSET_SELECTED
;
92 if (nr
== browser
->max_jump_sources
)
93 return HE_COLORSET_TOP
;
95 return HE_COLORSET_MEDIUM
;
96 return HE_COLORSET_NORMAL
;
99 static int annotate_browser__set_jumps_percent_color(struct annotate_browser
*browser
,
100 int nr
, bool current
)
102 int color
= annotate_browser__jumps_percent_color(browser
, nr
, current
);
103 return ui_browser__set_color(&browser
->b
, color
);
106 static int annotate_browser__pcnt_width(struct annotate_browser
*ab
)
108 int w
= 7 * ab
->nr_events
;
111 w
+= IPC_WIDTH
+ CYCLES_WIDTH
;
115 static void annotate_browser__write(struct ui_browser
*browser
, void *entry
, int row
)
117 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
118 struct disasm_line
*dl
= list_entry(entry
, struct disasm_line
, node
);
119 struct browser_disasm_line
*bdl
= disasm_line__browser(dl
);
120 bool current_entry
= ui_browser__is_current_entry(browser
, row
);
121 bool change_color
= (!annotate_browser__opts
.hide_src_code
&&
122 (!current_entry
|| (browser
->use_navkeypressed
&&
123 !browser
->navkeypressed
)));
124 int width
= browser
->width
, printed
;
125 int i
, pcnt_width
= annotate_browser__pcnt_width(ab
);
126 double percent_max
= 0.0;
128 bool show_title
= false;
130 for (i
= 0; i
< ab
->nr_events
; i
++) {
131 if (bdl
->samples
[i
].percent
> percent_max
)
132 percent_max
= bdl
->samples
[i
].percent
;
135 if ((row
== 0) && (dl
->offset
== -1 || percent_max
== 0.0)) {
136 if (ab
->have_cycles
) {
137 if (dl
->ipc
== 0.0 && dl
->cycles
== 0)
143 if (dl
->offset
!= -1 && percent_max
!= 0.0) {
144 for (i
= 0; i
< ab
->nr_events
; i
++) {
145 ui_browser__set_percent_color(browser
,
146 bdl
->samples
[i
].percent
,
148 if (annotate_browser__opts
.show_total_period
) {
149 ui_browser__printf(browser
, "%6" PRIu64
" ",
152 ui_browser__printf(browser
, "%6.2f ",
153 bdl
->samples
[i
].percent
);
157 ui_browser__set_percent_color(browser
, 0, current_entry
);
160 ui_browser__write_nstring(browser
, " ", 7 * ab
->nr_events
);
162 ui_browser__printf(browser
, "%*s", 7, "Percent");
164 if (ab
->have_cycles
) {
166 ui_browser__printf(browser
, "%*.2f ", IPC_WIDTH
- 1, dl
->ipc
);
167 else if (!show_title
)
168 ui_browser__write_nstring(browser
, " ", IPC_WIDTH
);
170 ui_browser__printf(browser
, "%*s ", IPC_WIDTH
- 1, "IPC");
173 ui_browser__printf(browser
, "%*" PRIu64
" ",
174 CYCLES_WIDTH
- 1, dl
->cycles
);
175 else if (!show_title
)
176 ui_browser__write_nstring(browser
, " ", CYCLES_WIDTH
);
178 ui_browser__printf(browser
, "%*s ", CYCLES_WIDTH
- 1, "Cycle");
181 SLsmg_write_char(' ');
183 /* The scroll bar isn't being used */
184 if (!browser
->navkeypressed
)
188 ui_browser__write_nstring(browser
, " ", width
- pcnt_width
);
189 else if (dl
->offset
== -1) {
190 if (dl
->line_nr
&& annotate_browser__opts
.show_linenr
)
191 printed
= scnprintf(bf
, sizeof(bf
), "%-*d ",
192 ab
->addr_width
+ 1, dl
->line_nr
);
194 printed
= scnprintf(bf
, sizeof(bf
), "%*s ",
195 ab
->addr_width
, " ");
196 ui_browser__write_nstring(browser
, bf
, printed
);
197 ui_browser__write_nstring(browser
, dl
->line
, width
- printed
- pcnt_width
+ 1);
199 u64 addr
= dl
->offset
;
202 if (!annotate_browser__opts
.use_offset
)
205 if (!annotate_browser__opts
.use_offset
) {
206 printed
= scnprintf(bf
, sizeof(bf
), "%" PRIx64
": ", addr
);
208 if (bdl
->jump_sources
) {
209 if (annotate_browser__opts
.show_nr_jumps
) {
211 printed
= scnprintf(bf
, sizeof(bf
), "%*d ",
214 prev
= annotate_browser__set_jumps_percent_color(ab
, bdl
->jump_sources
,
216 ui_browser__write_nstring(browser
, bf
, printed
);
217 ui_browser__set_color(browser
, prev
);
220 printed
= scnprintf(bf
, sizeof(bf
), "%*" PRIx64
": ",
221 ab
->target_width
, addr
);
223 printed
= scnprintf(bf
, sizeof(bf
), "%*s ",
224 ab
->addr_width
, " ");
229 color
= ui_browser__set_color(browser
, HE_COLORSET_ADDR
);
230 ui_browser__write_nstring(browser
, bf
, printed
);
232 ui_browser__set_color(browser
, color
);
233 if (dl
->ins
.ops
&& dl
->ins
.ops
->scnprintf
) {
234 if (ins__is_jump(&dl
->ins
)) {
235 bool fwd
= dl
->ops
.target
.offset
> dl
->offset
;
237 ui_browser__write_graph(browser
, fwd
? SLSMG_DARROW_CHAR
:
239 SLsmg_write_char(' ');
240 } else if (ins__is_call(&dl
->ins
)) {
241 ui_browser__write_graph(browser
, SLSMG_RARROW_CHAR
);
242 SLsmg_write_char(' ');
243 } else if (ins__is_ret(&dl
->ins
)) {
244 ui_browser__write_graph(browser
, SLSMG_LARROW_CHAR
);
245 SLsmg_write_char(' ');
247 ui_browser__write_nstring(browser
, " ", 2);
250 ui_browser__write_nstring(browser
, " ", 2);
253 disasm_line__scnprintf(dl
, bf
, sizeof(bf
), !annotate_browser__opts
.use_offset
);
254 ui_browser__write_nstring(browser
, bf
, width
- pcnt_width
- 3 - printed
);
261 static bool disasm_line__is_valid_jump(struct disasm_line
*dl
, struct symbol
*sym
)
263 if (!dl
|| !dl
->ins
.ops
|| !ins__is_jump(&dl
->ins
)
264 || !disasm_line__has_offset(dl
)
265 || dl
->ops
.target
.offset
< 0
266 || dl
->ops
.target
.offset
>= (s64
)symbol__size(sym
))
272 static void annotate_browser__draw_current_jump(struct ui_browser
*browser
)
274 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
275 struct disasm_line
*cursor
= ab
->selection
, *target
;
276 struct browser_disasm_line
*btarget
, *bcursor
;
277 unsigned int from
, to
;
278 struct map_symbol
*ms
= ab
->b
.priv
;
279 struct symbol
*sym
= ms
->sym
;
280 u8 pcnt_width
= annotate_browser__pcnt_width(ab
);
282 /* PLT symbols contain external offsets */
283 if (strstr(sym
->name
, "@plt"))
286 if (!disasm_line__is_valid_jump(cursor
, sym
))
289 target
= ab
->offsets
[cursor
->ops
.target
.offset
];
293 bcursor
= disasm_line__browser(cursor
);
294 btarget
= disasm_line__browser(target
);
296 if (annotate_browser__opts
.hide_src_code
) {
297 from
= bcursor
->idx_asm
;
298 to
= btarget
->idx_asm
;
300 from
= (u64
)bcursor
->idx
;
301 to
= (u64
)btarget
->idx
;
304 ui_browser__set_color(browser
, HE_COLORSET_JUMP_ARROWS
);
305 __ui_browser__line_arrow(browser
, pcnt_width
+ 2 + ab
->addr_width
,
309 static unsigned int annotate_browser__refresh(struct ui_browser
*browser
)
311 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
312 int ret
= ui_browser__list_head_refresh(browser
);
313 int pcnt_width
= annotate_browser__pcnt_width(ab
);
315 if (annotate_browser__opts
.jump_arrows
)
316 annotate_browser__draw_current_jump(browser
);
318 ui_browser__set_color(browser
, HE_COLORSET_NORMAL
);
319 __ui_browser__vline(browser
, pcnt_width
, 0, browser
->height
- 1);
323 static int disasm__cmp(struct browser_disasm_line
*a
,
324 struct browser_disasm_line
*b
, int nr_pcnt
)
328 for (i
= 0; i
< nr_pcnt
; i
++) {
329 if (a
->samples
[i
].percent
== b
->samples
[i
].percent
)
331 return a
->samples
[i
].percent
< b
->samples
[i
].percent
;
336 static void disasm_rb_tree__insert(struct rb_root
*root
, struct browser_disasm_line
*bdl
,
339 struct rb_node
**p
= &root
->rb_node
;
340 struct rb_node
*parent
= NULL
;
341 struct browser_disasm_line
*l
;
345 l
= rb_entry(parent
, struct browser_disasm_line
, rb_node
);
347 if (disasm__cmp(bdl
, l
, nr_events
))
352 rb_link_node(&bdl
->rb_node
, parent
, p
);
353 rb_insert_color(&bdl
->rb_node
, root
);
356 static void annotate_browser__set_top(struct annotate_browser
*browser
,
357 struct disasm_line
*pos
, u32 idx
)
361 ui_browser__refresh_dimensions(&browser
->b
);
362 back
= browser
->b
.height
/ 2;
363 browser
->b
.top_idx
= browser
->b
.index
= idx
;
365 while (browser
->b
.top_idx
!= 0 && back
!= 0) {
366 pos
= list_entry(pos
->node
.prev
, struct disasm_line
, node
);
368 if (disasm_line__filter(&browser
->b
, &pos
->node
))
371 --browser
->b
.top_idx
;
375 browser
->b
.top
= pos
;
376 browser
->b
.navkeypressed
= true;
379 static void annotate_browser__set_rb_top(struct annotate_browser
*browser
,
382 struct browser_disasm_line
*bpos
;
383 struct disasm_line
*pos
;
386 bpos
= rb_entry(nd
, struct browser_disasm_line
, rb_node
);
387 pos
= ((struct disasm_line
*)bpos
) - 1;
389 if (annotate_browser__opts
.hide_src_code
)
391 annotate_browser__set_top(browser
, pos
, idx
);
392 browser
->curr_hot
= nd
;
395 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
396 struct perf_evsel
*evsel
)
398 struct map_symbol
*ms
= browser
->b
.priv
;
399 struct symbol
*sym
= ms
->sym
;
400 struct annotation
*notes
= symbol__annotation(sym
);
401 struct disasm_line
*pos
, *next
;
402 s64 len
= symbol__size(sym
);
404 browser
->entries
= RB_ROOT
;
406 pthread_mutex_lock(¬es
->lock
);
408 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
409 struct browser_disasm_line
*bpos
= disasm_line__browser(pos
);
410 const char *path
= NULL
;
411 double max_percent
= 0.0;
414 if (pos
->offset
== -1) {
415 RB_CLEAR_NODE(&bpos
->rb_node
);
419 next
= disasm__get_next_ip_line(¬es
->src
->source
, pos
);
421 for (i
= 0; i
< browser
->nr_events
; i
++) {
424 bpos
->samples
[i
].percent
= disasm__calc_percent(notes
,
427 next
? next
->offset
: len
,
429 bpos
->samples
[i
].nr
= nr_samples
;
431 if (max_percent
< bpos
->samples
[i
].percent
)
432 max_percent
= bpos
->samples
[i
].percent
;
435 if (max_percent
< 0.01 && pos
->ipc
== 0) {
436 RB_CLEAR_NODE(&bpos
->rb_node
);
439 disasm_rb_tree__insert(&browser
->entries
, bpos
,
442 pthread_mutex_unlock(¬es
->lock
);
444 browser
->curr_hot
= rb_last(&browser
->entries
);
447 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
449 struct disasm_line
*dl
;
450 struct browser_disasm_line
*bdl
;
451 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
453 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
454 dl
= list_entry(browser
->b
.top
, struct disasm_line
, node
);
455 bdl
= disasm_line__browser(dl
);
457 if (annotate_browser__opts
.hide_src_code
) {
458 if (bdl
->idx_asm
< offset
)
461 browser
->b
.nr_entries
= browser
->nr_entries
;
462 annotate_browser__opts
.hide_src_code
= false;
463 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
464 browser
->b
.top_idx
= bdl
->idx
- offset
;
465 browser
->b
.index
= bdl
->idx
;
467 if (bdl
->idx_asm
< 0) {
468 ui_helpline__puts("Only available for assembly lines.");
469 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
473 if (bdl
->idx_asm
< offset
)
474 offset
= bdl
->idx_asm
;
476 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
477 annotate_browser__opts
.hide_src_code
= true;
478 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
479 browser
->b
.top_idx
= bdl
->idx_asm
- offset
;
480 browser
->b
.index
= bdl
->idx_asm
;
486 static void annotate_browser__init_asm_mode(struct annotate_browser
*browser
)
488 ui_browser__reset_index(&browser
->b
);
489 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
492 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
494 static int sym_title(struct symbol
*sym
, struct map
*map
, char *title
,
497 return snprintf(title
, sz
, "%s %s", sym
->name
, map
->dso
->long_name
);
500 static bool annotate_browser__callq(struct annotate_browser
*browser
,
501 struct perf_evsel
*evsel
,
502 struct hist_browser_timer
*hbt
)
504 struct map_symbol
*ms
= browser
->b
.priv
;
505 struct disasm_line
*dl
= browser
->selection
;
506 struct annotation
*notes
;
507 struct addr_map_symbol target
= {
509 .addr
= map__objdump_2mem(ms
->map
, dl
->ops
.target
.addr
),
511 char title
[SYM_TITLE_MAX_SIZE
];
513 if (!ins__is_call(&dl
->ins
))
516 if (map_groups__find_ams(&target
) ||
517 map__rip_2objdump(target
.map
, target
.map
->map_ip(target
.map
,
519 dl
->ops
.target
.addr
) {
520 ui_helpline__puts("The called function was not found.");
524 notes
= symbol__annotation(target
.sym
);
525 pthread_mutex_lock(¬es
->lock
);
527 if (notes
->src
== NULL
&& symbol__alloc_hist(target
.sym
) < 0) {
528 pthread_mutex_unlock(¬es
->lock
);
529 ui__warning("Not enough memory for annotating '%s' symbol!\n",
534 pthread_mutex_unlock(¬es
->lock
);
535 symbol__tui_annotate(target
.sym
, target
.map
, evsel
, hbt
);
536 sym_title(ms
->sym
, ms
->map
, title
, sizeof(title
));
537 ui_browser__show_title(&browser
->b
, title
);
542 struct disasm_line
*annotate_browser__find_offset(struct annotate_browser
*browser
,
543 s64 offset
, s64
*idx
)
545 struct map_symbol
*ms
= browser
->b
.priv
;
546 struct symbol
*sym
= ms
->sym
;
547 struct annotation
*notes
= symbol__annotation(sym
);
548 struct disasm_line
*pos
;
551 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
552 if (pos
->offset
== offset
)
554 if (!disasm_line__filter(&browser
->b
, &pos
->node
))
561 static bool annotate_browser__jump(struct annotate_browser
*browser
)
563 struct disasm_line
*dl
= browser
->selection
;
567 if (!ins__is_jump(&dl
->ins
))
570 offset
= dl
->ops
.target
.offset
;
571 dl
= annotate_browser__find_offset(browser
, offset
, &idx
);
573 ui_helpline__printf("Invalid jump offset: %" PRIx64
, offset
);
577 annotate_browser__set_top(browser
, dl
, idx
);
583 struct disasm_line
*annotate_browser__find_string(struct annotate_browser
*browser
,
586 struct map_symbol
*ms
= browser
->b
.priv
;
587 struct symbol
*sym
= ms
->sym
;
588 struct annotation
*notes
= symbol__annotation(sym
);
589 struct disasm_line
*pos
= browser
->selection
;
591 *idx
= browser
->b
.index
;
592 list_for_each_entry_continue(pos
, ¬es
->src
->source
, node
) {
593 if (disasm_line__filter(&browser
->b
, &pos
->node
))
598 if (pos
->line
&& strstr(pos
->line
, s
) != NULL
)
605 static bool __annotate_browser__search(struct annotate_browser
*browser
)
607 struct disasm_line
*dl
;
610 dl
= annotate_browser__find_string(browser
, browser
->search_bf
, &idx
);
612 ui_helpline__puts("String not found!");
616 annotate_browser__set_top(browser
, dl
, idx
);
617 browser
->searching_backwards
= false;
622 struct disasm_line
*annotate_browser__find_string_reverse(struct annotate_browser
*browser
,
625 struct map_symbol
*ms
= browser
->b
.priv
;
626 struct symbol
*sym
= ms
->sym
;
627 struct annotation
*notes
= symbol__annotation(sym
);
628 struct disasm_line
*pos
= browser
->selection
;
630 *idx
= browser
->b
.index
;
631 list_for_each_entry_continue_reverse(pos
, ¬es
->src
->source
, node
) {
632 if (disasm_line__filter(&browser
->b
, &pos
->node
))
637 if (pos
->line
&& strstr(pos
->line
, s
) != NULL
)
644 static bool __annotate_browser__search_reverse(struct annotate_browser
*browser
)
646 struct disasm_line
*dl
;
649 dl
= annotate_browser__find_string_reverse(browser
, browser
->search_bf
, &idx
);
651 ui_helpline__puts("String not found!");
655 annotate_browser__set_top(browser
, dl
, idx
);
656 browser
->searching_backwards
= true;
660 static bool annotate_browser__search_window(struct annotate_browser
*browser
,
663 if (ui_browser__input_window("Search", "String: ", browser
->search_bf
,
664 "ENTER: OK, ESC: Cancel",
665 delay_secs
* 2) != K_ENTER
||
666 !*browser
->search_bf
)
672 static bool annotate_browser__search(struct annotate_browser
*browser
, int delay_secs
)
674 if (annotate_browser__search_window(browser
, delay_secs
))
675 return __annotate_browser__search(browser
);
680 static bool annotate_browser__continue_search(struct annotate_browser
*browser
,
683 if (!*browser
->search_bf
)
684 return annotate_browser__search(browser
, delay_secs
);
686 return __annotate_browser__search(browser
);
689 static bool annotate_browser__search_reverse(struct annotate_browser
*browser
,
692 if (annotate_browser__search_window(browser
, delay_secs
))
693 return __annotate_browser__search_reverse(browser
);
699 bool annotate_browser__continue_search_reverse(struct annotate_browser
*browser
,
702 if (!*browser
->search_bf
)
703 return annotate_browser__search_reverse(browser
, delay_secs
);
705 return __annotate_browser__search_reverse(browser
);
708 static void annotate_browser__update_addr_width(struct annotate_browser
*browser
)
710 if (annotate_browser__opts
.use_offset
)
711 browser
->target_width
= browser
->min_addr_width
;
713 browser
->target_width
= browser
->max_addr_width
;
715 browser
->addr_width
= browser
->target_width
;
717 if (annotate_browser__opts
.show_nr_jumps
)
718 browser
->addr_width
+= browser
->jumps_width
+ 1;
721 static int annotate_browser__run(struct annotate_browser
*browser
,
722 struct perf_evsel
*evsel
,
723 struct hist_browser_timer
*hbt
)
725 struct rb_node
*nd
= NULL
;
726 struct map_symbol
*ms
= browser
->b
.priv
;
727 struct symbol
*sym
= ms
->sym
;
728 const char *help
= "Press 'h' for help on key bindings";
729 int delay_secs
= hbt
? hbt
->refresh
: 0;
731 char title
[SYM_TITLE_MAX_SIZE
];
733 sym_title(sym
, ms
->map
, title
, sizeof(title
));
734 if (ui_browser__show(&browser
->b
, title
, help
) < 0)
737 annotate_browser__calc_percent(browser
, evsel
);
739 if (browser
->curr_hot
) {
740 annotate_browser__set_rb_top(browser
, browser
->curr_hot
);
741 browser
->b
.navkeypressed
= false;
744 nd
= browser
->curr_hot
;
747 key
= ui_browser__run(&browser
->b
, delay_secs
);
749 if (delay_secs
!= 0) {
750 annotate_browser__calc_percent(browser
, evsel
);
752 * Current line focus got out of the list of most active
753 * lines, NULL it so that if TAB|UNTAB is pressed, we
754 * move to curr_hot (current hottest line).
756 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
763 hbt
->timer(hbt
->arg
);
766 symbol__annotate_decay_histogram(sym
, evsel
->idx
);
772 nd
= rb_last(&browser
->entries
);
774 nd
= browser
->curr_hot
;
780 nd
= rb_first(&browser
->entries
);
782 nd
= browser
->curr_hot
;
786 ui_browser__help_window(&browser
->b
,
788 "PGDN/SPACE Navigate\n"
789 "q/ESC/CTRL+C Exit\n\n"
790 "ENTER Go to target\n"
792 "H Cycle thru hottest instructions\n"
793 "j Toggle showing jump to target arrows\n"
794 "J Toggle showing number of jump sources on targets\n"
795 "n Search next string\n"
796 "o Toggle disassembler output/simplified view\n"
797 "s Toggle source code view\n"
798 "t Toggle total period view\n"
800 "k Toggle line numbers\n"
801 "r Run available scripts\n"
802 "? Search string backwards\n");
810 annotate_browser__opts
.show_linenr
=
811 !annotate_browser__opts
.show_linenr
;
814 nd
= browser
->curr_hot
;
817 if (annotate_browser__toggle_source(browser
))
818 ui_helpline__puts(help
);
821 annotate_browser__opts
.use_offset
= !annotate_browser__opts
.use_offset
;
822 annotate_browser__update_addr_width(browser
);
825 annotate_browser__opts
.jump_arrows
= !annotate_browser__opts
.jump_arrows
;
828 annotate_browser__opts
.show_nr_jumps
= !annotate_browser__opts
.show_nr_jumps
;
829 annotate_browser__update_addr_width(browser
);
832 if (annotate_browser__search(browser
, delay_secs
)) {
834 ui_helpline__puts(help
);
838 if (browser
->searching_backwards
?
839 annotate_browser__continue_search_reverse(browser
, delay_secs
) :
840 annotate_browser__continue_search(browser
, delay_secs
))
844 if (annotate_browser__search_reverse(browser
, delay_secs
))
850 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
851 seq
++, browser
->b
.nr_entries
,
855 browser
->nr_asm_entries
);
860 if (browser
->selection
== NULL
)
861 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
862 else if (browser
->selection
->offset
== -1)
863 ui_helpline__puts("Actions are only available for assembly lines.");
864 else if (!browser
->selection
->ins
.ops
)
866 else if (ins__is_ret(&browser
->selection
->ins
))
868 else if (!(annotate_browser__jump(browser
) ||
869 annotate_browser__callq(browser
, evsel
, hbt
))) {
871 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
875 annotate_browser__opts
.show_total_period
=
876 !annotate_browser__opts
.show_total_period
;
877 annotate_browser__update_addr_width(browser
);
889 annotate_browser__set_rb_top(browser
, nd
);
892 ui_browser__hide(&browser
->b
);
896 int map_symbol__tui_annotate(struct map_symbol
*ms
, struct perf_evsel
*evsel
,
897 struct hist_browser_timer
*hbt
)
899 /* Set default value for show_total_period. */
900 annotate_browser__opts
.show_total_period
=
901 symbol_conf
.show_total_period
;
903 return symbol__tui_annotate(ms
->sym
, ms
->map
, evsel
, hbt
);
906 int hist_entry__tui_annotate(struct hist_entry
*he
, struct perf_evsel
*evsel
,
907 struct hist_browser_timer
*hbt
)
909 /* reset abort key so that it can get Ctrl-C as a key */
911 SLang_init_tty(0, 0, 0);
913 return map_symbol__tui_annotate(&he
->ms
, evsel
, hbt
);
917 static unsigned count_insn(struct annotate_browser
*browser
, u64 start
, u64 end
)
922 for (offset
= start
; offset
<= end
; offset
++) {
923 if (browser
->offsets
[offset
])
929 static void count_and_fill(struct annotate_browser
*browser
, u64 start
, u64 end
,
935 n_insn
= count_insn(browser
, start
, end
);
936 if (n_insn
&& ch
->num
&& ch
->cycles
) {
937 float ipc
= n_insn
/ ((double)ch
->cycles
/ (double)ch
->num
);
939 /* Hide data when there are too many overlaps. */
940 if (ch
->reset
>= 0x7fff || ch
->reset
>= ch
->num
/ 2)
943 for (offset
= start
; offset
<= end
; offset
++) {
944 struct disasm_line
*dl
= browser
->offsets
[offset
];
953 * This should probably be in util/annotate.c to share with the tty
954 * annotate, but right now we need the per byte offsets arrays,
955 * which are only here.
957 static void annotate__compute_ipc(struct annotate_browser
*browser
, size_t size
,
961 struct annotation
*notes
= symbol__annotation(sym
);
963 if (!notes
->src
|| !notes
->src
->cycles_hist
)
966 pthread_mutex_lock(¬es
->lock
);
967 for (offset
= 0; offset
< size
; ++offset
) {
970 ch
= ¬es
->src
->cycles_hist
[offset
];
971 if (ch
&& ch
->cycles
) {
972 struct disasm_line
*dl
;
975 count_and_fill(browser
, ch
->start
, offset
, ch
);
976 dl
= browser
->offsets
[offset
];
977 if (dl
&& ch
->num_aggr
)
978 dl
->cycles
= ch
->cycles_aggr
/ ch
->num_aggr
;
979 browser
->have_cycles
= true;
982 pthread_mutex_unlock(¬es
->lock
);
985 static void annotate_browser__mark_jump_targets(struct annotate_browser
*browser
,
989 struct map_symbol
*ms
= browser
->b
.priv
;
990 struct symbol
*sym
= ms
->sym
;
992 /* PLT symbols contain external offsets */
993 if (strstr(sym
->name
, "@plt"))
996 for (offset
= 0; offset
< size
; ++offset
) {
997 struct disasm_line
*dl
= browser
->offsets
[offset
], *dlt
;
998 struct browser_disasm_line
*bdlt
;
1000 if (!disasm_line__is_valid_jump(dl
, sym
))
1003 dlt
= browser
->offsets
[dl
->ops
.target
.offset
];
1005 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
1006 * have to adjust to the previous offset?
1011 bdlt
= disasm_line__browser(dlt
);
1012 if (++bdlt
->jump_sources
> browser
->max_jump_sources
)
1013 browser
->max_jump_sources
= bdlt
->jump_sources
;
1015 ++browser
->nr_jumps
;
1019 static inline int width_jumps(int n
)
1028 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
,
1029 struct perf_evsel
*evsel
,
1030 struct hist_browser_timer
*hbt
)
1032 struct disasm_line
*pos
, *n
;
1033 struct annotation
*notes
;
1035 struct map_symbol ms
= {
1039 struct annotate_browser browser
= {
1041 .refresh
= annotate_browser__refresh
,
1042 .seek
= ui_browser__list_head_seek
,
1043 .write
= annotate_browser__write
,
1044 .filter
= disasm_line__filter
,
1046 .use_navkeypressed
= true,
1051 size_t sizeof_bdl
= sizeof(struct browser_disasm_line
);
1056 size
= symbol__size(sym
);
1058 if (map
->dso
->annotate_warned
)
1061 browser
.offsets
= zalloc(size
* sizeof(struct disasm_line
*));
1062 if (browser
.offsets
== NULL
) {
1063 ui__error("Not enough memory!");
1067 if (perf_evsel__is_group_event(evsel
)) {
1068 nr_pcnt
= evsel
->nr_members
;
1069 sizeof_bdl
+= sizeof(struct disasm_line_samples
) *
1073 err
= symbol__disassemble(sym
, map
, perf_evsel__env_arch(evsel
), sizeof_bdl
);
1076 symbol__strerror_disassemble(sym
, map
, err
, msg
, sizeof(msg
));
1077 ui__error("Couldn't annotate %s:\n%s", sym
->name
, msg
);
1078 goto out_free_offsets
;
1081 ui_helpline__push("Press ESC to exit");
1083 notes
= symbol__annotation(sym
);
1084 browser
.start
= map__rip_2objdump(map
, sym
->start
);
1086 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
1087 struct browser_disasm_line
*bpos
;
1088 size_t line_len
= strlen(pos
->line
);
1090 if (browser
.b
.width
< line_len
)
1091 browser
.b
.width
= line_len
;
1092 bpos
= disasm_line__browser(pos
);
1093 bpos
->idx
= browser
.nr_entries
++;
1094 if (pos
->offset
!= -1) {
1095 bpos
->idx_asm
= browser
.nr_asm_entries
++;
1097 * FIXME: short term bandaid to cope with assembly
1098 * routines that comes with labels in the same column
1099 * as the address in objdump, sigh.
1101 * E.g. copy_user_generic_unrolled
1103 if (pos
->offset
< (s64
)size
)
1104 browser
.offsets
[pos
->offset
] = pos
;
1109 annotate_browser__mark_jump_targets(&browser
, size
);
1110 annotate__compute_ipc(&browser
, size
, sym
);
1112 browser
.addr_width
= browser
.target_width
= browser
.min_addr_width
= hex_width(size
);
1113 browser
.max_addr_width
= hex_width(sym
->end
);
1114 browser
.jumps_width
= width_jumps(browser
.max_jump_sources
);
1115 browser
.nr_events
= nr_pcnt
;
1116 browser
.b
.nr_entries
= browser
.nr_entries
;
1117 browser
.b
.entries
= ¬es
->src
->source
,
1118 browser
.b
.width
+= 18; /* Percentage */
1120 if (annotate_browser__opts
.hide_src_code
)
1121 annotate_browser__init_asm_mode(&browser
);
1123 annotate_browser__update_addr_width(&browser
);
1125 ret
= annotate_browser__run(&browser
, evsel
, hbt
);
1126 list_for_each_entry_safe(pos
, n
, ¬es
->src
->source
, node
) {
1127 list_del(&pos
->node
);
1128 disasm_line__free(pos
);
1132 free(browser
.offsets
);
1136 #define ANNOTATE_CFG(n) \
1137 { .name = #n, .value = &annotate_browser__opts.n, }
1140 * Keep the entries sorted, they are bsearch'ed
1142 static struct annotate_config
{
1145 } annotate__configs
[] = {
1146 ANNOTATE_CFG(hide_src_code
),
1147 ANNOTATE_CFG(jump_arrows
),
1148 ANNOTATE_CFG(show_linenr
),
1149 ANNOTATE_CFG(show_nr_jumps
),
1150 ANNOTATE_CFG(show_total_period
),
1151 ANNOTATE_CFG(use_offset
),
1156 static int annotate_config__cmp(const void *name
, const void *cfgp
)
1158 const struct annotate_config
*cfg
= cfgp
;
1160 return strcmp(name
, cfg
->name
);
1163 static int annotate__config(const char *var
, const char *value
,
1164 void *data __maybe_unused
)
1166 struct annotate_config
*cfg
;
1169 if (prefixcmp(var
, "annotate.") != 0)
1173 cfg
= bsearch(name
, annotate__configs
, ARRAY_SIZE(annotate__configs
),
1174 sizeof(struct annotate_config
), annotate_config__cmp
);
1177 ui__warning("%s variable unknown, ignoring...", var
);
1179 *cfg
->value
= perf_config_bool(name
, value
);
1183 void annotate_browser__init(void)
1185 perf_config(annotate__config
, NULL
);