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 struct disasm_line_samples {
20 #define CYCLES_WIDTH 6
22 struct browser_disasm_line {
23 struct rb_node rb_node;
28 * actual length of this array is saved on the nr_events field
29 * of the struct annotate_browser
31 struct disasm_line_samples samples[1];
34 static struct annotate_browser_opt {
41 } annotate_browser__opts = {
46 struct annotate_browser {
48 struct rb_root entries;
49 struct rb_node *curr_hot;
50 struct disasm_line *selection;
51 struct disasm_line **offsets;
58 bool searching_backwards;
68 static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
70 return (struct browser_disasm_line *)(dl + 1);
73 static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
76 if (annotate_browser__opts.hide_src_code) {
77 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
78 return dl->offset == -1;
84 static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
87 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
88 return HE_COLORSET_SELECTED;
89 if (nr == browser->max_jump_sources)
90 return HE_COLORSET_TOP;
92 return HE_COLORSET_MEDIUM;
93 return HE_COLORSET_NORMAL;
96 static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
99 int color = annotate_browser__jumps_percent_color(browser, nr, current);
100 return ui_browser__set_color(&browser->b, color);
103 static int annotate_browser__pcnt_width(struct annotate_browser *ab)
105 int w = 7 * ab->nr_events;
108 w += IPC_WIDTH + CYCLES_WIDTH;
112 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
114 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
115 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
116 struct browser_disasm_line *bdl = disasm_line__browser(dl);
117 bool current_entry = ui_browser__is_current_entry(browser, row);
118 bool change_color = (!annotate_browser__opts.hide_src_code &&
119 (!current_entry || (browser->use_navkeypressed &&
120 !browser->navkeypressed)));
121 int width = browser->width, printed;
122 int i, pcnt_width = annotate_browser__pcnt_width(ab);
123 double percent_max = 0.0;
126 for (i = 0; i < ab->nr_events; i++) {
127 if (bdl->samples[i].percent > percent_max)
128 percent_max = bdl->samples[i].percent;
131 if (dl->offset != -1 && percent_max != 0.0) {
132 if (percent_max != 0.0) {
133 for (i = 0; i < ab->nr_events; i++) {
134 ui_browser__set_percent_color(browser,
135 bdl->samples[i].percent,
137 if (annotate_browser__opts.show_total_period) {
138 ui_browser__printf(browser, "%6" PRIu64 " ",
141 ui_browser__printf(browser, "%6.2f ",
142 bdl->samples[i].percent);
146 ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
149 ui_browser__set_percent_color(browser, 0, current_entry);
150 ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
152 if (ab->have_cycles) {
154 ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
156 ui_browser__write_nstring(browser, " ", IPC_WIDTH);
158 ui_browser__printf(browser, "%*" PRIu64 " ",
159 CYCLES_WIDTH - 1, dl->cycles);
161 ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
164 SLsmg_write_char(' ');
166 /* The scroll bar isn't being used */
167 if (!browser->navkeypressed)
171 ui_browser__write_nstring(browser, " ", width - pcnt_width);
172 else if (dl->offset == -1) {
173 if (dl->line_nr && annotate_browser__opts.show_linenr)
174 printed = scnprintf(bf, sizeof(bf), "%-*d ",
175 ab->addr_width + 1, dl->line_nr);
177 printed = scnprintf(bf, sizeof(bf), "%*s ",
178 ab->addr_width, " ");
179 ui_browser__write_nstring(browser, bf, printed);
180 ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
182 u64 addr = dl->offset;
185 if (!annotate_browser__opts.use_offset)
188 if (!annotate_browser__opts.use_offset) {
189 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
191 if (bdl->jump_sources) {
192 if (annotate_browser__opts.show_nr_jumps) {
194 printed = scnprintf(bf, sizeof(bf), "%*d ",
197 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
199 ui_browser__write_nstring(browser, bf, printed);
200 ui_browser__set_color(browser, prev);
203 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
204 ab->target_width, addr);
206 printed = scnprintf(bf, sizeof(bf), "%*s ",
207 ab->addr_width, " ");
212 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
213 ui_browser__write_nstring(browser, bf, printed);
215 ui_browser__set_color(browser, color);
216 if (dl->ins && dl->ins->ops->scnprintf) {
217 if (ins__is_jump(dl->ins)) {
218 bool fwd = dl->ops.target.offset > (u64)dl->offset;
220 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
222 SLsmg_write_char(' ');
223 } else if (ins__is_call(dl->ins)) {
224 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
225 SLsmg_write_char(' ');
226 } else if (ins__is_ret(dl->ins)) {
227 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
228 SLsmg_write_char(' ');
230 ui_browser__write_nstring(browser, " ", 2);
233 ui_browser__write_nstring(browser, " ", 2);
236 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
237 ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
244 static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
246 if (!dl || !dl->ins || !ins__is_jump(dl->ins)
247 || !disasm_line__has_offset(dl)
248 || dl->ops.target.offset >= symbol__size(sym))
254 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
256 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
257 struct disasm_line *cursor = ab->selection, *target;
258 struct browser_disasm_line *btarget, *bcursor;
259 unsigned int from, to;
260 struct map_symbol *ms = ab->b.priv;
261 struct symbol *sym = ms->sym;
262 u8 pcnt_width = annotate_browser__pcnt_width(ab);
264 /* PLT symbols contain external offsets */
265 if (strstr(sym->name, "@plt"))
268 if (!disasm_line__is_valid_jump(cursor, sym))
271 target = ab->offsets[cursor->ops.target.offset];
275 bcursor = disasm_line__browser(cursor);
276 btarget = disasm_line__browser(target);
278 if (annotate_browser__opts.hide_src_code) {
279 from = bcursor->idx_asm;
280 to = btarget->idx_asm;
282 from = (u64)bcursor->idx;
283 to = (u64)btarget->idx;
286 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
287 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
291 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
293 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
294 int ret = ui_browser__list_head_refresh(browser);
295 int pcnt_width = annotate_browser__pcnt_width(ab);
297 if (annotate_browser__opts.jump_arrows)
298 annotate_browser__draw_current_jump(browser);
300 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
301 __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
305 static int disasm__cmp(struct browser_disasm_line *a,
306 struct browser_disasm_line *b, int nr_pcnt)
310 for (i = 0; i < nr_pcnt; i++) {
311 if (a->samples[i].percent == b->samples[i].percent)
313 return a->samples[i].percent < b->samples[i].percent;
318 static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
321 struct rb_node **p = &root->rb_node;
322 struct rb_node *parent = NULL;
323 struct browser_disasm_line *l;
327 l = rb_entry(parent, struct browser_disasm_line, rb_node);
329 if (disasm__cmp(bdl, l, nr_events))
334 rb_link_node(&bdl->rb_node, parent, p);
335 rb_insert_color(&bdl->rb_node, root);
338 static void annotate_browser__set_top(struct annotate_browser *browser,
339 struct disasm_line *pos, u32 idx)
343 ui_browser__refresh_dimensions(&browser->b);
344 back = browser->b.height / 2;
345 browser->b.top_idx = browser->b.index = idx;
347 while (browser->b.top_idx != 0 && back != 0) {
348 pos = list_entry(pos->node.prev, struct disasm_line, node);
350 if (disasm_line__filter(&browser->b, &pos->node))
353 --browser->b.top_idx;
357 browser->b.top = pos;
358 browser->b.navkeypressed = true;
361 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
364 struct browser_disasm_line *bpos;
365 struct disasm_line *pos;
368 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
369 pos = ((struct disasm_line *)bpos) - 1;
371 if (annotate_browser__opts.hide_src_code)
373 annotate_browser__set_top(browser, pos, idx);
374 browser->curr_hot = nd;
377 static void annotate_browser__calc_percent(struct annotate_browser *browser,
378 struct perf_evsel *evsel)
380 struct map_symbol *ms = browser->b.priv;
381 struct symbol *sym = ms->sym;
382 struct annotation *notes = symbol__annotation(sym);
383 struct disasm_line *pos, *next;
384 s64 len = symbol__size(sym);
386 browser->entries = RB_ROOT;
388 pthread_mutex_lock(¬es->lock);
390 list_for_each_entry(pos, ¬es->src->source, node) {
391 struct browser_disasm_line *bpos = disasm_line__browser(pos);
392 const char *path = NULL;
393 double max_percent = 0.0;
396 if (pos->offset == -1) {
397 RB_CLEAR_NODE(&bpos->rb_node);
401 next = disasm__get_next_ip_line(¬es->src->source, pos);
403 for (i = 0; i < browser->nr_events; i++) {
406 bpos->samples[i].percent = disasm__calc_percent(notes,
409 next ? next->offset : len,
411 bpos->samples[i].nr = nr_samples;
413 if (max_percent < bpos->samples[i].percent)
414 max_percent = bpos->samples[i].percent;
417 if (max_percent < 0.01 && pos->ipc == 0) {
418 RB_CLEAR_NODE(&bpos->rb_node);
421 disasm_rb_tree__insert(&browser->entries, bpos,
424 pthread_mutex_unlock(¬es->lock);
426 browser->curr_hot = rb_last(&browser->entries);
429 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
431 struct disasm_line *dl;
432 struct browser_disasm_line *bdl;
433 off_t offset = browser->b.index - browser->b.top_idx;
435 browser->b.seek(&browser->b, offset, SEEK_CUR);
436 dl = list_entry(browser->b.top, struct disasm_line, node);
437 bdl = disasm_line__browser(dl);
439 if (annotate_browser__opts.hide_src_code) {
440 if (bdl->idx_asm < offset)
443 browser->b.nr_entries = browser->nr_entries;
444 annotate_browser__opts.hide_src_code = false;
445 browser->b.seek(&browser->b, -offset, SEEK_CUR);
446 browser->b.top_idx = bdl->idx - offset;
447 browser->b.index = bdl->idx;
449 if (bdl->idx_asm < 0) {
450 ui_helpline__puts("Only available for assembly lines.");
451 browser->b.seek(&browser->b, -offset, SEEK_CUR);
455 if (bdl->idx_asm < offset)
456 offset = bdl->idx_asm;
458 browser->b.nr_entries = browser->nr_asm_entries;
459 annotate_browser__opts.hide_src_code = true;
460 browser->b.seek(&browser->b, -offset, SEEK_CUR);
461 browser->b.top_idx = bdl->idx_asm - offset;
462 browser->b.index = bdl->idx_asm;
468 static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
470 ui_browser__reset_index(&browser->b);
471 browser->b.nr_entries = browser->nr_asm_entries;
474 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
476 static int sym_title(struct symbol *sym, struct map *map, char *title,
479 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
482 static bool annotate_browser__callq(struct annotate_browser *browser,
483 struct perf_evsel *evsel,
484 struct hist_browser_timer *hbt)
486 struct map_symbol *ms = browser->b.priv;
487 struct disasm_line *dl = browser->selection;
488 struct annotation *notes;
489 struct addr_map_symbol target = {
491 .addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
493 char title[SYM_TITLE_MAX_SIZE];
495 if (!ins__is_call(dl->ins))
498 if (map_groups__find_ams(&target, NULL) ||
499 map__rip_2objdump(target.map, target.map->map_ip(target.map,
501 dl->ops.target.addr) {
502 ui_helpline__puts("The called function was not found.");
506 notes = symbol__annotation(target.sym);
507 pthread_mutex_lock(¬es->lock);
509 if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
510 pthread_mutex_unlock(¬es->lock);
511 ui__warning("Not enough memory for annotating '%s' symbol!\n",
516 pthread_mutex_unlock(¬es->lock);
517 symbol__tui_annotate(target.sym, target.map, evsel, hbt);
518 sym_title(ms->sym, ms->map, title, sizeof(title));
519 ui_browser__show_title(&browser->b, title);
524 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
525 s64 offset, s64 *idx)
527 struct map_symbol *ms = browser->b.priv;
528 struct symbol *sym = ms->sym;
529 struct annotation *notes = symbol__annotation(sym);
530 struct disasm_line *pos;
533 list_for_each_entry(pos, ¬es->src->source, node) {
534 if (pos->offset == offset)
536 if (!disasm_line__filter(&browser->b, &pos->node))
543 static bool annotate_browser__jump(struct annotate_browser *browser)
545 struct disasm_line *dl = browser->selection;
548 if (!ins__is_jump(dl->ins))
551 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
553 ui_helpline__puts("Invalid jump offset");
557 annotate_browser__set_top(browser, dl, idx);
563 struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
566 struct map_symbol *ms = browser->b.priv;
567 struct symbol *sym = ms->sym;
568 struct annotation *notes = symbol__annotation(sym);
569 struct disasm_line *pos = browser->selection;
571 *idx = browser->b.index;
572 list_for_each_entry_continue(pos, ¬es->src->source, node) {
573 if (disasm_line__filter(&browser->b, &pos->node))
578 if (pos->line && strstr(pos->line, s) != NULL)
585 static bool __annotate_browser__search(struct annotate_browser *browser)
587 struct disasm_line *dl;
590 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
592 ui_helpline__puts("String not found!");
596 annotate_browser__set_top(browser, dl, idx);
597 browser->searching_backwards = false;
602 struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
605 struct map_symbol *ms = browser->b.priv;
606 struct symbol *sym = ms->sym;
607 struct annotation *notes = symbol__annotation(sym);
608 struct disasm_line *pos = browser->selection;
610 *idx = browser->b.index;
611 list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) {
612 if (disasm_line__filter(&browser->b, &pos->node))
617 if (pos->line && strstr(pos->line, s) != NULL)
624 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
626 struct disasm_line *dl;
629 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
631 ui_helpline__puts("String not found!");
635 annotate_browser__set_top(browser, dl, idx);
636 browser->searching_backwards = true;
640 static bool annotate_browser__search_window(struct annotate_browser *browser,
643 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
644 "ENTER: OK, ESC: Cancel",
645 delay_secs * 2) != K_ENTER ||
646 !*browser->search_bf)
652 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
654 if (annotate_browser__search_window(browser, delay_secs))
655 return __annotate_browser__search(browser);
660 static bool annotate_browser__continue_search(struct annotate_browser *browser,
663 if (!*browser->search_bf)
664 return annotate_browser__search(browser, delay_secs);
666 return __annotate_browser__search(browser);
669 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
672 if (annotate_browser__search_window(browser, delay_secs))
673 return __annotate_browser__search_reverse(browser);
679 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
682 if (!*browser->search_bf)
683 return annotate_browser__search_reverse(browser, delay_secs);
685 return __annotate_browser__search_reverse(browser);
688 static void annotate_browser__update_addr_width(struct annotate_browser *browser)
690 if (annotate_browser__opts.use_offset)
691 browser->target_width = browser->min_addr_width;
693 browser->target_width = browser->max_addr_width;
695 browser->addr_width = browser->target_width;
697 if (annotate_browser__opts.show_nr_jumps)
698 browser->addr_width += browser->jumps_width + 1;
701 static int annotate_browser__run(struct annotate_browser *browser,
702 struct perf_evsel *evsel,
703 struct hist_browser_timer *hbt)
705 struct rb_node *nd = NULL;
706 struct map_symbol *ms = browser->b.priv;
707 struct symbol *sym = ms->sym;
708 const char *help = "Press 'h' for help on key bindings";
709 int delay_secs = hbt ? hbt->refresh : 0;
711 char title[SYM_TITLE_MAX_SIZE];
713 sym_title(sym, ms->map, title, sizeof(title));
714 if (ui_browser__show(&browser->b, title, help) < 0)
717 annotate_browser__calc_percent(browser, evsel);
719 if (browser->curr_hot) {
720 annotate_browser__set_rb_top(browser, browser->curr_hot);
721 browser->b.navkeypressed = false;
724 nd = browser->curr_hot;
727 key = ui_browser__run(&browser->b, delay_secs);
729 if (delay_secs != 0) {
730 annotate_browser__calc_percent(browser, evsel);
732 * Current line focus got out of the list of most active
733 * lines, NULL it so that if TAB|UNTAB is pressed, we
734 * move to curr_hot (current hottest line).
736 if (nd != NULL && RB_EMPTY_NODE(nd))
743 hbt->timer(hbt->arg);
746 symbol__annotate_decay_histogram(sym, evsel->idx);
752 nd = rb_last(&browser->entries);
754 nd = browser->curr_hot;
760 nd = rb_first(&browser->entries);
762 nd = browser->curr_hot;
766 ui_browser__help_window(&browser->b,
768 "PGDN/SPACE Navigate\n"
769 "q/ESC/CTRL+C Exit\n\n"
770 "ENTER Go to target\n"
772 "H Cycle thru hottest instructions\n"
773 "j Toggle showing jump to target arrows\n"
774 "J Toggle showing number of jump sources on targets\n"
775 "n Search next string\n"
776 "o Toggle disassembler output/simplified view\n"
777 "s Toggle source code view\n"
778 "t Toggle total period view\n"
780 "k Toggle line numbers\n"
781 "r Run available scripts\n"
782 "? Search string backwards\n");
790 annotate_browser__opts.show_linenr =
791 !annotate_browser__opts.show_linenr;
794 nd = browser->curr_hot;
797 if (annotate_browser__toggle_source(browser))
798 ui_helpline__puts(help);
801 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
802 annotate_browser__update_addr_width(browser);
805 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
808 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
809 annotate_browser__update_addr_width(browser);
812 if (annotate_browser__search(browser, delay_secs)) {
814 ui_helpline__puts(help);
818 if (browser->searching_backwards ?
819 annotate_browser__continue_search_reverse(browser, delay_secs) :
820 annotate_browser__continue_search(browser, delay_secs))
824 if (annotate_browser__search_reverse(browser, delay_secs))
830 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
831 seq++, browser->b.nr_entries,
835 browser->nr_asm_entries);
840 if (browser->selection == NULL)
841 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
842 else if (browser->selection->offset == -1)
843 ui_helpline__puts("Actions are only available for assembly lines.");
844 else if (!browser->selection->ins)
846 else if (ins__is_ret(browser->selection->ins))
848 else if (!(annotate_browser__jump(browser) ||
849 annotate_browser__callq(browser, evsel, hbt))) {
851 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
855 annotate_browser__opts.show_total_period =
856 !annotate_browser__opts.show_total_period;
857 annotate_browser__update_addr_width(browser);
869 annotate_browser__set_rb_top(browser, nd);
872 ui_browser__hide(&browser->b);
876 int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
877 struct hist_browser_timer *hbt)
879 /* Set default value for show_total_period. */
880 annotate_browser__opts.show_total_period =
881 symbol_conf.show_total_period;
883 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
886 int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
887 struct hist_browser_timer *hbt)
889 /* reset abort key so that it can get Ctrl-C as a key */
891 SLang_init_tty(0, 0, 0);
893 return map_symbol__tui_annotate(&he->ms, evsel, hbt);
897 static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
902 for (offset = start; offset <= end; offset++) {
903 if (browser->offsets[offset])
909 static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
915 n_insn = count_insn(browser, start, end);
916 if (n_insn && ch->num && ch->cycles) {
917 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
919 /* Hide data when there are too many overlaps. */
920 if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
923 for (offset = start; offset <= end; offset++) {
924 struct disasm_line *dl = browser->offsets[offset];
933 * This should probably be in util/annotate.c to share with the tty
934 * annotate, but right now we need the per byte offsets arrays,
935 * which are only here.
937 static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
941 struct annotation *notes = symbol__annotation(sym);
943 if (!notes->src || !notes->src->cycles_hist)
946 pthread_mutex_lock(¬es->lock);
947 for (offset = 0; offset < size; ++offset) {
950 ch = ¬es->src->cycles_hist[offset];
951 if (ch && ch->cycles) {
952 struct disasm_line *dl;
955 count_and_fill(browser, ch->start, offset, ch);
956 dl = browser->offsets[offset];
957 if (dl && ch->num_aggr)
958 dl->cycles = ch->cycles_aggr / ch->num_aggr;
959 browser->have_cycles = true;
962 pthread_mutex_unlock(¬es->lock);
965 static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
969 struct map_symbol *ms = browser->b.priv;
970 struct symbol *sym = ms->sym;
972 /* PLT symbols contain external offsets */
973 if (strstr(sym->name, "@plt"))
976 for (offset = 0; offset < size; ++offset) {
977 struct disasm_line *dl = browser->offsets[offset], *dlt;
978 struct browser_disasm_line *bdlt;
980 if (!disasm_line__is_valid_jump(dl, sym))
983 dlt = browser->offsets[dl->ops.target.offset];
985 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
986 * have to adjust to the previous offset?
991 bdlt = disasm_line__browser(dlt);
992 if (++bdlt->jump_sources > browser->max_jump_sources)
993 browser->max_jump_sources = bdlt->jump_sources;
999 static inline int width_jumps(int n)
1008 int symbol__tui_annotate(struct symbol *sym, struct map *map,
1009 struct perf_evsel *evsel,
1010 struct hist_browser_timer *hbt)
1012 struct disasm_line *pos, *n;
1013 struct annotation *notes;
1015 struct map_symbol ms = {
1019 struct annotate_browser browser = {
1021 .refresh = annotate_browser__refresh,
1022 .seek = ui_browser__list_head_seek,
1023 .write = annotate_browser__write,
1024 .filter = disasm_line__filter,
1026 .use_navkeypressed = true,
1031 size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1036 size = symbol__size(sym);
1038 if (map->dso->annotate_warned)
1041 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1042 if (browser.offsets == NULL) {
1043 ui__error("Not enough memory!");
1047 if (perf_evsel__is_group_event(evsel)) {
1048 nr_pcnt = evsel->nr_members;
1049 sizeof_bdl += sizeof(struct disasm_line_samples) *
1053 err = symbol__disassemble(sym, map, sizeof_bdl);
1056 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1057 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1058 goto out_free_offsets;
1061 ui_helpline__push("Press ESC to exit");
1063 notes = symbol__annotation(sym);
1064 browser.start = map__rip_2objdump(map, sym->start);
1066 list_for_each_entry(pos, ¬es->src->source, node) {
1067 struct browser_disasm_line *bpos;
1068 size_t line_len = strlen(pos->line);
1070 if (browser.b.width < line_len)
1071 browser.b.width = line_len;
1072 bpos = disasm_line__browser(pos);
1073 bpos->idx = browser.nr_entries++;
1074 if (pos->offset != -1) {
1075 bpos->idx_asm = browser.nr_asm_entries++;
1077 * FIXME: short term bandaid to cope with assembly
1078 * routines that comes with labels in the same column
1079 * as the address in objdump, sigh.
1081 * E.g. copy_user_generic_unrolled
1083 if (pos->offset < (s64)size)
1084 browser.offsets[pos->offset] = pos;
1089 annotate_browser__mark_jump_targets(&browser, size);
1090 annotate__compute_ipc(&browser, size, sym);
1092 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
1093 browser.max_addr_width = hex_width(sym->end);
1094 browser.jumps_width = width_jumps(browser.max_jump_sources);
1095 browser.nr_events = nr_pcnt;
1096 browser.b.nr_entries = browser.nr_entries;
1097 browser.b.entries = ¬es->src->source,
1098 browser.b.width += 18; /* Percentage */
1100 if (annotate_browser__opts.hide_src_code)
1101 annotate_browser__init_asm_mode(&browser);
1103 annotate_browser__update_addr_width(&browser);
1105 ret = annotate_browser__run(&browser, evsel, hbt);
1106 list_for_each_entry_safe(pos, n, ¬es->src->source, node) {
1107 list_del(&pos->node);
1108 disasm_line__free(pos);
1112 free(browser.offsets);
1116 #define ANNOTATE_CFG(n) \
1117 { .name = #n, .value = &annotate_browser__opts.n, }
1120 * Keep the entries sorted, they are bsearch'ed
1122 static struct annotate_config {
1125 } annotate__configs[] = {
1126 ANNOTATE_CFG(hide_src_code),
1127 ANNOTATE_CFG(jump_arrows),
1128 ANNOTATE_CFG(show_linenr),
1129 ANNOTATE_CFG(show_nr_jumps),
1130 ANNOTATE_CFG(show_total_period),
1131 ANNOTATE_CFG(use_offset),
1136 static int annotate_config__cmp(const void *name, const void *cfgp)
1138 const struct annotate_config *cfg = cfgp;
1140 return strcmp(name, cfg->name);
1143 static int annotate__config(const char *var, const char *value,
1144 void *data __maybe_unused)
1146 struct annotate_config *cfg;
1149 if (prefixcmp(var, "annotate.") != 0)
1153 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
1154 sizeof(struct annotate_config), annotate_config__cmp);
1157 ui__warning("%s variable unknown, ignoring...", var);
1159 *cfg->value = perf_config_bool(name, value);
1163 void annotate_browser__init(void)
1165 perf_config(annotate__config, NULL);