1 #include "../../util/util.h"
2 #include "../browser.h"
3 #include "../helpline.h"
4 #include "../libslang.h"
7 #include "../../util/annotate.h"
8 #include "../../util/hist.h"
9 #include "../../util/sort.h"
10 #include "../../util/symbol.h"
11 #include "../../util/evsel.h"
14 struct disasm_line_samples
{
19 struct browser_disasm_line
{
20 struct rb_node rb_node
;
25 * actual length of this array is saved on the nr_events field
26 * of the struct annotate_browser
28 struct disasm_line_samples samples
[1];
31 static struct annotate_browser_opt
{
38 } annotate_browser__opts
= {
43 struct annotate_browser
{
45 struct rb_root entries
;
46 struct rb_node
*curr_hot
;
47 struct disasm_line
*selection
;
48 struct disasm_line
**offsets
;
55 bool searching_backwards
;
65 static inline struct browser_disasm_line
*disasm_line__browser(struct disasm_line
*dl
)
67 return (struct browser_disasm_line
*)(dl
+ 1);
70 static bool disasm_line__filter(struct ui_browser
*browser __maybe_unused
,
73 if (annotate_browser__opts
.hide_src_code
) {
74 struct disasm_line
*dl
= list_entry(entry
, struct disasm_line
, node
);
75 return dl
->offset
== -1;
81 static int annotate_browser__jumps_percent_color(struct annotate_browser
*browser
,
84 if (current
&& (!browser
->b
.use_navkeypressed
|| browser
->b
.navkeypressed
))
85 return HE_COLORSET_SELECTED
;
86 if (nr
== browser
->max_jump_sources
)
87 return HE_COLORSET_TOP
;
89 return HE_COLORSET_MEDIUM
;
90 return HE_COLORSET_NORMAL
;
93 static int annotate_browser__set_jumps_percent_color(struct annotate_browser
*browser
,
96 int color
= annotate_browser__jumps_percent_color(browser
, nr
, current
);
97 return ui_browser__set_color(&browser
->b
, color
);
100 static void annotate_browser__write(struct ui_browser
*browser
, void *entry
, int row
)
102 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
103 struct disasm_line
*dl
= list_entry(entry
, struct disasm_line
, node
);
104 struct browser_disasm_line
*bdl
= disasm_line__browser(dl
);
105 bool current_entry
= ui_browser__is_current_entry(browser
, row
);
106 bool change_color
= (!annotate_browser__opts
.hide_src_code
&&
107 (!current_entry
|| (browser
->use_navkeypressed
&&
108 !browser
->navkeypressed
)));
109 int width
= browser
->width
, printed
;
110 int i
, pcnt_width
= 7 * ab
->nr_events
;
111 double percent_max
= 0.0;
114 for (i
= 0; i
< ab
->nr_events
; i
++) {
115 if (bdl
->samples
[i
].percent
> percent_max
)
116 percent_max
= bdl
->samples
[i
].percent
;
119 if (dl
->offset
!= -1 && percent_max
!= 0.0) {
120 for (i
= 0; i
< ab
->nr_events
; i
++) {
121 ui_browser__set_percent_color(browser
,
122 bdl
->samples
[i
].percent
,
124 if (annotate_browser__opts
.show_total_period
)
125 slsmg_printf("%6" PRIu64
" ",
128 slsmg_printf("%6.2f ", bdl
->samples
[i
].percent
);
131 ui_browser__set_percent_color(browser
, 0, current_entry
);
132 slsmg_write_nstring(" ", pcnt_width
);
135 SLsmg_write_char(' ');
137 /* The scroll bar isn't being used */
138 if (!browser
->navkeypressed
)
142 slsmg_write_nstring(" ", width
- pcnt_width
);
143 else if (dl
->offset
== -1) {
144 if (dl
->line_nr
&& annotate_browser__opts
.show_linenr
)
145 printed
= scnprintf(bf
, sizeof(bf
), "%-*d ",
146 ab
->addr_width
+ 1, dl
->line_nr
);
148 printed
= scnprintf(bf
, sizeof(bf
), "%*s ",
149 ab
->addr_width
, " ");
150 slsmg_write_nstring(bf
, printed
);
151 slsmg_write_nstring(dl
->line
, width
- printed
- pcnt_width
+ 1);
153 u64 addr
= dl
->offset
;
156 if (!annotate_browser__opts
.use_offset
)
159 if (!annotate_browser__opts
.use_offset
) {
160 printed
= scnprintf(bf
, sizeof(bf
), "%" PRIx64
": ", addr
);
162 if (bdl
->jump_sources
) {
163 if (annotate_browser__opts
.show_nr_jumps
) {
165 printed
= scnprintf(bf
, sizeof(bf
), "%*d ",
168 prev
= annotate_browser__set_jumps_percent_color(ab
, bdl
->jump_sources
,
170 slsmg_write_nstring(bf
, printed
);
171 ui_browser__set_color(browser
, prev
);
174 printed
= scnprintf(bf
, sizeof(bf
), "%*" PRIx64
": ",
175 ab
->target_width
, addr
);
177 printed
= scnprintf(bf
, sizeof(bf
), "%*s ",
178 ab
->addr_width
, " ");
183 color
= ui_browser__set_color(browser
, HE_COLORSET_ADDR
);
184 slsmg_write_nstring(bf
, printed
);
186 ui_browser__set_color(browser
, color
);
187 if (dl
->ins
&& dl
->ins
->ops
->scnprintf
) {
188 if (ins__is_jump(dl
->ins
)) {
189 bool fwd
= dl
->ops
.target
.offset
> (u64
)dl
->offset
;
191 ui_browser__write_graph(browser
, fwd
? SLSMG_DARROW_CHAR
:
193 SLsmg_write_char(' ');
194 } else if (ins__is_call(dl
->ins
)) {
195 ui_browser__write_graph(browser
, SLSMG_RARROW_CHAR
);
196 SLsmg_write_char(' ');
198 slsmg_write_nstring(" ", 2);
201 if (strcmp(dl
->name
, "retq")) {
202 slsmg_write_nstring(" ", 2);
204 ui_browser__write_graph(browser
, SLSMG_LARROW_CHAR
);
205 SLsmg_write_char(' ');
209 disasm_line__scnprintf(dl
, bf
, sizeof(bf
), !annotate_browser__opts
.use_offset
);
210 slsmg_write_nstring(bf
, width
- pcnt_width
- 3 - printed
);
217 static bool disasm_line__is_valid_jump(struct disasm_line
*dl
, struct symbol
*sym
)
219 if (!dl
|| !dl
->ins
|| !ins__is_jump(dl
->ins
)
220 || !disasm_line__has_offset(dl
)
221 || dl
->ops
.target
.offset
>= symbol__size(sym
))
227 static void annotate_browser__draw_current_jump(struct ui_browser
*browser
)
229 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
230 struct disasm_line
*cursor
= ab
->selection
, *target
;
231 struct browser_disasm_line
*btarget
, *bcursor
;
232 unsigned int from
, to
;
233 struct map_symbol
*ms
= ab
->b
.priv
;
234 struct symbol
*sym
= ms
->sym
;
237 /* PLT symbols contain external offsets */
238 if (strstr(sym
->name
, "@plt"))
241 if (!disasm_line__is_valid_jump(cursor
, sym
))
244 target
= ab
->offsets
[cursor
->ops
.target
.offset
];
248 bcursor
= disasm_line__browser(cursor
);
249 btarget
= disasm_line__browser(target
);
251 if (annotate_browser__opts
.hide_src_code
) {
252 from
= bcursor
->idx_asm
;
253 to
= btarget
->idx_asm
;
255 from
= (u64
)bcursor
->idx
;
256 to
= (u64
)btarget
->idx
;
259 pcnt_width
*= ab
->nr_events
;
261 ui_browser__set_color(browser
, HE_COLORSET_CODE
);
262 __ui_browser__line_arrow(browser
, pcnt_width
+ 2 + ab
->addr_width
,
266 static unsigned int annotate_browser__refresh(struct ui_browser
*browser
)
268 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
269 int ret
= ui_browser__list_head_refresh(browser
);
272 pcnt_width
= 7 * ab
->nr_events
;
274 if (annotate_browser__opts
.jump_arrows
)
275 annotate_browser__draw_current_jump(browser
);
277 ui_browser__set_color(browser
, HE_COLORSET_NORMAL
);
278 __ui_browser__vline(browser
, pcnt_width
, 0, browser
->height
- 1);
282 static int disasm__cmp(struct browser_disasm_line
*a
,
283 struct browser_disasm_line
*b
, int nr_pcnt
)
287 for (i
= 0; i
< nr_pcnt
; i
++) {
288 if (a
->samples
[i
].percent
== b
->samples
[i
].percent
)
290 return a
->samples
[i
].percent
< b
->samples
[i
].percent
;
295 static void disasm_rb_tree__insert(struct rb_root
*root
, struct browser_disasm_line
*bdl
,
298 struct rb_node
**p
= &root
->rb_node
;
299 struct rb_node
*parent
= NULL
;
300 struct browser_disasm_line
*l
;
304 l
= rb_entry(parent
, struct browser_disasm_line
, rb_node
);
306 if (disasm__cmp(bdl
, l
, nr_events
))
311 rb_link_node(&bdl
->rb_node
, parent
, p
);
312 rb_insert_color(&bdl
->rb_node
, root
);
315 static void annotate_browser__set_top(struct annotate_browser
*browser
,
316 struct disasm_line
*pos
, u32 idx
)
320 ui_browser__refresh_dimensions(&browser
->b
);
321 back
= browser
->b
.height
/ 2;
322 browser
->b
.top_idx
= browser
->b
.index
= idx
;
324 while (browser
->b
.top_idx
!= 0 && back
!= 0) {
325 pos
= list_entry(pos
->node
.prev
, struct disasm_line
, node
);
327 if (disasm_line__filter(&browser
->b
, &pos
->node
))
330 --browser
->b
.top_idx
;
334 browser
->b
.top
= pos
;
335 browser
->b
.navkeypressed
= true;
338 static void annotate_browser__set_rb_top(struct annotate_browser
*browser
,
341 struct browser_disasm_line
*bpos
;
342 struct disasm_line
*pos
;
345 bpos
= rb_entry(nd
, struct browser_disasm_line
, rb_node
);
346 pos
= ((struct disasm_line
*)bpos
) - 1;
348 if (annotate_browser__opts
.hide_src_code
)
350 annotate_browser__set_top(browser
, pos
, idx
);
351 browser
->curr_hot
= nd
;
354 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
355 struct perf_evsel
*evsel
)
357 struct map_symbol
*ms
= browser
->b
.priv
;
358 struct symbol
*sym
= ms
->sym
;
359 struct annotation
*notes
= symbol__annotation(sym
);
360 struct disasm_line
*pos
, *next
;
361 s64 len
= symbol__size(sym
);
363 browser
->entries
= RB_ROOT
;
365 pthread_mutex_lock(¬es
->lock
);
367 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
368 struct browser_disasm_line
*bpos
= disasm_line__browser(pos
);
369 const char *path
= NULL
;
370 double max_percent
= 0.0;
373 if (pos
->offset
== -1) {
374 RB_CLEAR_NODE(&bpos
->rb_node
);
378 next
= disasm__get_next_ip_line(¬es
->src
->source
, pos
);
380 for (i
= 0; i
< browser
->nr_events
; i
++) {
383 bpos
->samples
[i
].percent
= disasm__calc_percent(notes
,
386 next
? next
->offset
: len
,
388 bpos
->samples
[i
].nr
= nr_samples
;
390 if (max_percent
< bpos
->samples
[i
].percent
)
391 max_percent
= bpos
->samples
[i
].percent
;
394 if (max_percent
< 0.01 && pos
->ipc
== 0) {
395 RB_CLEAR_NODE(&bpos
->rb_node
);
398 disasm_rb_tree__insert(&browser
->entries
, bpos
,
401 pthread_mutex_unlock(¬es
->lock
);
403 browser
->curr_hot
= rb_last(&browser
->entries
);
406 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
408 struct disasm_line
*dl
;
409 struct browser_disasm_line
*bdl
;
410 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
412 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
413 dl
= list_entry(browser
->b
.top
, struct disasm_line
, node
);
414 bdl
= disasm_line__browser(dl
);
416 if (annotate_browser__opts
.hide_src_code
) {
417 if (bdl
->idx_asm
< offset
)
420 browser
->b
.nr_entries
= browser
->nr_entries
;
421 annotate_browser__opts
.hide_src_code
= false;
422 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
423 browser
->b
.top_idx
= bdl
->idx
- offset
;
424 browser
->b
.index
= bdl
->idx
;
426 if (bdl
->idx_asm
< 0) {
427 ui_helpline__puts("Only available for assembly lines.");
428 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
432 if (bdl
->idx_asm
< offset
)
433 offset
= bdl
->idx_asm
;
435 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
436 annotate_browser__opts
.hide_src_code
= true;
437 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
438 browser
->b
.top_idx
= bdl
->idx_asm
- offset
;
439 browser
->b
.index
= bdl
->idx_asm
;
445 static void annotate_browser__init_asm_mode(struct annotate_browser
*browser
)
447 ui_browser__reset_index(&browser
->b
);
448 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
451 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
453 static int sym_title(struct symbol
*sym
, struct map
*map
, char *title
,
456 return snprintf(title
, sz
, "%s %s", sym
->name
, map
->dso
->long_name
);
459 static bool annotate_browser__callq(struct annotate_browser
*browser
,
460 struct perf_evsel
*evsel
,
461 struct hist_browser_timer
*hbt
)
463 struct map_symbol
*ms
= browser
->b
.priv
;
464 struct disasm_line
*dl
= browser
->selection
;
465 struct annotation
*notes
;
466 struct addr_map_symbol target
= {
468 .addr
= map__objdump_2mem(ms
->map
, dl
->ops
.target
.addr
),
470 char title
[SYM_TITLE_MAX_SIZE
];
472 if (!ins__is_call(dl
->ins
))
475 if (map_groups__find_ams(&target
, NULL
) ||
476 map__rip_2objdump(target
.map
, target
.map
->map_ip(target
.map
,
478 dl
->ops
.target
.addr
) {
479 ui_helpline__puts("The called function was not found.");
483 notes
= symbol__annotation(target
.sym
);
484 pthread_mutex_lock(¬es
->lock
);
486 if (notes
->src
== NULL
&& symbol__alloc_hist(target
.sym
) < 0) {
487 pthread_mutex_unlock(¬es
->lock
);
488 ui__warning("Not enough memory for annotating '%s' symbol!\n",
493 pthread_mutex_unlock(¬es
->lock
);
494 symbol__tui_annotate(target
.sym
, target
.map
, evsel
, hbt
);
495 sym_title(ms
->sym
, ms
->map
, title
, sizeof(title
));
496 ui_browser__show_title(&browser
->b
, title
);
501 struct disasm_line
*annotate_browser__find_offset(struct annotate_browser
*browser
,
502 s64 offset
, s64
*idx
)
504 struct map_symbol
*ms
= browser
->b
.priv
;
505 struct symbol
*sym
= ms
->sym
;
506 struct annotation
*notes
= symbol__annotation(sym
);
507 struct disasm_line
*pos
;
510 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
511 if (pos
->offset
== offset
)
513 if (!disasm_line__filter(&browser
->b
, &pos
->node
))
520 static bool annotate_browser__jump(struct annotate_browser
*browser
)
522 struct disasm_line
*dl
= browser
->selection
;
525 if (!ins__is_jump(dl
->ins
))
528 dl
= annotate_browser__find_offset(browser
, dl
->ops
.target
.offset
, &idx
);
530 ui_helpline__puts("Invalid jump offset");
534 annotate_browser__set_top(browser
, dl
, idx
);
540 struct disasm_line
*annotate_browser__find_string(struct annotate_browser
*browser
,
543 struct map_symbol
*ms
= browser
->b
.priv
;
544 struct symbol
*sym
= ms
->sym
;
545 struct annotation
*notes
= symbol__annotation(sym
);
546 struct disasm_line
*pos
= browser
->selection
;
548 *idx
= browser
->b
.index
;
549 list_for_each_entry_continue(pos
, ¬es
->src
->source
, node
) {
550 if (disasm_line__filter(&browser
->b
, &pos
->node
))
555 if (pos
->line
&& strstr(pos
->line
, s
) != NULL
)
562 static bool __annotate_browser__search(struct annotate_browser
*browser
)
564 struct disasm_line
*dl
;
567 dl
= annotate_browser__find_string(browser
, browser
->search_bf
, &idx
);
569 ui_helpline__puts("String not found!");
573 annotate_browser__set_top(browser
, dl
, idx
);
574 browser
->searching_backwards
= false;
579 struct disasm_line
*annotate_browser__find_string_reverse(struct annotate_browser
*browser
,
582 struct map_symbol
*ms
= browser
->b
.priv
;
583 struct symbol
*sym
= ms
->sym
;
584 struct annotation
*notes
= symbol__annotation(sym
);
585 struct disasm_line
*pos
= browser
->selection
;
587 *idx
= browser
->b
.index
;
588 list_for_each_entry_continue_reverse(pos
, ¬es
->src
->source
, node
) {
589 if (disasm_line__filter(&browser
->b
, &pos
->node
))
594 if (pos
->line
&& strstr(pos
->line
, s
) != NULL
)
601 static bool __annotate_browser__search_reverse(struct annotate_browser
*browser
)
603 struct disasm_line
*dl
;
606 dl
= annotate_browser__find_string_reverse(browser
, browser
->search_bf
, &idx
);
608 ui_helpline__puts("String not found!");
612 annotate_browser__set_top(browser
, dl
, idx
);
613 browser
->searching_backwards
= true;
617 static bool annotate_browser__search_window(struct annotate_browser
*browser
,
620 if (ui_browser__input_window("Search", "String: ", browser
->search_bf
,
621 "ENTER: OK, ESC: Cancel",
622 delay_secs
* 2) != K_ENTER
||
623 !*browser
->search_bf
)
629 static bool annotate_browser__search(struct annotate_browser
*browser
, int delay_secs
)
631 if (annotate_browser__search_window(browser
, delay_secs
))
632 return __annotate_browser__search(browser
);
637 static bool annotate_browser__continue_search(struct annotate_browser
*browser
,
640 if (!*browser
->search_bf
)
641 return annotate_browser__search(browser
, delay_secs
);
643 return __annotate_browser__search(browser
);
646 static bool annotate_browser__search_reverse(struct annotate_browser
*browser
,
649 if (annotate_browser__search_window(browser
, delay_secs
))
650 return __annotate_browser__search_reverse(browser
);
656 bool annotate_browser__continue_search_reverse(struct annotate_browser
*browser
,
659 if (!*browser
->search_bf
)
660 return annotate_browser__search_reverse(browser
, delay_secs
);
662 return __annotate_browser__search_reverse(browser
);
665 static void annotate_browser__update_addr_width(struct annotate_browser
*browser
)
667 if (annotate_browser__opts
.use_offset
)
668 browser
->target_width
= browser
->min_addr_width
;
670 browser
->target_width
= browser
->max_addr_width
;
672 browser
->addr_width
= browser
->target_width
;
674 if (annotate_browser__opts
.show_nr_jumps
)
675 browser
->addr_width
+= browser
->jumps_width
+ 1;
678 static int annotate_browser__run(struct annotate_browser
*browser
,
679 struct perf_evsel
*evsel
,
680 struct hist_browser_timer
*hbt
)
682 struct rb_node
*nd
= NULL
;
683 struct map_symbol
*ms
= browser
->b
.priv
;
684 struct symbol
*sym
= ms
->sym
;
685 const char *help
= "Press 'h' for help on key bindings";
686 int delay_secs
= hbt
? hbt
->refresh
: 0;
688 char title
[SYM_TITLE_MAX_SIZE
];
690 sym_title(sym
, ms
->map
, title
, sizeof(title
));
691 if (ui_browser__show(&browser
->b
, title
, help
) < 0)
694 annotate_browser__calc_percent(browser
, evsel
);
696 if (browser
->curr_hot
) {
697 annotate_browser__set_rb_top(browser
, browser
->curr_hot
);
698 browser
->b
.navkeypressed
= false;
701 nd
= browser
->curr_hot
;
704 key
= ui_browser__run(&browser
->b
, delay_secs
);
706 if (delay_secs
!= 0) {
707 annotate_browser__calc_percent(browser
, evsel
);
709 * Current line focus got out of the list of most active
710 * lines, NULL it so that if TAB|UNTAB is pressed, we
711 * move to curr_hot (current hottest line).
713 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
720 hbt
->timer(hbt
->arg
);
723 symbol__annotate_decay_histogram(sym
, evsel
->idx
);
729 nd
= rb_last(&browser
->entries
);
731 nd
= browser
->curr_hot
;
737 nd
= rb_first(&browser
->entries
);
739 nd
= browser
->curr_hot
;
743 ui_browser__help_window(&browser
->b
,
745 "PGDN/SPACE Navigate\n"
746 "q/ESC/CTRL+C Exit\n\n"
749 "H Cycle thru hottest instructions\n"
750 "j Toggle showing jump to target arrows\n"
751 "J Toggle showing number of jump sources on targets\n"
752 "n Search next string\n"
753 "o Toggle disassembler output/simplified view\n"
754 "s Toggle source code view\n"
755 "t Toggle total period view\n"
757 "k Toggle line numbers\n"
758 "r Run available scripts\n"
759 "? Search string backwards\n");
767 annotate_browser__opts
.show_linenr
=
768 !annotate_browser__opts
.show_linenr
;
771 nd
= browser
->curr_hot
;
774 if (annotate_browser__toggle_source(browser
))
775 ui_helpline__puts(help
);
778 annotate_browser__opts
.use_offset
= !annotate_browser__opts
.use_offset
;
779 annotate_browser__update_addr_width(browser
);
782 annotate_browser__opts
.jump_arrows
= !annotate_browser__opts
.jump_arrows
;
785 annotate_browser__opts
.show_nr_jumps
= !annotate_browser__opts
.show_nr_jumps
;
786 annotate_browser__update_addr_width(browser
);
789 if (annotate_browser__search(browser
, delay_secs
)) {
791 ui_helpline__puts(help
);
795 if (browser
->searching_backwards
?
796 annotate_browser__continue_search_reverse(browser
, delay_secs
) :
797 annotate_browser__continue_search(browser
, delay_secs
))
801 if (annotate_browser__search_reverse(browser
, delay_secs
))
807 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
808 seq
++, browser
->b
.nr_entries
,
812 browser
->nr_asm_entries
);
817 if (browser
->selection
== NULL
)
818 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
819 else if (browser
->selection
->offset
== -1)
820 ui_helpline__puts("Actions are only available for assembly lines.");
821 else if (!browser
->selection
->ins
) {
822 if (strcmp(browser
->selection
->name
, "retq"))
825 } else if (!(annotate_browser__jump(browser
) ||
826 annotate_browser__callq(browser
, evsel
, hbt
))) {
828 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
832 annotate_browser__opts
.show_total_period
=
833 !annotate_browser__opts
.show_total_period
;
834 annotate_browser__update_addr_width(browser
);
846 annotate_browser__set_rb_top(browser
, nd
);
849 ui_browser__hide(&browser
->b
);
853 int map_symbol__tui_annotate(struct map_symbol
*ms
, struct perf_evsel
*evsel
,
854 struct hist_browser_timer
*hbt
)
856 /* Set default value for show_total_period. */
857 annotate_browser__opts
.show_total_period
=
858 symbol_conf
.show_total_period
;
860 return symbol__tui_annotate(ms
->sym
, ms
->map
, evsel
, hbt
);
863 int hist_entry__tui_annotate(struct hist_entry
*he
, struct perf_evsel
*evsel
,
864 struct hist_browser_timer
*hbt
)
866 /* reset abort key so that it can get Ctrl-C as a key */
868 SLang_init_tty(0, 0, 0);
870 return map_symbol__tui_annotate(&he
->ms
, evsel
, hbt
);
874 static unsigned count_insn(struct annotate_browser
*browser
, u64 start
, u64 end
)
879 for (offset
= start
; offset
<= end
; offset
++) {
880 if (browser
->offsets
[offset
])
886 static void count_and_fill(struct annotate_browser
*browser
, u64 start
, u64 end
,
892 n_insn
= count_insn(browser
, start
, end
);
893 if (n_insn
&& ch
->num
&& ch
->cycles
) {
894 float ipc
= n_insn
/ ((double)ch
->cycles
/ (double)ch
->num
);
896 /* Hide data when there are too many overlaps. */
897 if (ch
->reset
>= 0x7fff || ch
->reset
>= ch
->num
/ 2)
900 for (offset
= start
; offset
<= end
; offset
++) {
901 struct disasm_line
*dl
= browser
->offsets
[offset
];
910 * This should probably be in util/annotate.c to share with the tty
911 * annotate, but right now we need the per byte offsets arrays,
912 * which are only here.
914 static void annotate__compute_ipc(struct annotate_browser
*browser
, size_t size
,
918 struct annotation
*notes
= symbol__annotation(sym
);
920 if (!notes
->src
|| !notes
->src
->cycles_hist
)
923 pthread_mutex_lock(¬es
->lock
);
924 for (offset
= 0; offset
< size
; ++offset
) {
927 ch
= ¬es
->src
->cycles_hist
[offset
];
928 if (ch
&& ch
->cycles
) {
929 struct disasm_line
*dl
;
932 count_and_fill(browser
, ch
->start
, offset
, ch
);
933 dl
= browser
->offsets
[offset
];
934 if (dl
&& ch
->num_aggr
)
935 dl
->cycles
= ch
->cycles_aggr
/ ch
->num_aggr
;
936 browser
->have_cycles
= true;
939 pthread_mutex_unlock(¬es
->lock
);
942 static void annotate_browser__mark_jump_targets(struct annotate_browser
*browser
,
946 struct map_symbol
*ms
= browser
->b
.priv
;
947 struct symbol
*sym
= ms
->sym
;
949 /* PLT symbols contain external offsets */
950 if (strstr(sym
->name
, "@plt"))
953 for (offset
= 0; offset
< size
; ++offset
) {
954 struct disasm_line
*dl
= browser
->offsets
[offset
], *dlt
;
955 struct browser_disasm_line
*bdlt
;
957 if (!disasm_line__is_valid_jump(dl
, sym
))
960 dlt
= browser
->offsets
[dl
->ops
.target
.offset
];
962 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
963 * have to adjust to the previous offset?
968 bdlt
= disasm_line__browser(dlt
);
969 if (++bdlt
->jump_sources
> browser
->max_jump_sources
)
970 browser
->max_jump_sources
= bdlt
->jump_sources
;
976 static inline int width_jumps(int n
)
985 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
,
986 struct perf_evsel
*evsel
,
987 struct hist_browser_timer
*hbt
)
989 struct disasm_line
*pos
, *n
;
990 struct annotation
*notes
;
992 struct map_symbol ms
= {
996 struct annotate_browser browser
= {
998 .refresh
= annotate_browser__refresh
,
999 .seek
= ui_browser__list_head_seek
,
1000 .write
= annotate_browser__write
,
1001 .filter
= disasm_line__filter
,
1003 .use_navkeypressed
= true,
1008 size_t sizeof_bdl
= sizeof(struct browser_disasm_line
);
1013 size
= symbol__size(sym
);
1015 if (map
->dso
->annotate_warned
)
1018 browser
.offsets
= zalloc(size
* sizeof(struct disasm_line
*));
1019 if (browser
.offsets
== NULL
) {
1020 ui__error("Not enough memory!");
1024 if (perf_evsel__is_group_event(evsel
)) {
1025 nr_pcnt
= evsel
->nr_members
;
1026 sizeof_bdl
+= sizeof(struct disasm_line_samples
) *
1030 if (symbol__annotate(sym
, map
, sizeof_bdl
) < 0) {
1031 ui__error("%s", ui_helpline__last_msg
);
1032 goto out_free_offsets
;
1035 ui_helpline__push("Press <- or ESC to exit");
1037 notes
= symbol__annotation(sym
);
1038 browser
.start
= map__rip_2objdump(map
, sym
->start
);
1040 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
1041 struct browser_disasm_line
*bpos
;
1042 size_t line_len
= strlen(pos
->line
);
1044 if (browser
.b
.width
< line_len
)
1045 browser
.b
.width
= line_len
;
1046 bpos
= disasm_line__browser(pos
);
1047 bpos
->idx
= browser
.nr_entries
++;
1048 if (pos
->offset
!= -1) {
1049 bpos
->idx_asm
= browser
.nr_asm_entries
++;
1051 * FIXME: short term bandaid to cope with assembly
1052 * routines that comes with labels in the same column
1053 * as the address in objdump, sigh.
1055 * E.g. copy_user_generic_unrolled
1057 if (pos
->offset
< (s64
)size
)
1058 browser
.offsets
[pos
->offset
] = pos
;
1063 annotate_browser__mark_jump_targets(&browser
, size
);
1064 annotate__compute_ipc(&browser
, size
, sym
);
1066 browser
.addr_width
= browser
.target_width
= browser
.min_addr_width
= hex_width(size
);
1067 browser
.max_addr_width
= hex_width(sym
->end
);
1068 browser
.jumps_width
= width_jumps(browser
.max_jump_sources
);
1069 browser
.nr_events
= nr_pcnt
;
1070 browser
.b
.nr_entries
= browser
.nr_entries
;
1071 browser
.b
.entries
= ¬es
->src
->source
,
1072 browser
.b
.width
+= 18; /* Percentage */
1074 if (annotate_browser__opts
.hide_src_code
)
1075 annotate_browser__init_asm_mode(&browser
);
1077 annotate_browser__update_addr_width(&browser
);
1079 ret
= annotate_browser__run(&browser
, evsel
, hbt
);
1080 list_for_each_entry_safe(pos
, n
, ¬es
->src
->source
, node
) {
1081 list_del(&pos
->node
);
1082 disasm_line__free(pos
);
1086 free(browser
.offsets
);
1090 #define ANNOTATE_CFG(n) \
1091 { .name = #n, .value = &annotate_browser__opts.n, }
1094 * Keep the entries sorted, they are bsearch'ed
1096 static struct annotate_config
{
1099 } annotate__configs
[] = {
1100 ANNOTATE_CFG(hide_src_code
),
1101 ANNOTATE_CFG(jump_arrows
),
1102 ANNOTATE_CFG(show_linenr
),
1103 ANNOTATE_CFG(show_nr_jumps
),
1104 ANNOTATE_CFG(use_offset
),
1105 ANNOTATE_CFG(show_total_period
),
1110 static int annotate_config__cmp(const void *name
, const void *cfgp
)
1112 const struct annotate_config
*cfg
= cfgp
;
1114 return strcmp(name
, cfg
->name
);
1117 static int annotate__config(const char *var
, const char *value
,
1118 void *data __maybe_unused
)
1120 struct annotate_config
*cfg
;
1123 if (prefixcmp(var
, "annotate.") != 0)
1127 cfg
= bsearch(name
, annotate__configs
, ARRAY_SIZE(annotate__configs
),
1128 sizeof(struct annotate_config
), annotate_config__cmp
);
1133 *cfg
->value
= perf_config_bool(name
, value
);
1137 void annotate_browser__init(void)
1139 perf_config(annotate__config
, NULL
);