]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - tools/perf/ui/browsers/annotate.c
perf annotate browser: Display titles in left frame
[mirror_ubuntu-artful-kernel.git] / tools / perf / ui / browsers / annotate.c
CommitLineData
aca7a94d 1#include "../../util/util.h"
211ef127
ACM
2#include "../browser.h"
3#include "../helpline.h"
ae55795e
ACM
4#include "../ui.h"
5#include "../util.h"
aca7a94d
NK
6#include "../../util/annotate.h"
7#include "../../util/hist.h"
8#include "../../util/sort.h"
9#include "../../util/symbol.h"
db8fd07a 10#include "../../util/evsel.h"
41840d21 11#include "../../util/config.h"
fd20e811 12#include <inttypes.h>
c97cf422 13#include <pthread.h>
877a7a11 14#include <linux/kernel.h>
b0742e90 15#include <sys/ttydefaults.h>
211ef127 16
0c4a5bce
ML
17struct disasm_line_samples {
18 double percent;
19 u64 nr;
20};
21
f8f4aaea
AK
22#define IPC_WIDTH 6
23#define CYCLES_WIDTH 6
24
b793a401 25struct browser_disasm_line {
0c4a5bce
ML
26 struct rb_node rb_node;
27 u32 idx;
28 int idx_asm;
29 int jump_sources;
c7e7b610
NK
30 /*
31 * actual length of this array is saved on the nr_events field
32 * of the struct annotate_browser
33 */
0c4a5bce 34 struct disasm_line_samples samples[1];
b793a401
ACM
35};
36
e9823b21
ACM
37static struct annotate_browser_opt {
38 bool hide_src_code,
39 use_offset,
40 jump_arrows,
e592488c 41 show_linenr,
0c4a5bce
ML
42 show_nr_jumps,
43 show_total_period;
e9823b21
ACM
44} annotate_browser__opts = {
45 .use_offset = true,
46 .jump_arrows = true,
47};
48
92221162
ACM
49struct annotate_browser {
50 struct ui_browser b;
51 struct rb_root entries;
f1e9214c 52 struct rb_node *curr_hot;
c7e7b610 53 struct disasm_line *selection;
b793a401 54 struct disasm_line **offsets;
c7e7b610 55 int nr_events;
058b4cc9 56 u64 start;
0361fc25
ACM
57 int nr_asm_entries;
58 int nr_entries;
2402e4a9
ACM
59 int max_jump_sources;
60 int nr_jumps;
d3d1f61a 61 bool searching_backwards;
30e863bb 62 bool have_cycles;
83b1f2aa 63 u8 addr_width;
2402e4a9
ACM
64 u8 jumps_width;
65 u8 target_width;
83b1f2aa
ACM
66 u8 min_addr_width;
67 u8 max_addr_width;
d3d1f61a 68 char search_bf[128];
92221162
ACM
69};
70
887c0066 71static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
92221162 72{
887c0066 73 return (struct browser_disasm_line *)(dl + 1);
92221162
ACM
74}
75
1d037ca1
IT
76static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
77 void *entry)
0361fc25 78{
e9823b21 79 if (annotate_browser__opts.hide_src_code) {
29ed6e76
ACM
80 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
81 return dl->offset == -1;
0361fc25
ACM
82 }
83
84 return false;
85}
86
2402e4a9
ACM
87static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
88 int nr, bool current)
89{
90 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
91 return HE_COLORSET_SELECTED;
92 if (nr == browser->max_jump_sources)
93 return HE_COLORSET_TOP;
94 if (nr > 1)
95 return HE_COLORSET_MEDIUM;
96 return HE_COLORSET_NORMAL;
97}
98
99static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
100 int nr, bool current)
101{
102 int color = annotate_browser__jumps_percent_color(browser, nr, current);
103 return ui_browser__set_color(&browser->b, color);
104}
105
f8f4aaea
AK
106static int annotate_browser__pcnt_width(struct annotate_browser *ab)
107{
108 int w = 7 * ab->nr_events;
109
110 if (ab->have_cycles)
111 w += IPC_WIDTH + CYCLES_WIDTH;
112 return w;
113}
114
05e8b080 115static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
211ef127 116{
05e8b080 117 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
29ed6e76 118 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
b793a401 119 struct browser_disasm_line *bdl = disasm_line__browser(dl);
05e8b080 120 bool current_entry = ui_browser__is_current_entry(browser, row);
e9823b21 121 bool change_color = (!annotate_browser__opts.hide_src_code &&
05e8b080
ACM
122 (!current_entry || (browser->use_navkeypressed &&
123 !browser->navkeypressed)));
124 int width = browser->width, printed;
f8f4aaea 125 int i, pcnt_width = annotate_browser__pcnt_width(ab);
c7e7b610 126 double percent_max = 0.0;
83b1f2aa 127 char bf[256];
ec27ae18 128 bool show_title = false;
211ef127 129
c7e7b610 130 for (i = 0; i < ab->nr_events; i++) {
0c4a5bce
ML
131 if (bdl->samples[i].percent > percent_max)
132 percent_max = bdl->samples[i].percent;
c7e7b610
NK
133 }
134
ec27ae18
JY
135 if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) {
136 if (ab->have_cycles) {
137 if (dl->ipc == 0.0 && dl->cycles == 0)
138 show_title = true;
139 } else
140 show_title = true;
141 }
142
c7e7b610 143 if (dl->offset != -1 && percent_max != 0.0) {
c564f0db
JY
144 for (i = 0; i < ab->nr_events; i++) {
145 ui_browser__set_percent_color(browser,
146 bdl->samples[i].percent,
147 current_entry);
148 if (annotate_browser__opts.show_total_period) {
149 ui_browser__printf(browser, "%6" PRIu64 " ",
150 bdl->samples[i].nr);
151 } else {
152 ui_browser__printf(browser, "%6.2f ",
153 bdl->samples[i].percent);
f8f4aaea 154 }
c7e7b610 155 }
92221162 156 } else {
05e8b080 157 ui_browser__set_percent_color(browser, 0, current_entry);
ec27ae18
JY
158
159 if (!show_title)
160 ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
161 else
162 ui_browser__printf(browser, "%*s", 7, "Percent");
f8f4aaea
AK
163 }
164 if (ab->have_cycles) {
165 if (dl->ipc)
517dfdb3 166 ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
ec27ae18 167 else if (!show_title)
26270a00 168 ui_browser__write_nstring(browser, " ", IPC_WIDTH);
ec27ae18
JY
169 else
170 ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
171
f8f4aaea 172 if (dl->cycles)
517dfdb3
ACM
173 ui_browser__printf(browser, "%*" PRIu64 " ",
174 CYCLES_WIDTH - 1, dl->cycles);
ec27ae18 175 else if (!show_title)
26270a00 176 ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
ec27ae18
JY
177 else
178 ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
92221162
ACM
179 }
180
cf2dacc5 181 SLsmg_write_char(' ');
c172f742
ACM
182
183 /* The scroll bar isn't being used */
05e8b080 184 if (!browser->navkeypressed)
c172f742
ACM
185 width += 1;
186
29ed6e76 187 if (!*dl->line)
26270a00 188 ui_browser__write_nstring(browser, " ", width - pcnt_width);
83b1f2aa 189 else if (dl->offset == -1) {
e592488c
AK
190 if (dl->line_nr && annotate_browser__opts.show_linenr)
191 printed = scnprintf(bf, sizeof(bf), "%-*d ",
192 ab->addr_width + 1, dl->line_nr);
193 else
194 printed = scnprintf(bf, sizeof(bf), "%*s ",
83b1f2aa 195 ab->addr_width, " ");
26270a00
ACM
196 ui_browser__write_nstring(browser, bf, printed);
197 ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
83b1f2aa 198 } else {
29ed6e76 199 u64 addr = dl->offset;
83b1f2aa 200 int color = -1;
058b4cc9 201
e9823b21 202 if (!annotate_browser__opts.use_offset)
e235f3f3
ACM
203 addr += ab->start;
204
e9823b21 205 if (!annotate_browser__opts.use_offset) {
83b1f2aa 206 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
61e04b33 207 } else {
7d5b12f5 208 if (bdl->jump_sources) {
e9823b21 209 if (annotate_browser__opts.show_nr_jumps) {
2402e4a9
ACM
210 int prev;
211 printed = scnprintf(bf, sizeof(bf), "%*d ",
212 ab->jumps_width,
213 bdl->jump_sources);
214 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
215 current_entry);
26270a00 216 ui_browser__write_nstring(browser, bf, printed);
05e8b080 217 ui_browser__set_color(browser, prev);
2402e4a9
ACM
218 }
219
83b1f2aa 220 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2402e4a9 221 ab->target_width, addr);
61e04b33 222 } else {
83b1f2aa
ACM
223 printed = scnprintf(bf, sizeof(bf), "%*s ",
224 ab->addr_width, " ");
61e04b33
ACM
225 }
226 }
b793a401 227
058b4cc9 228 if (change_color)
05e8b080 229 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
26270a00 230 ui_browser__write_nstring(browser, bf, printed);
058b4cc9 231 if (change_color)
05e8b080 232 ui_browser__set_color(browser, color);
75b49202
ACM
233 if (dl->ins.ops && dl->ins.ops->scnprintf) {
234 if (ins__is_jump(&dl->ins)) {
e216874c 235 bool fwd = dl->ops.target.offset > dl->offset;
51a0d455 236
05e8b080 237 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
59d038d5 238 SLSMG_UARROW_CHAR);
51a0d455 239 SLsmg_write_char(' ');
75b49202 240 } else if (ins__is_call(&dl->ins)) {
05e8b080 241 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
88298f5a 242 SLsmg_write_char(' ');
75b49202 243 } else if (ins__is_ret(&dl->ins)) {
6ef94929
NR
244 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
245 SLsmg_write_char(' ');
51a0d455 246 } else {
26270a00 247 ui_browser__write_nstring(browser, " ", 2);
51a0d455 248 }
4ea08b52 249 } else {
6ef94929 250 ui_browser__write_nstring(browser, " ", 2);
4ea08b52 251 }
28548d78 252
e9823b21 253 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
26270a00 254 ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
058b4cc9 255 }
b99976e2 256
58e817d9 257 if (current_entry)
29ed6e76 258 ab->selection = dl;
92221162
ACM
259}
260
865c66c4
FD
261static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
262{
75b49202 263 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
865c66c4 264 || !disasm_line__has_offset(dl)
e216874c
RB
265 || dl->ops.target.offset < 0
266 || dl->ops.target.offset >= (s64)symbol__size(sym))
865c66c4
FD
267 return false;
268
269 return true;
270}
271
9d1ef56d 272static void annotate_browser__draw_current_jump(struct ui_browser *browser)
a3f895be
ACM
273{
274 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9d1ef56d
ACM
275 struct disasm_line *cursor = ab->selection, *target;
276 struct browser_disasm_line *btarget, *bcursor;
83b1f2aa 277 unsigned int from, to;
32ae1efd
NK
278 struct map_symbol *ms = ab->b.priv;
279 struct symbol *sym = ms->sym;
f8f4aaea 280 u8 pcnt_width = annotate_browser__pcnt_width(ab);
32ae1efd
NK
281
282 /* PLT symbols contain external offsets */
283 if (strstr(sym->name, "@plt"))
284 return;
a3f895be 285
865c66c4 286 if (!disasm_line__is_valid_jump(cursor, sym))
9d1ef56d 287 return;
a3f895be 288
9d1ef56d
ACM
289 target = ab->offsets[cursor->ops.target.offset];
290 if (!target)
291 return;
a3f895be 292
9d1ef56d
ACM
293 bcursor = disasm_line__browser(cursor);
294 btarget = disasm_line__browser(target);
a3f895be 295
e9823b21 296 if (annotate_browser__opts.hide_src_code) {
9d1ef56d 297 from = bcursor->idx_asm;
a3f895be
ACM
298 to = btarget->idx_asm;
299 } else {
9d1ef56d 300 from = (u64)bcursor->idx;
a3f895be
ACM
301 to = (u64)btarget->idx;
302 }
303
78ce08df 304 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
c7e7b610
NK
305 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
306 from, to);
a3f895be
ACM
307}
308
309static unsigned int annotate_browser__refresh(struct ui_browser *browser)
310{
c7e7b610 311 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
a3f895be 312 int ret = ui_browser__list_head_refresh(browser);
f8f4aaea 313 int pcnt_width = annotate_browser__pcnt_width(ab);
a3f895be 314
e9823b21 315 if (annotate_browser__opts.jump_arrows)
9d1ef56d 316 annotate_browser__draw_current_jump(browser);
a3f895be 317
83b1f2aa 318 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
c7e7b610 319 __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
a3f895be
ACM
320 return ret;
321}
322
c7e7b610
NK
323static int disasm__cmp(struct browser_disasm_line *a,
324 struct browser_disasm_line *b, int nr_pcnt)
325{
326 int i;
327
328 for (i = 0; i < nr_pcnt; i++) {
0c4a5bce 329 if (a->samples[i].percent == b->samples[i].percent)
c7e7b610 330 continue;
0c4a5bce 331 return a->samples[i].percent < b->samples[i].percent;
c7e7b610
NK
332 }
333 return 0;
334}
335
336static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
337 int nr_events)
92221162 338{
29ed6e76 339 struct rb_node **p = &root->rb_node;
92221162 340 struct rb_node *parent = NULL;
887c0066 341 struct browser_disasm_line *l;
92221162
ACM
342
343 while (*p != NULL) {
344 parent = *p;
887c0066 345 l = rb_entry(parent, struct browser_disasm_line, rb_node);
c7e7b610
NK
346
347 if (disasm__cmp(bdl, l, nr_events))
92221162
ACM
348 p = &(*p)->rb_left;
349 else
350 p = &(*p)->rb_right;
351 }
887c0066
ACM
352 rb_link_node(&bdl->rb_node, parent, p);
353 rb_insert_color(&bdl->rb_node, root);
211ef127
ACM
354}
355
05e8b080 356static void annotate_browser__set_top(struct annotate_browser *browser,
29ed6e76 357 struct disasm_line *pos, u32 idx)
f1e9214c 358{
f1e9214c
ACM
359 unsigned back;
360
05e8b080
ACM
361 ui_browser__refresh_dimensions(&browser->b);
362 back = browser->b.height / 2;
363 browser->b.top_idx = browser->b.index = idx;
f1e9214c 364
05e8b080 365 while (browser->b.top_idx != 0 && back != 0) {
29ed6e76 366 pos = list_entry(pos->node.prev, struct disasm_line, node);
f1e9214c 367
05e8b080 368 if (disasm_line__filter(&browser->b, &pos->node))
08be4eed
ACM
369 continue;
370
05e8b080 371 --browser->b.top_idx;
f1e9214c
ACM
372 --back;
373 }
374
05e8b080
ACM
375 browser->b.top = pos;
376 browser->b.navkeypressed = true;
b0ffb2c4
ACM
377}
378
379static void annotate_browser__set_rb_top(struct annotate_browser *browser,
380 struct rb_node *nd)
381{
887c0066 382 struct browser_disasm_line *bpos;
29ed6e76 383 struct disasm_line *pos;
a44b45f2 384 u32 idx;
b0ffb2c4 385
887c0066
ACM
386 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
387 pos = ((struct disasm_line *)bpos) - 1;
a44b45f2 388 idx = bpos->idx;
e9823b21 389 if (annotate_browser__opts.hide_src_code)
a44b45f2
ACM
390 idx = bpos->idx_asm;
391 annotate_browser__set_top(browser, pos, idx);
b0ffb2c4 392 browser->curr_hot = nd;
f1e9214c
ACM
393}
394
c97cf422 395static void annotate_browser__calc_percent(struct annotate_browser *browser,
db8fd07a 396 struct perf_evsel *evsel)
f1e9214c 397{
34958544
ACM
398 struct map_symbol *ms = browser->b.priv;
399 struct symbol *sym = ms->sym;
c97cf422 400 struct annotation *notes = symbol__annotation(sym);
e64aa75b
NK
401 struct disasm_line *pos, *next;
402 s64 len = symbol__size(sym);
c97cf422
ACM
403
404 browser->entries = RB_ROOT;
405
406 pthread_mutex_lock(&notes->lock);
407
408 list_for_each_entry(pos, &notes->src->source, node) {
887c0066 409 struct browser_disasm_line *bpos = disasm_line__browser(pos);
e64aa75b 410 const char *path = NULL;
c7e7b610
NK
411 double max_percent = 0.0;
412 int i;
e64aa75b
NK
413
414 if (pos->offset == -1) {
415 RB_CLEAR_NODE(&bpos->rb_node);
416 continue;
417 }
418
419 next = disasm__get_next_ip_line(&notes->src->source, pos);
e64aa75b 420
c7e7b610 421 for (i = 0; i < browser->nr_events; i++) {
0c4a5bce
ML
422 u64 nr_samples;
423
424 bpos->samples[i].percent = disasm__calc_percent(notes,
c7e7b610
NK
425 evsel->idx + i,
426 pos->offset,
427 next ? next->offset : len,
0c4a5bce
ML
428 &path, &nr_samples);
429 bpos->samples[i].nr = nr_samples;
c7e7b610 430
0c4a5bce
ML
431 if (max_percent < bpos->samples[i].percent)
432 max_percent = bpos->samples[i].percent;
c7e7b610
NK
433 }
434
30e863bb 435 if (max_percent < 0.01 && pos->ipc == 0) {
887c0066 436 RB_CLEAR_NODE(&bpos->rb_node);
c97cf422
ACM
437 continue;
438 }
c7e7b610
NK
439 disasm_rb_tree__insert(&browser->entries, bpos,
440 browser->nr_events);
c97cf422
ACM
441 }
442 pthread_mutex_unlock(&notes->lock);
443
444 browser->curr_hot = rb_last(&browser->entries);
445}
446
0361fc25
ACM
447static bool annotate_browser__toggle_source(struct annotate_browser *browser)
448{
29ed6e76 449 struct disasm_line *dl;
887c0066 450 struct browser_disasm_line *bdl;
0361fc25
ACM
451 off_t offset = browser->b.index - browser->b.top_idx;
452
453 browser->b.seek(&browser->b, offset, SEEK_CUR);
29ed6e76 454 dl = list_entry(browser->b.top, struct disasm_line, node);
887c0066 455 bdl = disasm_line__browser(dl);
0361fc25 456
e9823b21 457 if (annotate_browser__opts.hide_src_code) {
887c0066
ACM
458 if (bdl->idx_asm < offset)
459 offset = bdl->idx;
0361fc25
ACM
460
461 browser->b.nr_entries = browser->nr_entries;
e9823b21 462 annotate_browser__opts.hide_src_code = false;
0361fc25 463 browser->b.seek(&browser->b, -offset, SEEK_CUR);
887c0066
ACM
464 browser->b.top_idx = bdl->idx - offset;
465 browser->b.index = bdl->idx;
0361fc25 466 } else {
887c0066 467 if (bdl->idx_asm < 0) {
0361fc25
ACM
468 ui_helpline__puts("Only available for assembly lines.");
469 browser->b.seek(&browser->b, -offset, SEEK_CUR);
470 return false;
471 }
472
887c0066
ACM
473 if (bdl->idx_asm < offset)
474 offset = bdl->idx_asm;
0361fc25
ACM
475
476 browser->b.nr_entries = browser->nr_asm_entries;
e9823b21 477 annotate_browser__opts.hide_src_code = true;
0361fc25 478 browser->b.seek(&browser->b, -offset, SEEK_CUR);
887c0066
ACM
479 browser->b.top_idx = bdl->idx_asm - offset;
480 browser->b.index = bdl->idx_asm;
0361fc25
ACM
481 }
482
483 return true;
484}
485
e9823b21
ACM
486static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
487{
488 ui_browser__reset_index(&browser->b);
489 browser->b.nr_entries = browser->nr_asm_entries;
490}
491
34f77abc
AH
492#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
493
494static int sym_title(struct symbol *sym, struct map *map, char *title,
495 size_t sz)
496{
497 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
498}
499
db8fd07a
NK
500static bool annotate_browser__callq(struct annotate_browser *browser,
501 struct perf_evsel *evsel,
9783adf7 502 struct hist_browser_timer *hbt)
60521702
ACM
503{
504 struct map_symbol *ms = browser->b.priv;
657bcaf5 505 struct disasm_line *dl = browser->selection;
60521702 506 struct annotation *notes;
1179e11b
AH
507 struct addr_map_symbol target = {
508 .map = ms->map,
1d5077bd 509 .addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
1179e11b 510 };
34f77abc 511 char title[SYM_TITLE_MAX_SIZE];
60521702 512
75b49202 513 if (!ins__is_call(&dl->ins))
60521702
ACM
514 return false;
515
be39db9f 516 if (map_groups__find_ams(&target) ||
1d5077bd
AH
517 map__rip_2objdump(target.map, target.map->map_ip(target.map,
518 target.addr)) !=
519 dl->ops.target.addr) {
60521702
ACM
520 ui_helpline__puts("The called function was not found.");
521 return true;
522 }
523
1179e11b 524 notes = symbol__annotation(target.sym);
60521702
ACM
525 pthread_mutex_lock(&notes->lock);
526
1179e11b 527 if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
60521702
ACM
528 pthread_mutex_unlock(&notes->lock);
529 ui__warning("Not enough memory for annotating '%s' symbol!\n",
1179e11b 530 target.sym->name);
60521702
ACM
531 return true;
532 }
533
534 pthread_mutex_unlock(&notes->lock);
1179e11b
AH
535 symbol__tui_annotate(target.sym, target.map, evsel, hbt);
536 sym_title(ms->sym, ms->map, title, sizeof(title));
34f77abc 537 ui_browser__show_title(&browser->b, title);
60521702
ACM
538 return true;
539}
540
29ed6e76
ACM
541static
542struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
543 s64 offset, s64 *idx)
08be4eed
ACM
544{
545 struct map_symbol *ms = browser->b.priv;
546 struct symbol *sym = ms->sym;
547 struct annotation *notes = symbol__annotation(sym);
29ed6e76 548 struct disasm_line *pos;
08be4eed
ACM
549
550 *idx = 0;
551 list_for_each_entry(pos, &notes->src->source, node) {
552 if (pos->offset == offset)
553 return pos;
29ed6e76 554 if (!disasm_line__filter(&browser->b, &pos->node))
08be4eed
ACM
555 ++*idx;
556 }
557
558 return NULL;
559}
560
561static bool annotate_browser__jump(struct annotate_browser *browser)
562{
657bcaf5 563 struct disasm_line *dl = browser->selection;
5252b1ae 564 u64 offset;
4f9d0325 565 s64 idx;
08be4eed 566
75b49202 567 if (!ins__is_jump(&dl->ins))
08be4eed
ACM
568 return false;
569
5252b1ae
ACM
570 offset = dl->ops.target.offset;
571 dl = annotate_browser__find_offset(browser, offset, &idx);
29ed6e76 572 if (dl == NULL) {
5252b1ae 573 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
08be4eed
ACM
574 return true;
575 }
576
29ed6e76 577 annotate_browser__set_top(browser, dl, idx);
48000a1a 578
08be4eed
ACM
579 return true;
580}
581
29ed6e76
ACM
582static
583struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
584 char *s, s64 *idx)
d3d1f61a
ACM
585{
586 struct map_symbol *ms = browser->b.priv;
587 struct symbol *sym = ms->sym;
588 struct annotation *notes = symbol__annotation(sym);
29ed6e76 589 struct disasm_line *pos = browser->selection;
d3d1f61a
ACM
590
591 *idx = browser->b.index;
592 list_for_each_entry_continue(pos, &notes->src->source, node) {
29ed6e76 593 if (disasm_line__filter(&browser->b, &pos->node))
d3d1f61a
ACM
594 continue;
595
596 ++*idx;
597
598 if (pos->line && strstr(pos->line, s) != NULL)
599 return pos;
600 }
601
602 return NULL;
603}
604
605static bool __annotate_browser__search(struct annotate_browser *browser)
606{
29ed6e76 607 struct disasm_line *dl;
d3d1f61a
ACM
608 s64 idx;
609
29ed6e76
ACM
610 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
611 if (dl == NULL) {
d3d1f61a
ACM
612 ui_helpline__puts("String not found!");
613 return false;
614 }
615
29ed6e76 616 annotate_browser__set_top(browser, dl, idx);
d3d1f61a
ACM
617 browser->searching_backwards = false;
618 return true;
619}
620
29ed6e76
ACM
621static
622struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
623 char *s, s64 *idx)
d3d1f61a
ACM
624{
625 struct map_symbol *ms = browser->b.priv;
626 struct symbol *sym = ms->sym;
627 struct annotation *notes = symbol__annotation(sym);
29ed6e76 628 struct disasm_line *pos = browser->selection;
d3d1f61a
ACM
629
630 *idx = browser->b.index;
631 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
29ed6e76 632 if (disasm_line__filter(&browser->b, &pos->node))
d3d1f61a
ACM
633 continue;
634
635 --*idx;
636
637 if (pos->line && strstr(pos->line, s) != NULL)
638 return pos;
639 }
640
641 return NULL;
642}
643
644static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
645{
29ed6e76 646 struct disasm_line *dl;
d3d1f61a
ACM
647 s64 idx;
648
29ed6e76
ACM
649 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
650 if (dl == NULL) {
d3d1f61a
ACM
651 ui_helpline__puts("String not found!");
652 return false;
653 }
654
29ed6e76 655 annotate_browser__set_top(browser, dl, idx);
d3d1f61a
ACM
656 browser->searching_backwards = true;
657 return true;
658}
659
660static bool annotate_browser__search_window(struct annotate_browser *browser,
661 int delay_secs)
662{
663 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
664 "ENTER: OK, ESC: Cancel",
665 delay_secs * 2) != K_ENTER ||
666 !*browser->search_bf)
667 return false;
668
669 return true;
670}
671
672static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
673{
674 if (annotate_browser__search_window(browser, delay_secs))
675 return __annotate_browser__search(browser);
676
677 return false;
678}
679
680static bool annotate_browser__continue_search(struct annotate_browser *browser,
681 int delay_secs)
682{
683 if (!*browser->search_bf)
684 return annotate_browser__search(browser, delay_secs);
685
686 return __annotate_browser__search(browser);
687}
688
689static bool annotate_browser__search_reverse(struct annotate_browser *browser,
690 int delay_secs)
691{
692 if (annotate_browser__search_window(browser, delay_secs))
693 return __annotate_browser__search_reverse(browser);
694
695 return false;
696}
697
698static
699bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
700 int delay_secs)
701{
702 if (!*browser->search_bf)
703 return annotate_browser__search_reverse(browser, delay_secs);
704
705 return __annotate_browser__search_reverse(browser);
706}
707
e9823b21
ACM
708static void annotate_browser__update_addr_width(struct annotate_browser *browser)
709{
710 if (annotate_browser__opts.use_offset)
711 browser->target_width = browser->min_addr_width;
712 else
713 browser->target_width = browser->max_addr_width;
714
715 browser->addr_width = browser->target_width;
716
717 if (annotate_browser__opts.show_nr_jumps)
718 browser->addr_width += browser->jumps_width + 1;
719}
720
db8fd07a
NK
721static int annotate_browser__run(struct annotate_browser *browser,
722 struct perf_evsel *evsel,
9783adf7 723 struct hist_browser_timer *hbt)
c97cf422
ACM
724{
725 struct rb_node *nd = NULL;
05e8b080 726 struct map_symbol *ms = browser->b.priv;
34958544 727 struct symbol *sym = ms->sym;
54e7a4e8 728 const char *help = "Press 'h' for help on key bindings";
9783adf7 729 int delay_secs = hbt ? hbt->refresh : 0;
b50e003d 730 int key;
34f77abc 731 char title[SYM_TITLE_MAX_SIZE];
f1e9214c 732
34f77abc
AH
733 sym_title(sym, ms->map, title, sizeof(title));
734 if (ui_browser__show(&browser->b, title, help) < 0)
f1e9214c 735 return -1;
c97cf422 736
db8fd07a 737 annotate_browser__calc_percent(browser, evsel);
c97cf422 738
05e8b080
ACM
739 if (browser->curr_hot) {
740 annotate_browser__set_rb_top(browser, browser->curr_hot);
741 browser->b.navkeypressed = false;
d3d1f61a 742 }
f1e9214c 743
05e8b080 744 nd = browser->curr_hot;
c97cf422 745
f1e9214c 746 while (1) {
05e8b080 747 key = ui_browser__run(&browser->b, delay_secs);
f1e9214c 748
81cce8de 749 if (delay_secs != 0) {
db8fd07a 750 annotate_browser__calc_percent(browser, evsel);
c97cf422
ACM
751 /*
752 * Current line focus got out of the list of most active
753 * lines, NULL it so that if TAB|UNTAB is pressed, we
754 * move to curr_hot (current hottest line).
755 */
756 if (nd != NULL && RB_EMPTY_NODE(nd))
757 nd = NULL;
758 }
759
b50e003d 760 switch (key) {
cf958003 761 case K_TIMER:
9783adf7
NK
762 if (hbt)
763 hbt->timer(hbt->arg);
81cce8de
ACM
764
765 if (delay_secs != 0)
db8fd07a 766 symbol__annotate_decay_histogram(sym, evsel->idx);
c97cf422 767 continue;
cf958003 768 case K_TAB:
c97cf422
ACM
769 if (nd != NULL) {
770 nd = rb_prev(nd);
771 if (nd == NULL)
05e8b080 772 nd = rb_last(&browser->entries);
c97cf422 773 } else
05e8b080 774 nd = browser->curr_hot;
f1e9214c 775 break;
cf958003 776 case K_UNTAB:
d4913cbd 777 if (nd != NULL) {
c97cf422
ACM
778 nd = rb_next(nd);
779 if (nd == NULL)
05e8b080 780 nd = rb_first(&browser->entries);
d4913cbd 781 } else
05e8b080 782 nd = browser->curr_hot;
c97cf422 783 break;
54e7a4e8 784 case K_F1:
ef7c5372 785 case 'h':
05e8b080 786 ui_browser__help_window(&browser->b,
54e7a4e8
ACM
787 "UP/DOWN/PGUP\n"
788 "PGDN/SPACE Navigate\n"
789 "q/ESC/CTRL+C Exit\n\n"
7727a925
ACM
790 "ENTER Go to target\n"
791 "ESC Exit\n"
107baeca 792 "H Cycle thru hottest instructions\n"
54e7a4e8
ACM
793 "j Toggle showing jump to target arrows\n"
794 "J Toggle showing number of jump sources on targets\n"
795 "n Search next string\n"
796 "o Toggle disassembler output/simplified view\n"
797 "s Toggle source code view\n"
0c4a5bce 798 "t Toggle total period view\n"
54e7a4e8 799 "/ Search string\n"
e592488c 800 "k Toggle line numbers\n"
79ee47fa 801 "r Run available scripts\n"
fcd9fef9 802 "? Search string backwards\n");
54e7a4e8 803 continue;
79ee47fa
FT
804 case 'r':
805 {
806 script_browse(NULL);
807 continue;
808 }
e592488c
AK
809 case 'k':
810 annotate_browser__opts.show_linenr =
811 !annotate_browser__opts.show_linenr;
812 break;
54e7a4e8 813 case 'H':
05e8b080 814 nd = browser->curr_hot;
f1e9214c 815 break;
ef7c5372 816 case 's':
05e8b080 817 if (annotate_browser__toggle_source(browser))
0361fc25
ACM
818 ui_helpline__puts(help);
819 continue;
e235f3f3 820 case 'o':
e9823b21 821 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
05e8b080 822 annotate_browser__update_addr_width(browser);
e235f3f3 823 continue;
9d1ef56d 824 case 'j':
e9823b21 825 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
9d1ef56d 826 continue;
2402e4a9 827 case 'J':
e9823b21 828 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
05e8b080 829 annotate_browser__update_addr_width(browser);
e9823b21 830 continue;
d3d1f61a 831 case '/':
05e8b080 832 if (annotate_browser__search(browser, delay_secs)) {
d3d1f61a
ACM
833show_help:
834 ui_helpline__puts(help);
835 }
836 continue;
837 case 'n':
05e8b080
ACM
838 if (browser->searching_backwards ?
839 annotate_browser__continue_search_reverse(browser, delay_secs) :
840 annotate_browser__continue_search(browser, delay_secs))
d3d1f61a
ACM
841 goto show_help;
842 continue;
843 case '?':
05e8b080 844 if (annotate_browser__search_reverse(browser, delay_secs))
d3d1f61a
ACM
845 goto show_help;
846 continue;
e9823b21
ACM
847 case 'D': {
848 static int seq;
849 ui_helpline__pop();
850 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
05e8b080
ACM
851 seq++, browser->b.nr_entries,
852 browser->b.height,
853 browser->b.index,
854 browser->b.top_idx,
855 browser->nr_asm_entries);
e9823b21
ACM
856 }
857 continue;
cf958003
ACM
858 case K_ENTER:
859 case K_RIGHT:
05e8b080 860 if (browser->selection == NULL)
234a5375 861 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
05e8b080 862 else if (browser->selection->offset == -1)
234a5375 863 ui_helpline__puts("Actions are only available for assembly lines.");
75b49202 864 else if (!browser->selection->ins.ops)
6ef94929 865 goto show_sup_ins;
75b49202 866 else if (ins__is_ret(&browser->selection->ins))
c4cceae3 867 goto out;
6ef94929 868 else if (!(annotate_browser__jump(browser) ||
db8fd07a 869 annotate_browser__callq(browser, evsel, hbt))) {
c4cceae3 870show_sup_ins:
6ef94929 871 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
c4cceae3 872 }
fe46e64c 873 continue;
0c4a5bce
ML
874 case 't':
875 annotate_browser__opts.show_total_period =
876 !annotate_browser__opts.show_total_period;
877 annotate_browser__update_addr_width(browser);
878 continue;
cf958003
ACM
879 case K_LEFT:
880 case K_ESC:
ed7e5662
ACM
881 case 'q':
882 case CTRL('c'):
f1e9214c 883 goto out;
ed7e5662
ACM
884 default:
885 continue;
f1e9214c 886 }
c97cf422
ACM
887
888 if (nd != NULL)
05e8b080 889 annotate_browser__set_rb_top(browser, nd);
f1e9214c
ACM
890 }
891out:
05e8b080 892 ui_browser__hide(&browser->b);
b50e003d 893 return key;
f1e9214c
ACM
894}
895
d5dbc518
ACM
896int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
897 struct hist_browser_timer *hbt)
898{
0c4a5bce
ML
899 /* Set default value for show_total_period. */
900 annotate_browser__opts.show_total_period =
901 symbol_conf.show_total_period;
902
d5dbc518
ACM
903 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
904}
905
db8fd07a 906int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9783adf7 907 struct hist_browser_timer *hbt)
78f7defe 908{
ed426915
NK
909 /* reset abort key so that it can get Ctrl-C as a key */
910 SLang_reset_tty();
911 SLang_init_tty(0, 0, 0);
912
d5dbc518 913 return map_symbol__tui_annotate(&he->ms, evsel, hbt);
78f7defe
ACM
914}
915
30e863bb
AK
916
917static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
918{
919 unsigned n_insn = 0;
920 u64 offset;
921
922 for (offset = start; offset <= end; offset++) {
923 if (browser->offsets[offset])
924 n_insn++;
925 }
926 return n_insn;
927}
928
929static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
930 struct cyc_hist *ch)
931{
932 unsigned n_insn;
933 u64 offset;
934
935 n_insn = count_insn(browser, start, end);
936 if (n_insn && ch->num && ch->cycles) {
937 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
938
939 /* Hide data when there are too many overlaps. */
940 if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
941 return;
942
943 for (offset = start; offset <= end; offset++) {
944 struct disasm_line *dl = browser->offsets[offset];
945
946 if (dl)
947 dl->ipc = ipc;
948 }
949 }
950}
951
952/*
953 * This should probably be in util/annotate.c to share with the tty
954 * annotate, but right now we need the per byte offsets arrays,
955 * which are only here.
956 */
957static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
958 struct symbol *sym)
959{
960 u64 offset;
961 struct annotation *notes = symbol__annotation(sym);
962
963 if (!notes->src || !notes->src->cycles_hist)
964 return;
965
966 pthread_mutex_lock(&notes->lock);
967 for (offset = 0; offset < size; ++offset) {
968 struct cyc_hist *ch;
969
970 ch = &notes->src->cycles_hist[offset];
971 if (ch && ch->cycles) {
972 struct disasm_line *dl;
973
974 if (ch->have_start)
975 count_and_fill(browser, ch->start, offset, ch);
976 dl = browser->offsets[offset];
977 if (dl && ch->num_aggr)
978 dl->cycles = ch->cycles_aggr / ch->num_aggr;
979 browser->have_cycles = true;
980 }
981 }
982 pthread_mutex_unlock(&notes->lock);
983}
984
b793a401
ACM
985static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
986 size_t size)
987{
988 u64 offset;
32ae1efd
NK
989 struct map_symbol *ms = browser->b.priv;
990 struct symbol *sym = ms->sym;
991
992 /* PLT symbols contain external offsets */
993 if (strstr(sym->name, "@plt"))
994 return;
b793a401
ACM
995
996 for (offset = 0; offset < size; ++offset) {
997 struct disasm_line *dl = browser->offsets[offset], *dlt;
998 struct browser_disasm_line *bdlt;
999
865c66c4 1000 if (!disasm_line__is_valid_jump(dl, sym))
b793a401
ACM
1001 continue;
1002
44d1a3ed 1003 dlt = browser->offsets[dl->ops.target.offset];
9481ede9
ACM
1004 /*
1005 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
1006 * have to adjust to the previous offset?
1007 */
1008 if (dlt == NULL)
1009 continue;
1010
b793a401 1011 bdlt = disasm_line__browser(dlt);
2402e4a9
ACM
1012 if (++bdlt->jump_sources > browser->max_jump_sources)
1013 browser->max_jump_sources = bdlt->jump_sources;
1014
1015 ++browser->nr_jumps;
b793a401 1016 }
b793a401
ACM
1017}
1018
2402e4a9
ACM
1019static inline int width_jumps(int n)
1020{
1021 if (n >= 100)
1022 return 5;
1023 if (n / 10)
1024 return 2;
1025 return 1;
1026}
1027
db8fd07a
NK
1028int symbol__tui_annotate(struct symbol *sym, struct map *map,
1029 struct perf_evsel *evsel,
9783adf7 1030 struct hist_browser_timer *hbt)
211ef127 1031{
29ed6e76 1032 struct disasm_line *pos, *n;
db9a9cbc 1033 struct annotation *notes;
c0a58fb2 1034 size_t size;
34958544
ACM
1035 struct map_symbol ms = {
1036 .map = map,
1037 .sym = sym,
1038 };
92221162
ACM
1039 struct annotate_browser browser = {
1040 .b = {
a3f895be 1041 .refresh = annotate_browser__refresh,
92221162
ACM
1042 .seek = ui_browser__list_head_seek,
1043 .write = annotate_browser__write,
29ed6e76 1044 .filter = disasm_line__filter,
34958544 1045 .priv = &ms,
c172f742 1046 .use_navkeypressed = true,
92221162 1047 },
211ef127 1048 };
ee51d851 1049 int ret = -1, err;
c7e7b610
NK
1050 int nr_pcnt = 1;
1051 size_t sizeof_bdl = sizeof(struct browser_disasm_line);
211ef127 1052
78f7defe 1053 if (sym == NULL)
211ef127
ACM
1054 return -1;
1055
c0a58fb2
SL
1056 size = symbol__size(sym);
1057
78f7defe 1058 if (map->dso->annotate_warned)
211ef127
ACM
1059 return -1;
1060
b793a401
ACM
1061 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1062 if (browser.offsets == NULL) {
1063 ui__error("Not enough memory!");
1064 return -1;
1065 }
1066
c7e7b610
NK
1067 if (perf_evsel__is_group_event(evsel)) {
1068 nr_pcnt = evsel->nr_members;
0c4a5bce
ML
1069 sizeof_bdl += sizeof(struct disasm_line_samples) *
1070 (nr_pcnt - 1);
c7e7b610
NK
1071 }
1072
786c1b51 1073 err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl);
ee51d851
ACM
1074 if (err) {
1075 char msg[BUFSIZ];
1076 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1077 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
b793a401 1078 goto out_free_offsets;
211ef127
ACM
1079 }
1080
7727a925 1081 ui_helpline__push("Press ESC to exit");
211ef127 1082
db9a9cbc 1083 notes = symbol__annotation(sym);
058b4cc9 1084 browser.start = map__rip_2objdump(map, sym->start);
db9a9cbc 1085
ce6f4fab 1086 list_for_each_entry(pos, &notes->src->source, node) {
887c0066 1087 struct browser_disasm_line *bpos;
211ef127 1088 size_t line_len = strlen(pos->line);
c97cf422 1089
92221162
ACM
1090 if (browser.b.width < line_len)
1091 browser.b.width = line_len;
887c0066
ACM
1092 bpos = disasm_line__browser(pos);
1093 bpos->idx = browser.nr_entries++;
b793a401 1094 if (pos->offset != -1) {
887c0066 1095 bpos->idx_asm = browser.nr_asm_entries++;
97148a97
ACM
1096 /*
1097 * FIXME: short term bandaid to cope with assembly
1098 * routines that comes with labels in the same column
1099 * as the address in objdump, sigh.
1100 *
1101 * E.g. copy_user_generic_unrolled
1102 */
1103 if (pos->offset < (s64)size)
1104 browser.offsets[pos->offset] = pos;
b793a401 1105 } else
887c0066 1106 bpos->idx_asm = -1;
92221162
ACM
1107 }
1108
b793a401 1109 annotate_browser__mark_jump_targets(&browser, size);
30e863bb 1110 annotate__compute_ipc(&browser, size, sym);
b793a401 1111
2402e4a9 1112 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
83b1f2aa 1113 browser.max_addr_width = hex_width(sym->end);
2402e4a9 1114 browser.jumps_width = width_jumps(browser.max_jump_sources);
c7e7b610 1115 browser.nr_events = nr_pcnt;
0361fc25 1116 browser.b.nr_entries = browser.nr_entries;
db9a9cbc 1117 browser.b.entries = &notes->src->source,
92221162 1118 browser.b.width += 18; /* Percentage */
e9823b21
ACM
1119
1120 if (annotate_browser__opts.hide_src_code)
1121 annotate_browser__init_asm_mode(&browser);
1122
1123 annotate_browser__update_addr_width(&browser);
1124
db8fd07a 1125 ret = annotate_browser__run(&browser, evsel, hbt);
ce6f4fab 1126 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
211ef127 1127 list_del(&pos->node);
29ed6e76 1128 disasm_line__free(pos);
211ef127 1129 }
b793a401
ACM
1130
1131out_free_offsets:
1132 free(browser.offsets);
211ef127
ACM
1133 return ret;
1134}
c323cf04
ACM
1135
1136#define ANNOTATE_CFG(n) \
1137 { .name = #n, .value = &annotate_browser__opts.n, }
865c66c4 1138
c323cf04
ACM
1139/*
1140 * Keep the entries sorted, they are bsearch'ed
1141 */
7c3102b8 1142static struct annotate_config {
c323cf04
ACM
1143 const char *name;
1144 bool *value;
1145} annotate__configs[] = {
1146 ANNOTATE_CFG(hide_src_code),
1147 ANNOTATE_CFG(jump_arrows),
e592488c 1148 ANNOTATE_CFG(show_linenr),
c323cf04 1149 ANNOTATE_CFG(show_nr_jumps),
0c4a5bce 1150 ANNOTATE_CFG(show_total_period),
39ff7cdb 1151 ANNOTATE_CFG(use_offset),
c323cf04
ACM
1152};
1153
1154#undef ANNOTATE_CFG
1155
1156static int annotate_config__cmp(const void *name, const void *cfgp)
1157{
7c3102b8 1158 const struct annotate_config *cfg = cfgp;
c323cf04
ACM
1159
1160 return strcmp(name, cfg->name);
1161}
1162
1d037ca1
IT
1163static int annotate__config(const char *var, const char *value,
1164 void *data __maybe_unused)
c323cf04 1165{
7c3102b8 1166 struct annotate_config *cfg;
c323cf04
ACM
1167 const char *name;
1168
1169 if (prefixcmp(var, "annotate.") != 0)
1170 return 0;
1171
1172 name = var + 9;
1173 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
7c3102b8 1174 sizeof(struct annotate_config), annotate_config__cmp);
c323cf04
ACM
1175
1176 if (cfg == NULL)
f06cff7c
ACM
1177 ui__warning("%s variable unknown, ignoring...", var);
1178 else
1179 *cfg->value = perf_config_bool(name, value);
c323cf04
ACM
1180 return 0;
1181}
1182
1183void annotate_browser__init(void)
1184{
1185 perf_config(annotate__config, NULL);
1186}