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.ops && dl->ins.ops->scnprintf) {
217 if (ins__is_jump(&dl->ins)) {
218 bool fwd = dl->ops.target.offset > 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.ops || !ins__is_jump(&dl->ins)
247 || !disasm_line__has_offset(dl)
248 || dl->ops.target.offset < 0
249 || dl->ops.target.offset >= (s64)symbol__size(sym))
255 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
257 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
258 struct disasm_line *cursor = ab->selection, *target;
259 struct browser_disasm_line *btarget, *bcursor;
260 unsigned int from, to;
261 struct map_symbol *ms = ab->b.priv;
262 struct symbol *sym = ms->sym;
263 u8 pcnt_width = annotate_browser__pcnt_width(ab);
265 /* PLT symbols contain external offsets */
266 if (strstr(sym->name, "@plt"))
269 if (!disasm_line__is_valid_jump(cursor, sym))
272 target = ab->offsets[cursor->ops.target.offset];
276 bcursor = disasm_line__browser(cursor);
277 btarget = disasm_line__browser(target);
279 if (annotate_browser__opts.hide_src_code) {
280 from = bcursor->idx_asm;
281 to = btarget->idx_asm;
283 from = (u64)bcursor->idx;
284 to = (u64)btarget->idx;
287 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
288 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
292 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
294 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
295 int ret = ui_browser__list_head_refresh(browser);
296 int pcnt_width = annotate_browser__pcnt_width(ab);
298 if (annotate_browser__opts.jump_arrows)
299 annotate_browser__draw_current_jump(browser);
301 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
302 __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
306 static int disasm__cmp(struct browser_disasm_line *a,
307 struct browser_disasm_line *b, int nr_pcnt)
311 for (i = 0; i < nr_pcnt; i++) {
312 if (a->samples[i].percent == b->samples[i].percent)
314 return a->samples[i].percent < b->samples[i].percent;
319 static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
322 struct rb_node **p = &root->rb_node;
323 struct rb_node *parent = NULL;
324 struct browser_disasm_line *l;
328 l = rb_entry(parent, struct browser_disasm_line, rb_node);
330 if (disasm__cmp(bdl, l, nr_events))
335 rb_link_node(&bdl->rb_node, parent, p);
336 rb_insert_color(&bdl->rb_node, root);
339 static void annotate_browser__set_top(struct annotate_browser *browser,
340 struct disasm_line *pos, u32 idx)
344 ui_browser__refresh_dimensions(&browser->b);
345 back = browser->b.height / 2;
346 browser->b.top_idx = browser->b.index = idx;
348 while (browser->b.top_idx != 0 && back != 0) {
349 pos = list_entry(pos->node.prev, struct disasm_line, node);
351 if (disasm_line__filter(&browser->b, &pos->node))
354 --browser->b.top_idx;
358 browser->b.top = pos;
359 browser->b.navkeypressed = true;
362 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
365 struct browser_disasm_line *bpos;
366 struct disasm_line *pos;
369 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
370 pos = ((struct disasm_line *)bpos) - 1;
372 if (annotate_browser__opts.hide_src_code)
374 annotate_browser__set_top(browser, pos, idx);
375 browser->curr_hot = nd;
378 static void annotate_browser__calc_percent(struct annotate_browser *browser,
379 struct perf_evsel *evsel)
381 struct map_symbol *ms = browser->b.priv;
382 struct symbol *sym = ms->sym;
383 struct annotation *notes = symbol__annotation(sym);
384 struct disasm_line *pos, *next;
385 s64 len = symbol__size(sym);
387 browser->entries = RB_ROOT;
389 pthread_mutex_lock(¬es->lock);
391 list_for_each_entry(pos, ¬es->src->source, node) {
392 struct browser_disasm_line *bpos = disasm_line__browser(pos);
393 const char *path = NULL;
394 double max_percent = 0.0;
397 if (pos->offset == -1) {
398 RB_CLEAR_NODE(&bpos->rb_node);
402 next = disasm__get_next_ip_line(¬es->src->source, pos);
404 for (i = 0; i < browser->nr_events; i++) {
407 bpos->samples[i].percent = disasm__calc_percent(notes,
410 next ? next->offset : len,
412 bpos->samples[i].nr = nr_samples;
414 if (max_percent < bpos->samples[i].percent)
415 max_percent = bpos->samples[i].percent;
418 if (max_percent < 0.01 && pos->ipc == 0) {
419 RB_CLEAR_NODE(&bpos->rb_node);
422 disasm_rb_tree__insert(&browser->entries, bpos,
425 pthread_mutex_unlock(¬es->lock);
427 browser->curr_hot = rb_last(&browser->entries);
430 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
432 struct disasm_line *dl;
433 struct browser_disasm_line *bdl;
434 off_t offset = browser->b.index - browser->b.top_idx;
436 browser->b.seek(&browser->b, offset, SEEK_CUR);
437 dl = list_entry(browser->b.top, struct disasm_line, node);
438 bdl = disasm_line__browser(dl);
440 if (annotate_browser__opts.hide_src_code) {
441 if (bdl->idx_asm < offset)
444 browser->b.nr_entries = browser->nr_entries;
445 annotate_browser__opts.hide_src_code = false;
446 browser->b.seek(&browser->b, -offset, SEEK_CUR);
447 browser->b.top_idx = bdl->idx - offset;
448 browser->b.index = bdl->idx;
450 if (bdl->idx_asm < 0) {
451 ui_helpline__puts("Only available for assembly lines.");
452 browser->b.seek(&browser->b, -offset, SEEK_CUR);
456 if (bdl->idx_asm < offset)
457 offset = bdl->idx_asm;
459 browser->b.nr_entries = browser->nr_asm_entries;
460 annotate_browser__opts.hide_src_code = true;
461 browser->b.seek(&browser->b, -offset, SEEK_CUR);
462 browser->b.top_idx = bdl->idx_asm - offset;
463 browser->b.index = bdl->idx_asm;
469 static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
471 ui_browser__reset_index(&browser->b);
472 browser->b.nr_entries = browser->nr_asm_entries;
475 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
477 static int sym_title(struct symbol *sym, struct map *map, char *title,
480 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
483 static bool annotate_browser__callq(struct annotate_browser *browser,
484 struct perf_evsel *evsel,
485 struct hist_browser_timer *hbt)
487 struct map_symbol *ms = browser->b.priv;
488 struct disasm_line *dl = browser->selection;
489 struct annotation *notes;
490 struct addr_map_symbol target = {
492 .addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
494 char title[SYM_TITLE_MAX_SIZE];
496 if (!ins__is_call(&dl->ins))
499 if (map_groups__find_ams(&target) ||
500 map__rip_2objdump(target.map, target.map->map_ip(target.map,
502 dl->ops.target.addr) {
503 ui_helpline__puts("The called function was not found.");
507 notes = symbol__annotation(target.sym);
508 pthread_mutex_lock(¬es->lock);
510 if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
511 pthread_mutex_unlock(¬es->lock);
512 ui__warning("Not enough memory for annotating '%s' symbol!\n",
517 pthread_mutex_unlock(¬es->lock);
518 symbol__tui_annotate(target.sym, target.map, evsel, hbt);
519 sym_title(ms->sym, ms->map, title, sizeof(title));
520 ui_browser__show_title(&browser->b, title);
525 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
526 s64 offset, s64 *idx)
528 struct map_symbol *ms = browser->b.priv;
529 struct symbol *sym = ms->sym;
530 struct annotation *notes = symbol__annotation(sym);
531 struct disasm_line *pos;
534 list_for_each_entry(pos, ¬es->src->source, node) {
535 if (pos->offset == offset)
537 if (!disasm_line__filter(&browser->b, &pos->node))
544 static bool annotate_browser__jump(struct annotate_browser *browser)
546 struct disasm_line *dl = browser->selection;
550 if (!ins__is_jump(&dl->ins))
553 offset = dl->ops.target.offset;
554 dl = annotate_browser__find_offset(browser, offset, &idx);
556 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
560 annotate_browser__set_top(browser, dl, idx);
566 struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
569 struct map_symbol *ms = browser->b.priv;
570 struct symbol *sym = ms->sym;
571 struct annotation *notes = symbol__annotation(sym);
572 struct disasm_line *pos = browser->selection;
574 *idx = browser->b.index;
575 list_for_each_entry_continue(pos, ¬es->src->source, node) {
576 if (disasm_line__filter(&browser->b, &pos->node))
581 if (pos->line && strstr(pos->line, s) != NULL)
588 static bool __annotate_browser__search(struct annotate_browser *browser)
590 struct disasm_line *dl;
593 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
595 ui_helpline__puts("String not found!");
599 annotate_browser__set_top(browser, dl, idx);
600 browser->searching_backwards = false;
605 struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
608 struct map_symbol *ms = browser->b.priv;
609 struct symbol *sym = ms->sym;
610 struct annotation *notes = symbol__annotation(sym);
611 struct disasm_line *pos = browser->selection;
613 *idx = browser->b.index;
614 list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) {
615 if (disasm_line__filter(&browser->b, &pos->node))
620 if (pos->line && strstr(pos->line, s) != NULL)
627 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
629 struct disasm_line *dl;
632 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
634 ui_helpline__puts("String not found!");
638 annotate_browser__set_top(browser, dl, idx);
639 browser->searching_backwards = true;
643 static bool annotate_browser__search_window(struct annotate_browser *browser,
646 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
647 "ENTER: OK, ESC: Cancel",
648 delay_secs * 2) != K_ENTER ||
649 !*browser->search_bf)
655 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
657 if (annotate_browser__search_window(browser, delay_secs))
658 return __annotate_browser__search(browser);
663 static bool annotate_browser__continue_search(struct annotate_browser *browser,
666 if (!*browser->search_bf)
667 return annotate_browser__search(browser, delay_secs);
669 return __annotate_browser__search(browser);
672 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
675 if (annotate_browser__search_window(browser, delay_secs))
676 return __annotate_browser__search_reverse(browser);
682 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
685 if (!*browser->search_bf)
686 return annotate_browser__search_reverse(browser, delay_secs);
688 return __annotate_browser__search_reverse(browser);
691 static void annotate_browser__update_addr_width(struct annotate_browser *browser)
693 if (annotate_browser__opts.use_offset)
694 browser->target_width = browser->min_addr_width;
696 browser->target_width = browser->max_addr_width;
698 browser->addr_width = browser->target_width;
700 if (annotate_browser__opts.show_nr_jumps)
701 browser->addr_width += browser->jumps_width + 1;
704 static int annotate_browser__run(struct annotate_browser *browser,
705 struct perf_evsel *evsel,
706 struct hist_browser_timer *hbt)
708 struct rb_node *nd = NULL;
709 struct map_symbol *ms = browser->b.priv;
710 struct symbol *sym = ms->sym;
711 const char *help = "Press 'h' for help on key bindings";
712 int delay_secs = hbt ? hbt->refresh : 0;
714 char title[SYM_TITLE_MAX_SIZE];
716 sym_title(sym, ms->map, title, sizeof(title));
717 if (ui_browser__show(&browser->b, title, help) < 0)
720 annotate_browser__calc_percent(browser, evsel);
722 if (browser->curr_hot) {
723 annotate_browser__set_rb_top(browser, browser->curr_hot);
724 browser->b.navkeypressed = false;
727 nd = browser->curr_hot;
730 key = ui_browser__run(&browser->b, delay_secs);
732 if (delay_secs != 0) {
733 annotate_browser__calc_percent(browser, evsel);
735 * Current line focus got out of the list of most active
736 * lines, NULL it so that if TAB|UNTAB is pressed, we
737 * move to curr_hot (current hottest line).
739 if (nd != NULL && RB_EMPTY_NODE(nd))
746 hbt->timer(hbt->arg);
749 symbol__annotate_decay_histogram(sym, evsel->idx);
755 nd = rb_last(&browser->entries);
757 nd = browser->curr_hot;
763 nd = rb_first(&browser->entries);
765 nd = browser->curr_hot;
769 ui_browser__help_window(&browser->b,
771 "PGDN/SPACE Navigate\n"
772 "q/ESC/CTRL+C Exit\n\n"
773 "ENTER Go to target\n"
775 "H Cycle thru hottest instructions\n"
776 "j Toggle showing jump to target arrows\n"
777 "J Toggle showing number of jump sources on targets\n"
778 "n Search next string\n"
779 "o Toggle disassembler output/simplified view\n"
780 "s Toggle source code view\n"
781 "t Toggle total period view\n"
783 "k Toggle line numbers\n"
784 "r Run available scripts\n"
785 "? Search string backwards\n");
793 annotate_browser__opts.show_linenr =
794 !annotate_browser__opts.show_linenr;
797 nd = browser->curr_hot;
800 if (annotate_browser__toggle_source(browser))
801 ui_helpline__puts(help);
804 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
805 annotate_browser__update_addr_width(browser);
808 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
811 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
812 annotate_browser__update_addr_width(browser);
815 if (annotate_browser__search(browser, delay_secs)) {
817 ui_helpline__puts(help);
821 if (browser->searching_backwards ?
822 annotate_browser__continue_search_reverse(browser, delay_secs) :
823 annotate_browser__continue_search(browser, delay_secs))
827 if (annotate_browser__search_reverse(browser, delay_secs))
833 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
834 seq++, browser->b.nr_entries,
838 browser->nr_asm_entries);
843 if (browser->selection == NULL)
844 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
845 else if (browser->selection->offset == -1)
846 ui_helpline__puts("Actions are only available for assembly lines.");
847 else if (!browser->selection->ins.ops)
849 else if (ins__is_ret(&browser->selection->ins))
851 else if (!(annotate_browser__jump(browser) ||
852 annotate_browser__callq(browser, evsel, hbt))) {
854 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
858 annotate_browser__opts.show_total_period =
859 !annotate_browser__opts.show_total_period;
860 annotate_browser__update_addr_width(browser);
872 annotate_browser__set_rb_top(browser, nd);
875 ui_browser__hide(&browser->b);
879 int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
880 struct hist_browser_timer *hbt)
882 /* Set default value for show_total_period. */
883 annotate_browser__opts.show_total_period =
884 symbol_conf.show_total_period;
886 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
889 int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
890 struct hist_browser_timer *hbt)
892 /* reset abort key so that it can get Ctrl-C as a key */
894 SLang_init_tty(0, 0, 0);
896 return map_symbol__tui_annotate(&he->ms, evsel, hbt);
900 static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
905 for (offset = start; offset <= end; offset++) {
906 if (browser->offsets[offset])
912 static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
918 n_insn = count_insn(browser, start, end);
919 if (n_insn && ch->num && ch->cycles) {
920 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
922 /* Hide data when there are too many overlaps. */
923 if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
926 for (offset = start; offset <= end; offset++) {
927 struct disasm_line *dl = browser->offsets[offset];
936 * This should probably be in util/annotate.c to share with the tty
937 * annotate, but right now we need the per byte offsets arrays,
938 * which are only here.
940 static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
944 struct annotation *notes = symbol__annotation(sym);
946 if (!notes->src || !notes->src->cycles_hist)
949 pthread_mutex_lock(¬es->lock);
950 for (offset = 0; offset < size; ++offset) {
953 ch = ¬es->src->cycles_hist[offset];
954 if (ch && ch->cycles) {
955 struct disasm_line *dl;
958 count_and_fill(browser, ch->start, offset, ch);
959 dl = browser->offsets[offset];
960 if (dl && ch->num_aggr)
961 dl->cycles = ch->cycles_aggr / ch->num_aggr;
962 browser->have_cycles = true;
965 pthread_mutex_unlock(¬es->lock);
968 static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
972 struct map_symbol *ms = browser->b.priv;
973 struct symbol *sym = ms->sym;
975 /* PLT symbols contain external offsets */
976 if (strstr(sym->name, "@plt"))
979 for (offset = 0; offset < size; ++offset) {
980 struct disasm_line *dl = browser->offsets[offset], *dlt;
981 struct browser_disasm_line *bdlt;
983 if (!disasm_line__is_valid_jump(dl, sym))
986 dlt = browser->offsets[dl->ops.target.offset];
988 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
989 * have to adjust to the previous offset?
994 bdlt = disasm_line__browser(dlt);
995 if (++bdlt->jump_sources > browser->max_jump_sources)
996 browser->max_jump_sources = bdlt->jump_sources;
1002 static inline int width_jumps(int n)
1011 int symbol__tui_annotate(struct symbol *sym, struct map *map,
1012 struct perf_evsel *evsel,
1013 struct hist_browser_timer *hbt)
1015 struct disasm_line *pos, *n;
1016 struct annotation *notes;
1018 struct map_symbol ms = {
1022 struct annotate_browser browser = {
1024 .refresh = annotate_browser__refresh,
1025 .seek = ui_browser__list_head_seek,
1026 .write = annotate_browser__write,
1027 .filter = disasm_line__filter,
1029 .use_navkeypressed = true,
1034 size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1039 size = symbol__size(sym);
1041 if (map->dso->annotate_warned)
1044 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1045 if (browser.offsets == NULL) {
1046 ui__error("Not enough memory!");
1050 if (perf_evsel__is_group_event(evsel)) {
1051 nr_pcnt = evsel->nr_members;
1052 sizeof_bdl += sizeof(struct disasm_line_samples) *
1056 err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl);
1059 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1060 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1061 goto out_free_offsets;
1064 ui_helpline__push("Press ESC to exit");
1066 notes = symbol__annotation(sym);
1067 browser.start = map__rip_2objdump(map, sym->start);
1069 list_for_each_entry(pos, ¬es->src->source, node) {
1070 struct browser_disasm_line *bpos;
1071 size_t line_len = strlen(pos->line);
1073 if (browser.b.width < line_len)
1074 browser.b.width = line_len;
1075 bpos = disasm_line__browser(pos);
1076 bpos->idx = browser.nr_entries++;
1077 if (pos->offset != -1) {
1078 bpos->idx_asm = browser.nr_asm_entries++;
1080 * FIXME: short term bandaid to cope with assembly
1081 * routines that comes with labels in the same column
1082 * as the address in objdump, sigh.
1084 * E.g. copy_user_generic_unrolled
1086 if (pos->offset < (s64)size)
1087 browser.offsets[pos->offset] = pos;
1092 annotate_browser__mark_jump_targets(&browser, size);
1093 annotate__compute_ipc(&browser, size, sym);
1095 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
1096 browser.max_addr_width = hex_width(sym->end);
1097 browser.jumps_width = width_jumps(browser.max_jump_sources);
1098 browser.nr_events = nr_pcnt;
1099 browser.b.nr_entries = browser.nr_entries;
1100 browser.b.entries = ¬es->src->source,
1101 browser.b.width += 18; /* Percentage */
1103 if (annotate_browser__opts.hide_src_code)
1104 annotate_browser__init_asm_mode(&browser);
1106 annotate_browser__update_addr_width(&browser);
1108 ret = annotate_browser__run(&browser, evsel, hbt);
1109 list_for_each_entry_safe(pos, n, ¬es->src->source, node) {
1110 list_del(&pos->node);
1111 disasm_line__free(pos);
1115 free(browser.offsets);
1119 #define ANNOTATE_CFG(n) \
1120 { .name = #n, .value = &annotate_browser__opts.n, }
1123 * Keep the entries sorted, they are bsearch'ed
1125 static struct annotate_config {
1128 } annotate__configs[] = {
1129 ANNOTATE_CFG(hide_src_code),
1130 ANNOTATE_CFG(jump_arrows),
1131 ANNOTATE_CFG(show_linenr),
1132 ANNOTATE_CFG(show_nr_jumps),
1133 ANNOTATE_CFG(show_total_period),
1134 ANNOTATE_CFG(use_offset),
1139 static int annotate_config__cmp(const void *name, const void *cfgp)
1141 const struct annotate_config *cfg = cfgp;
1143 return strcmp(name, cfg->name);
1146 static int annotate__config(const char *var, const char *value,
1147 void *data __maybe_unused)
1149 struct annotate_config *cfg;
1152 if (prefixcmp(var, "annotate.") != 0)
1156 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
1157 sizeof(struct annotate_config), annotate_config__cmp);
1160 ui__warning("%s variable unknown, ignoring...", var);
1162 *cfg->value = perf_config_bool(name, value);
1166 void annotate_browser__init(void)
1168 perf_config(annotate__config, NULL);