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"
13 #include <linux/kernel.h>
15 struct disasm_line_samples {
21 #define CYCLES_WIDTH 6
23 struct browser_disasm_line {
24 struct rb_node rb_node;
29 * actual length of this array is saved on the nr_events field
30 * of the struct annotate_browser
32 struct disasm_line_samples samples[1];
35 static struct annotate_browser_opt {
42 } annotate_browser__opts = {
47 struct annotate_browser {
49 struct rb_root entries;
50 struct rb_node *curr_hot;
51 struct disasm_line *selection;
52 struct disasm_line **offsets;
59 bool searching_backwards;
69 static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
71 return (struct browser_disasm_line *)(dl + 1);
74 static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
77 if (annotate_browser__opts.hide_src_code) {
78 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
79 return dl->offset == -1;
85 static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
88 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
89 return HE_COLORSET_SELECTED;
90 if (nr == browser->max_jump_sources)
91 return HE_COLORSET_TOP;
93 return HE_COLORSET_MEDIUM;
94 return HE_COLORSET_NORMAL;
97 static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
100 int color = annotate_browser__jumps_percent_color(browser, nr, current);
101 return ui_browser__set_color(&browser->b, color);
104 static int annotate_browser__pcnt_width(struct annotate_browser *ab)
106 int w = 7 * ab->nr_events;
109 w += IPC_WIDTH + CYCLES_WIDTH;
113 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
115 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
116 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
117 struct browser_disasm_line *bdl = disasm_line__browser(dl);
118 bool current_entry = ui_browser__is_current_entry(browser, row);
119 bool change_color = (!annotate_browser__opts.hide_src_code &&
120 (!current_entry || (browser->use_navkeypressed &&
121 !browser->navkeypressed)));
122 int width = browser->width, printed;
123 int i, pcnt_width = annotate_browser__pcnt_width(ab);
124 double percent_max = 0.0;
127 for (i = 0; i < ab->nr_events; i++) {
128 if (bdl->samples[i].percent > percent_max)
129 percent_max = bdl->samples[i].percent;
132 if (dl->offset != -1 && percent_max != 0.0) {
133 if (percent_max != 0.0) {
134 for (i = 0; i < ab->nr_events; i++) {
135 ui_browser__set_percent_color(browser,
136 bdl->samples[i].percent,
138 if (annotate_browser__opts.show_total_period) {
139 ui_browser__printf(browser, "%6" PRIu64 " ",
142 ui_browser__printf(browser, "%6.2f ",
143 bdl->samples[i].percent);
147 ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
150 ui_browser__set_percent_color(browser, 0, current_entry);
151 ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
153 if (ab->have_cycles) {
155 ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
157 ui_browser__write_nstring(browser, " ", IPC_WIDTH);
159 ui_browser__printf(browser, "%*" PRIu64 " ",
160 CYCLES_WIDTH - 1, dl->cycles);
162 ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
165 SLsmg_write_char(' ');
167 /* The scroll bar isn't being used */
168 if (!browser->navkeypressed)
172 ui_browser__write_nstring(browser, " ", width - pcnt_width);
173 else if (dl->offset == -1) {
174 if (dl->line_nr && annotate_browser__opts.show_linenr)
175 printed = scnprintf(bf, sizeof(bf), "%-*d ",
176 ab->addr_width + 1, dl->line_nr);
178 printed = scnprintf(bf, sizeof(bf), "%*s ",
179 ab->addr_width, " ");
180 ui_browser__write_nstring(browser, bf, printed);
181 ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
183 u64 addr = dl->offset;
186 if (!annotate_browser__opts.use_offset)
189 if (!annotate_browser__opts.use_offset) {
190 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
192 if (bdl->jump_sources) {
193 if (annotate_browser__opts.show_nr_jumps) {
195 printed = scnprintf(bf, sizeof(bf), "%*d ",
198 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
200 ui_browser__write_nstring(browser, bf, printed);
201 ui_browser__set_color(browser, prev);
204 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
205 ab->target_width, addr);
207 printed = scnprintf(bf, sizeof(bf), "%*s ",
208 ab->addr_width, " ");
213 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
214 ui_browser__write_nstring(browser, bf, printed);
216 ui_browser__set_color(browser, color);
217 if (dl->ins.ops && dl->ins.ops->scnprintf) {
218 if (ins__is_jump(&dl->ins)) {
219 bool fwd = dl->ops.target.offset > dl->offset;
221 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
223 SLsmg_write_char(' ');
224 } else if (ins__is_call(&dl->ins)) {
225 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
226 SLsmg_write_char(' ');
227 } else if (ins__is_ret(&dl->ins)) {
228 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
229 SLsmg_write_char(' ');
231 ui_browser__write_nstring(browser, " ", 2);
234 ui_browser__write_nstring(browser, " ", 2);
237 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
238 ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
245 static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
247 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
248 || !disasm_line__has_offset(dl)
249 || dl->ops.target.offset < 0
250 || dl->ops.target.offset >= (s64)symbol__size(sym))
256 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
258 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
259 struct disasm_line *cursor = ab->selection, *target;
260 struct browser_disasm_line *btarget, *bcursor;
261 unsigned int from, to;
262 struct map_symbol *ms = ab->b.priv;
263 struct symbol *sym = ms->sym;
264 u8 pcnt_width = annotate_browser__pcnt_width(ab);
266 /* PLT symbols contain external offsets */
267 if (strstr(sym->name, "@plt"))
270 if (!disasm_line__is_valid_jump(cursor, sym))
273 target = ab->offsets[cursor->ops.target.offset];
277 bcursor = disasm_line__browser(cursor);
278 btarget = disasm_line__browser(target);
280 if (annotate_browser__opts.hide_src_code) {
281 from = bcursor->idx_asm;
282 to = btarget->idx_asm;
284 from = (u64)bcursor->idx;
285 to = (u64)btarget->idx;
288 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
289 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
293 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
295 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
296 int ret = ui_browser__list_head_refresh(browser);
297 int pcnt_width = annotate_browser__pcnt_width(ab);
299 if (annotate_browser__opts.jump_arrows)
300 annotate_browser__draw_current_jump(browser);
302 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
303 __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
307 static int disasm__cmp(struct browser_disasm_line *a,
308 struct browser_disasm_line *b, int nr_pcnt)
312 for (i = 0; i < nr_pcnt; i++) {
313 if (a->samples[i].percent == b->samples[i].percent)
315 return a->samples[i].percent < b->samples[i].percent;
320 static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
323 struct rb_node **p = &root->rb_node;
324 struct rb_node *parent = NULL;
325 struct browser_disasm_line *l;
329 l = rb_entry(parent, struct browser_disasm_line, rb_node);
331 if (disasm__cmp(bdl, l, nr_events))
336 rb_link_node(&bdl->rb_node, parent, p);
337 rb_insert_color(&bdl->rb_node, root);
340 static void annotate_browser__set_top(struct annotate_browser *browser,
341 struct disasm_line *pos, u32 idx)
345 ui_browser__refresh_dimensions(&browser->b);
346 back = browser->b.height / 2;
347 browser->b.top_idx = browser->b.index = idx;
349 while (browser->b.top_idx != 0 && back != 0) {
350 pos = list_entry(pos->node.prev, struct disasm_line, node);
352 if (disasm_line__filter(&browser->b, &pos->node))
355 --browser->b.top_idx;
359 browser->b.top = pos;
360 browser->b.navkeypressed = true;
363 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
366 struct browser_disasm_line *bpos;
367 struct disasm_line *pos;
370 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
371 pos = ((struct disasm_line *)bpos) - 1;
373 if (annotate_browser__opts.hide_src_code)
375 annotate_browser__set_top(browser, pos, idx);
376 browser->curr_hot = nd;
379 static void annotate_browser__calc_percent(struct annotate_browser *browser,
380 struct perf_evsel *evsel)
382 struct map_symbol *ms = browser->b.priv;
383 struct symbol *sym = ms->sym;
384 struct annotation *notes = symbol__annotation(sym);
385 struct disasm_line *pos, *next;
386 s64 len = symbol__size(sym);
388 browser->entries = RB_ROOT;
390 pthread_mutex_lock(¬es->lock);
392 list_for_each_entry(pos, ¬es->src->source, node) {
393 struct browser_disasm_line *bpos = disasm_line__browser(pos);
394 const char *path = NULL;
395 double max_percent = 0.0;
398 if (pos->offset == -1) {
399 RB_CLEAR_NODE(&bpos->rb_node);
403 next = disasm__get_next_ip_line(¬es->src->source, pos);
405 for (i = 0; i < browser->nr_events; i++) {
408 bpos->samples[i].percent = disasm__calc_percent(notes,
411 next ? next->offset : len,
413 bpos->samples[i].nr = nr_samples;
415 if (max_percent < bpos->samples[i].percent)
416 max_percent = bpos->samples[i].percent;
419 if (max_percent < 0.01 && pos->ipc == 0) {
420 RB_CLEAR_NODE(&bpos->rb_node);
423 disasm_rb_tree__insert(&browser->entries, bpos,
426 pthread_mutex_unlock(¬es->lock);
428 browser->curr_hot = rb_last(&browser->entries);
431 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
433 struct disasm_line *dl;
434 struct browser_disasm_line *bdl;
435 off_t offset = browser->b.index - browser->b.top_idx;
437 browser->b.seek(&browser->b, offset, SEEK_CUR);
438 dl = list_entry(browser->b.top, struct disasm_line, node);
439 bdl = disasm_line__browser(dl);
441 if (annotate_browser__opts.hide_src_code) {
442 if (bdl->idx_asm < offset)
445 browser->b.nr_entries = browser->nr_entries;
446 annotate_browser__opts.hide_src_code = false;
447 browser->b.seek(&browser->b, -offset, SEEK_CUR);
448 browser->b.top_idx = bdl->idx - offset;
449 browser->b.index = bdl->idx;
451 if (bdl->idx_asm < 0) {
452 ui_helpline__puts("Only available for assembly lines.");
453 browser->b.seek(&browser->b, -offset, SEEK_CUR);
457 if (bdl->idx_asm < offset)
458 offset = bdl->idx_asm;
460 browser->b.nr_entries = browser->nr_asm_entries;
461 annotate_browser__opts.hide_src_code = true;
462 browser->b.seek(&browser->b, -offset, SEEK_CUR);
463 browser->b.top_idx = bdl->idx_asm - offset;
464 browser->b.index = bdl->idx_asm;
470 static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
472 ui_browser__reset_index(&browser->b);
473 browser->b.nr_entries = browser->nr_asm_entries;
476 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
478 static int sym_title(struct symbol *sym, struct map *map, char *title,
481 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
484 static bool annotate_browser__callq(struct annotate_browser *browser,
485 struct perf_evsel *evsel,
486 struct hist_browser_timer *hbt)
488 struct map_symbol *ms = browser->b.priv;
489 struct disasm_line *dl = browser->selection;
490 struct annotation *notes;
491 struct addr_map_symbol target = {
493 .addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
495 char title[SYM_TITLE_MAX_SIZE];
497 if (!ins__is_call(&dl->ins))
500 if (map_groups__find_ams(&target) ||
501 map__rip_2objdump(target.map, target.map->map_ip(target.map,
503 dl->ops.target.addr) {
504 ui_helpline__puts("The called function was not found.");
508 notes = symbol__annotation(target.sym);
509 pthread_mutex_lock(¬es->lock);
511 if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
512 pthread_mutex_unlock(¬es->lock);
513 ui__warning("Not enough memory for annotating '%s' symbol!\n",
518 pthread_mutex_unlock(¬es->lock);
519 symbol__tui_annotate(target.sym, target.map, evsel, hbt);
520 sym_title(ms->sym, ms->map, title, sizeof(title));
521 ui_browser__show_title(&browser->b, title);
526 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
527 s64 offset, s64 *idx)
529 struct map_symbol *ms = browser->b.priv;
530 struct symbol *sym = ms->sym;
531 struct annotation *notes = symbol__annotation(sym);
532 struct disasm_line *pos;
535 list_for_each_entry(pos, ¬es->src->source, node) {
536 if (pos->offset == offset)
538 if (!disasm_line__filter(&browser->b, &pos->node))
545 static bool annotate_browser__jump(struct annotate_browser *browser)
547 struct disasm_line *dl = browser->selection;
551 if (!ins__is_jump(&dl->ins))
554 offset = dl->ops.target.offset;
555 dl = annotate_browser__find_offset(browser, offset, &idx);
557 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
561 annotate_browser__set_top(browser, dl, idx);
567 struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
570 struct map_symbol *ms = browser->b.priv;
571 struct symbol *sym = ms->sym;
572 struct annotation *notes = symbol__annotation(sym);
573 struct disasm_line *pos = browser->selection;
575 *idx = browser->b.index;
576 list_for_each_entry_continue(pos, ¬es->src->source, node) {
577 if (disasm_line__filter(&browser->b, &pos->node))
582 if (pos->line && strstr(pos->line, s) != NULL)
589 static bool __annotate_browser__search(struct annotate_browser *browser)
591 struct disasm_line *dl;
594 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
596 ui_helpline__puts("String not found!");
600 annotate_browser__set_top(browser, dl, idx);
601 browser->searching_backwards = false;
606 struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
609 struct map_symbol *ms = browser->b.priv;
610 struct symbol *sym = ms->sym;
611 struct annotation *notes = symbol__annotation(sym);
612 struct disasm_line *pos = browser->selection;
614 *idx = browser->b.index;
615 list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) {
616 if (disasm_line__filter(&browser->b, &pos->node))
621 if (pos->line && strstr(pos->line, s) != NULL)
628 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
630 struct disasm_line *dl;
633 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
635 ui_helpline__puts("String not found!");
639 annotate_browser__set_top(browser, dl, idx);
640 browser->searching_backwards = true;
644 static bool annotate_browser__search_window(struct annotate_browser *browser,
647 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
648 "ENTER: OK, ESC: Cancel",
649 delay_secs * 2) != K_ENTER ||
650 !*browser->search_bf)
656 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
658 if (annotate_browser__search_window(browser, delay_secs))
659 return __annotate_browser__search(browser);
664 static bool annotate_browser__continue_search(struct annotate_browser *browser,
667 if (!*browser->search_bf)
668 return annotate_browser__search(browser, delay_secs);
670 return __annotate_browser__search(browser);
673 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
676 if (annotate_browser__search_window(browser, delay_secs))
677 return __annotate_browser__search_reverse(browser);
683 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
686 if (!*browser->search_bf)
687 return annotate_browser__search_reverse(browser, delay_secs);
689 return __annotate_browser__search_reverse(browser);
692 static void annotate_browser__update_addr_width(struct annotate_browser *browser)
694 if (annotate_browser__opts.use_offset)
695 browser->target_width = browser->min_addr_width;
697 browser->target_width = browser->max_addr_width;
699 browser->addr_width = browser->target_width;
701 if (annotate_browser__opts.show_nr_jumps)
702 browser->addr_width += browser->jumps_width + 1;
705 static int annotate_browser__run(struct annotate_browser *browser,
706 struct perf_evsel *evsel,
707 struct hist_browser_timer *hbt)
709 struct rb_node *nd = NULL;
710 struct map_symbol *ms = browser->b.priv;
711 struct symbol *sym = ms->sym;
712 const char *help = "Press 'h' for help on key bindings";
713 int delay_secs = hbt ? hbt->refresh : 0;
715 char title[SYM_TITLE_MAX_SIZE];
717 sym_title(sym, ms->map, title, sizeof(title));
718 if (ui_browser__show(&browser->b, title, help) < 0)
721 annotate_browser__calc_percent(browser, evsel);
723 if (browser->curr_hot) {
724 annotate_browser__set_rb_top(browser, browser->curr_hot);
725 browser->b.navkeypressed = false;
728 nd = browser->curr_hot;
731 key = ui_browser__run(&browser->b, delay_secs);
733 if (delay_secs != 0) {
734 annotate_browser__calc_percent(browser, evsel);
736 * Current line focus got out of the list of most active
737 * lines, NULL it so that if TAB|UNTAB is pressed, we
738 * move to curr_hot (current hottest line).
740 if (nd != NULL && RB_EMPTY_NODE(nd))
747 hbt->timer(hbt->arg);
750 symbol__annotate_decay_histogram(sym, evsel->idx);
756 nd = rb_last(&browser->entries);
758 nd = browser->curr_hot;
764 nd = rb_first(&browser->entries);
766 nd = browser->curr_hot;
770 ui_browser__help_window(&browser->b,
772 "PGDN/SPACE Navigate\n"
773 "q/ESC/CTRL+C Exit\n\n"
774 "ENTER Go to target\n"
776 "H Cycle thru hottest instructions\n"
777 "j Toggle showing jump to target arrows\n"
778 "J Toggle showing number of jump sources on targets\n"
779 "n Search next string\n"
780 "o Toggle disassembler output/simplified view\n"
781 "s Toggle source code view\n"
782 "t Toggle total period view\n"
784 "k Toggle line numbers\n"
785 "r Run available scripts\n"
786 "? Search string backwards\n");
794 annotate_browser__opts.show_linenr =
795 !annotate_browser__opts.show_linenr;
798 nd = browser->curr_hot;
801 if (annotate_browser__toggle_source(browser))
802 ui_helpline__puts(help);
805 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
806 annotate_browser__update_addr_width(browser);
809 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
812 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
813 annotate_browser__update_addr_width(browser);
816 if (annotate_browser__search(browser, delay_secs)) {
818 ui_helpline__puts(help);
822 if (browser->searching_backwards ?
823 annotate_browser__continue_search_reverse(browser, delay_secs) :
824 annotate_browser__continue_search(browser, delay_secs))
828 if (annotate_browser__search_reverse(browser, delay_secs))
834 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
835 seq++, browser->b.nr_entries,
839 browser->nr_asm_entries);
844 if (browser->selection == NULL)
845 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
846 else if (browser->selection->offset == -1)
847 ui_helpline__puts("Actions are only available for assembly lines.");
848 else if (!browser->selection->ins.ops)
850 else if (ins__is_ret(&browser->selection->ins))
852 else if (!(annotate_browser__jump(browser) ||
853 annotate_browser__callq(browser, evsel, hbt))) {
855 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
859 annotate_browser__opts.show_total_period =
860 !annotate_browser__opts.show_total_period;
861 annotate_browser__update_addr_width(browser);
873 annotate_browser__set_rb_top(browser, nd);
876 ui_browser__hide(&browser->b);
880 int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
881 struct hist_browser_timer *hbt)
883 /* Set default value for show_total_period. */
884 annotate_browser__opts.show_total_period =
885 symbol_conf.show_total_period;
887 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
890 int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
891 struct hist_browser_timer *hbt)
893 /* reset abort key so that it can get Ctrl-C as a key */
895 SLang_init_tty(0, 0, 0);
897 return map_symbol__tui_annotate(&he->ms, evsel, hbt);
901 static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
906 for (offset = start; offset <= end; offset++) {
907 if (browser->offsets[offset])
913 static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
919 n_insn = count_insn(browser, start, end);
920 if (n_insn && ch->num && ch->cycles) {
921 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
923 /* Hide data when there are too many overlaps. */
924 if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
927 for (offset = start; offset <= end; offset++) {
928 struct disasm_line *dl = browser->offsets[offset];
937 * This should probably be in util/annotate.c to share with the tty
938 * annotate, but right now we need the per byte offsets arrays,
939 * which are only here.
941 static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
945 struct annotation *notes = symbol__annotation(sym);
947 if (!notes->src || !notes->src->cycles_hist)
950 pthread_mutex_lock(¬es->lock);
951 for (offset = 0; offset < size; ++offset) {
954 ch = ¬es->src->cycles_hist[offset];
955 if (ch && ch->cycles) {
956 struct disasm_line *dl;
959 count_and_fill(browser, ch->start, offset, ch);
960 dl = browser->offsets[offset];
961 if (dl && ch->num_aggr)
962 dl->cycles = ch->cycles_aggr / ch->num_aggr;
963 browser->have_cycles = true;
966 pthread_mutex_unlock(¬es->lock);
969 static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
973 struct map_symbol *ms = browser->b.priv;
974 struct symbol *sym = ms->sym;
976 /* PLT symbols contain external offsets */
977 if (strstr(sym->name, "@plt"))
980 for (offset = 0; offset < size; ++offset) {
981 struct disasm_line *dl = browser->offsets[offset], *dlt;
982 struct browser_disasm_line *bdlt;
984 if (!disasm_line__is_valid_jump(dl, sym))
987 dlt = browser->offsets[dl->ops.target.offset];
989 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
990 * have to adjust to the previous offset?
995 bdlt = disasm_line__browser(dlt);
996 if (++bdlt->jump_sources > browser->max_jump_sources)
997 browser->max_jump_sources = bdlt->jump_sources;
1003 static inline int width_jumps(int n)
1012 int symbol__tui_annotate(struct symbol *sym, struct map *map,
1013 struct perf_evsel *evsel,
1014 struct hist_browser_timer *hbt)
1016 struct disasm_line *pos, *n;
1017 struct annotation *notes;
1019 struct map_symbol ms = {
1023 struct annotate_browser browser = {
1025 .refresh = annotate_browser__refresh,
1026 .seek = ui_browser__list_head_seek,
1027 .write = annotate_browser__write,
1028 .filter = disasm_line__filter,
1030 .use_navkeypressed = true,
1035 size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1040 size = symbol__size(sym);
1042 if (map->dso->annotate_warned)
1045 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1046 if (browser.offsets == NULL) {
1047 ui__error("Not enough memory!");
1051 if (perf_evsel__is_group_event(evsel)) {
1052 nr_pcnt = evsel->nr_members;
1053 sizeof_bdl += sizeof(struct disasm_line_samples) *
1057 err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl);
1060 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1061 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1062 goto out_free_offsets;
1065 ui_helpline__push("Press ESC to exit");
1067 notes = symbol__annotation(sym);
1068 browser.start = map__rip_2objdump(map, sym->start);
1070 list_for_each_entry(pos, ¬es->src->source, node) {
1071 struct browser_disasm_line *bpos;
1072 size_t line_len = strlen(pos->line);
1074 if (browser.b.width < line_len)
1075 browser.b.width = line_len;
1076 bpos = disasm_line__browser(pos);
1077 bpos->idx = browser.nr_entries++;
1078 if (pos->offset != -1) {
1079 bpos->idx_asm = browser.nr_asm_entries++;
1081 * FIXME: short term bandaid to cope with assembly
1082 * routines that comes with labels in the same column
1083 * as the address in objdump, sigh.
1085 * E.g. copy_user_generic_unrolled
1087 if (pos->offset < (s64)size)
1088 browser.offsets[pos->offset] = pos;
1093 annotate_browser__mark_jump_targets(&browser, size);
1094 annotate__compute_ipc(&browser, size, sym);
1096 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
1097 browser.max_addr_width = hex_width(sym->end);
1098 browser.jumps_width = width_jumps(browser.max_jump_sources);
1099 browser.nr_events = nr_pcnt;
1100 browser.b.nr_entries = browser.nr_entries;
1101 browser.b.entries = ¬es->src->source,
1102 browser.b.width += 18; /* Percentage */
1104 if (annotate_browser__opts.hide_src_code)
1105 annotate_browser__init_asm_mode(&browser);
1107 annotate_browser__update_addr_width(&browser);
1109 ret = annotate_browser__run(&browser, evsel, hbt);
1110 list_for_each_entry_safe(pos, n, ¬es->src->source, node) {
1111 list_del(&pos->node);
1112 disasm_line__free(pos);
1116 free(browser.offsets);
1120 #define ANNOTATE_CFG(n) \
1121 { .name = #n, .value = &annotate_browser__opts.n, }
1124 * Keep the entries sorted, they are bsearch'ed
1126 static struct annotate_config {
1129 } annotate__configs[] = {
1130 ANNOTATE_CFG(hide_src_code),
1131 ANNOTATE_CFG(jump_arrows),
1132 ANNOTATE_CFG(show_linenr),
1133 ANNOTATE_CFG(show_nr_jumps),
1134 ANNOTATE_CFG(show_total_period),
1135 ANNOTATE_CFG(use_offset),
1140 static int annotate_config__cmp(const void *name, const void *cfgp)
1142 const struct annotate_config *cfg = cfgp;
1144 return strcmp(name, cfg->name);
1147 static int annotate__config(const char *var, const char *value,
1148 void *data __maybe_unused)
1150 struct annotate_config *cfg;
1153 if (prefixcmp(var, "annotate.") != 0)
1157 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
1158 sizeof(struct annotate_config), annotate_config__cmp);
1161 ui__warning("%s variable unknown, ignoring...", var);
1163 *cfg->value = perf_config_bool(name, value);
1167 void annotate_browser__init(void)
1169 perf_config(annotate__config, NULL);