aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/ui/browsers/annotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/ui/browsers/annotate.c')
-rw-r--r--tools/perf/ui/browsers/annotate.c702
1 files changed, 148 insertions, 554 deletions
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index fbf927cf775d..c02fb437ac8e 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -9,7 +9,6 @@
9#include "../../util/sort.h" 9#include "../../util/sort.h"
10#include "../../util/symbol.h" 10#include "../../util/symbol.h"
11#include "../../util/evsel.h" 11#include "../../util/evsel.h"
12#include "../../util/config.h"
13#include "../../util/evlist.h" 12#include "../../util/evlist.h"
14#include <inttypes.h> 13#include <inttypes.h>
15#include <pthread.h> 14#include <pthread.h>
@@ -22,28 +21,6 @@ struct disasm_line_samples {
22 struct sym_hist_entry he; 21 struct sym_hist_entry he;
23}; 22};
24 23
25#define IPC_WIDTH 6
26#define CYCLES_WIDTH 6
27
28struct browser_line {
29 u32 idx;
30 int idx_asm;
31 int jump_sources;
32};
33
34static struct annotate_browser_opt {
35 bool hide_src_code,
36 use_offset,
37 jump_arrows,
38 show_linenr,
39 show_nr_jumps,
40 show_nr_samples,
41 show_total_period;
42} annotate_browser__opts = {
43 .use_offset = true,
44 .jump_arrows = true,
45};
46
47struct arch; 24struct arch;
48 25
49struct annotate_browser { 26struct annotate_browser {
@@ -51,245 +28,98 @@ struct annotate_browser {
51 struct rb_root entries; 28 struct rb_root entries;
52 struct rb_node *curr_hot; 29 struct rb_node *curr_hot;
53 struct annotation_line *selection; 30 struct annotation_line *selection;
54 struct annotation_line **offsets;
55 struct arch *arch; 31 struct arch *arch;
56 int nr_events;
57 u64 start;
58 int nr_asm_entries;
59 int nr_entries;
60 int max_jump_sources;
61 int nr_jumps;
62 bool searching_backwards; 32 bool searching_backwards;
63 bool have_cycles;
64 u8 addr_width;
65 u8 jumps_width;
66 u8 target_width;
67 u8 min_addr_width;
68 u8 max_addr_width;
69 char search_bf[128]; 33 char search_bf[128];
70}; 34};
71 35
72static inline struct browser_line *browser_line(struct annotation_line *al) 36static inline struct annotation *browser__annotation(struct ui_browser *browser)
73{ 37{
74 void *ptr = al; 38 struct map_symbol *ms = browser->priv;
75 39 return symbol__annotation(ms->sym);
76 ptr = container_of(al, struct disasm_line, al);
77 return ptr - sizeof(struct browser_line);
78} 40}
79 41
80static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, 42static bool disasm_line__filter(struct ui_browser *browser, void *entry)
81 void *entry)
82{ 43{
83 if (annotate_browser__opts.hide_src_code) { 44 struct annotation *notes = browser__annotation(browser);
84 struct annotation_line *al = list_entry(entry, struct annotation_line, node); 45 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
85 46 return annotation_line__filter(al, notes);
86 return al->offset == -1;
87 }
88
89 return false;
90} 47}
91 48
92static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, 49static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
93 int nr, bool current)
94{ 50{
95 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) 51 struct annotation *notes = browser__annotation(browser);
52
53 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
96 return HE_COLORSET_SELECTED; 54 return HE_COLORSET_SELECTED;
97 if (nr == browser->max_jump_sources) 55 if (nr == notes->max_jump_sources)
98 return HE_COLORSET_TOP; 56 return HE_COLORSET_TOP;
99 if (nr > 1) 57 if (nr > 1)
100 return HE_COLORSET_MEDIUM; 58 return HE_COLORSET_MEDIUM;
101 return HE_COLORSET_NORMAL; 59 return HE_COLORSET_NORMAL;
102} 60}
103 61
104static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, 62static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
105 int nr, bool current)
106{ 63{
107 int color = annotate_browser__jumps_percent_color(browser, nr, current); 64 int color = ui_browser__jumps_percent_color(browser, nr, current);
108 return ui_browser__set_color(&browser->b, color); 65 return ui_browser__set_color(browser, color);
109} 66}
110 67
111static int annotate_browser__pcnt_width(struct annotate_browser *ab) 68static int annotate_browser__set_color(void *browser, int color)
112{ 69{
113 return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events; 70 return ui_browser__set_color(browser, color);
114} 71}
115 72
116static int annotate_browser__cycles_width(struct annotate_browser *ab) 73static void annotate_browser__write_graph(void *browser, int graph)
117{ 74{
118 return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0; 75 ui_browser__write_graph(browser, graph);
119} 76}
120 77
121static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, 78static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
122 char *bf, size_t size)
123{ 79{
124 if (dl->ins.ops && dl->ins.ops->scnprintf) { 80 ui_browser__set_percent_color(browser, percent, current);
125 if (ins__is_jump(&dl->ins)) { 81}
126 bool fwd = dl->ops.target.offset > dl->al.offset;
127
128 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
129 SLSMG_UARROW_CHAR);
130 SLsmg_write_char(' ');
131 } else if (ins__is_call(&dl->ins)) {
132 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
133 SLsmg_write_char(' ');
134 } else if (ins__is_ret(&dl->ins)) {
135 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
136 SLsmg_write_char(' ');
137 } else {
138 ui_browser__write_nstring(browser, " ", 2);
139 }
140 } else {
141 ui_browser__write_nstring(browser, " ", 2);
142 }
143 82
144 disasm_line__scnprintf(dl, bf, size, !annotate_browser__opts.use_offset); 83static void annotate_browser__printf(void *browser, const char *fmt, ...)
84{
85 va_list args;
86
87 va_start(args, fmt);
88 ui_browser__vprintf(browser, fmt, args);
89 va_end(args);
145} 90}
146 91
147static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) 92static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
148{ 93{
149 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 94 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
95 struct annotation *notes = browser__annotation(browser);
150 struct annotation_line *al = list_entry(entry, struct annotation_line, node); 96 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
151 struct browser_line *bl = browser_line(al); 97 struct annotation_write_ops ops = {
152 bool current_entry = ui_browser__is_current_entry(browser, row); 98 .first_line = row == 0,
153 bool change_color = (!annotate_browser__opts.hide_src_code && 99 .current_entry = ui_browser__is_current_entry(browser, row),
154 (!current_entry || (browser->use_navkeypressed && 100 .change_color = (!notes->options->hide_src_code &&
155 !browser->navkeypressed))); 101 (!ops.current_entry ||
156 int width = browser->width, printed; 102 (browser->use_navkeypressed &&
157 int i, pcnt_width = annotate_browser__pcnt_width(ab), 103 !browser->navkeypressed))),
158 cycles_width = annotate_browser__cycles_width(ab); 104 .width = browser->width,
159 double percent_max = 0.0; 105 .obj = browser,
160 char bf[256]; 106 .set_color = annotate_browser__set_color,
161 bool show_title = false; 107 .set_percent_color = annotate_browser__set_percent_color,
162 108 .set_jumps_percent_color = ui_browser__set_jumps_percent_color,
163 for (i = 0; i < ab->nr_events; i++) { 109 .printf = annotate_browser__printf,
164 if (al->samples[i].percent > percent_max) 110 .write_graph = annotate_browser__write_graph,
165 percent_max = al->samples[i].percent; 111 };
166 }
167
168 if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) {
169 if (ab->have_cycles) {
170 if (al->ipc == 0.0 && al->cycles == 0)
171 show_title = true;
172 } else
173 show_title = true;
174 }
175
176 if (al->offset != -1 && percent_max != 0.0) {
177 for (i = 0; i < ab->nr_events; i++) {
178 ui_browser__set_percent_color(browser,
179 al->samples[i].percent,
180 current_entry);
181 if (annotate_browser__opts.show_total_period) {
182 ui_browser__printf(browser, "%11" PRIu64 " ",
183 al->samples[i].he.period);
184 } else if (annotate_browser__opts.show_nr_samples) {
185 ui_browser__printf(browser, "%6" PRIu64 " ",
186 al->samples[i].he.nr_samples);
187 } else {
188 ui_browser__printf(browser, "%6.2f ",
189 al->samples[i].percent);
190 }
191 }
192 } else {
193 ui_browser__set_percent_color(browser, 0, current_entry);
194
195 if (!show_title)
196 ui_browser__write_nstring(browser, " ", pcnt_width);
197 else {
198 ui_browser__printf(browser, "%*s", pcnt_width,
199 annotate_browser__opts.show_total_period ? "Period" :
200 annotate_browser__opts.show_nr_samples ? "Samples" : "Percent");
201 }
202 }
203 if (ab->have_cycles) {
204 if (al->ipc)
205 ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, al->ipc);
206 else if (!show_title)
207 ui_browser__write_nstring(browser, " ", IPC_WIDTH);
208 else
209 ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
210
211 if (al->cycles)
212 ui_browser__printf(browser, "%*" PRIu64 " ",
213 CYCLES_WIDTH - 1, al->cycles);
214 else if (!show_title)
215 ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
216 else
217 ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
218 }
219
220 SLsmg_write_char(' ');
221 112
222 /* The scroll bar isn't being used */ 113 /* The scroll bar isn't being used */
223 if (!browser->navkeypressed) 114 if (!browser->navkeypressed)
224 width += 1; 115 ops.width += 1;
225
226 if (!*al->line)
227 ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
228 else if (al->offset == -1) {
229 if (al->line_nr && annotate_browser__opts.show_linenr)
230 printed = scnprintf(bf, sizeof(bf), "%-*d ",
231 ab->addr_width + 1, al->line_nr);
232 else
233 printed = scnprintf(bf, sizeof(bf), "%*s ",
234 ab->addr_width, " ");
235 ui_browser__write_nstring(browser, bf, printed);
236 ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1);
237 } else {
238 u64 addr = al->offset;
239 int color = -1;
240
241 if (!annotate_browser__opts.use_offset)
242 addr += ab->start;
243
244 if (!annotate_browser__opts.use_offset) {
245 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
246 } else {
247 if (bl->jump_sources) {
248 if (annotate_browser__opts.show_nr_jumps) {
249 int prev;
250 printed = scnprintf(bf, sizeof(bf), "%*d ",
251 ab->jumps_width,
252 bl->jump_sources);
253 prev = annotate_browser__set_jumps_percent_color(ab, bl->jump_sources,
254 current_entry);
255 ui_browser__write_nstring(browser, bf, printed);
256 ui_browser__set_color(browser, prev);
257 }
258
259 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
260 ab->target_width, addr);
261 } else {
262 printed = scnprintf(bf, sizeof(bf), "%*s ",
263 ab->addr_width, " ");
264 }
265 }
266
267 if (change_color)
268 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
269 ui_browser__write_nstring(browser, bf, printed);
270 if (change_color)
271 ui_browser__set_color(browser, color);
272 116
273 disasm_line__write(disasm_line(al), browser, bf, sizeof(bf)); 117 annotation_line__write(al, notes, &ops);
274 118
275 ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed); 119 if (ops.current_entry)
276 }
277
278 if (current_entry)
279 ab->selection = al; 120 ab->selection = al;
280} 121}
281 122
282static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
283{
284 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
285 || !disasm_line__has_offset(dl)
286 || dl->ops.target.offset < 0
287 || dl->ops.target.offset >= (s64)symbol__size(sym))
288 return false;
289
290 return true;
291}
292
293static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor) 123static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
294{ 124{
295 struct disasm_line *pos = list_prev_entry(cursor, al.node); 125 struct disasm_line *pos = list_prev_entry(cursor, al.node);
@@ -314,17 +144,18 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
314 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 144 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
315 struct disasm_line *cursor = disasm_line(ab->selection); 145 struct disasm_line *cursor = disasm_line(ab->selection);
316 struct annotation_line *target; 146 struct annotation_line *target;
317 struct browser_line *btarget, *bcursor;
318 unsigned int from, to; 147 unsigned int from, to;
319 struct map_symbol *ms = ab->b.priv; 148 struct map_symbol *ms = ab->b.priv;
320 struct symbol *sym = ms->sym; 149 struct symbol *sym = ms->sym;
321 u8 pcnt_width = annotate_browser__pcnt_width(ab); 150 struct annotation *notes = symbol__annotation(sym);
151 u8 pcnt_width = annotation__pcnt_width(notes);
152 int width;
322 153
323 /* PLT symbols contain external offsets */ 154 /* PLT symbols contain external offsets */
324 if (strstr(sym->name, "@plt")) 155 if (strstr(sym->name, "@plt"))
325 return; 156 return;
326 157
327 if (!disasm_line__is_valid_jump(cursor, sym)) 158 if (!disasm_line__is_valid_local_jump(cursor, sym))
328 return; 159 return;
329 160
330 /* 161 /*
@@ -347,31 +178,31 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
347 * name right after the '<' token and probably treating this like a 178 * name right after the '<' token and probably treating this like a
348 * 'call' instruction. 179 * 'call' instruction.
349 */ 180 */
350 target = ab->offsets[cursor->ops.target.offset]; 181 target = notes->offsets[cursor->ops.target.offset];
351 if (target == NULL) { 182 if (target == NULL) {
352 ui_helpline__printf("WARN: jump target inconsistency, press 'o', ab->offsets[%#x] = NULL\n", 183 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
353 cursor->ops.target.offset); 184 cursor->ops.target.offset);
354 return; 185 return;
355 } 186 }
356 187
357 bcursor = browser_line(&cursor->al); 188 if (notes->options->hide_src_code) {
358 btarget = browser_line(target); 189 from = cursor->al.idx_asm;
359 190 to = target->idx_asm;
360 if (annotate_browser__opts.hide_src_code) {
361 from = bcursor->idx_asm;
362 to = btarget->idx_asm;
363 } else { 191 } else {
364 from = (u64)bcursor->idx; 192 from = (u64)cursor->al.idx;
365 to = (u64)btarget->idx; 193 to = (u64)target->idx;
366 } 194 }
367 195
196 width = annotation__cycles_width(notes);
197
368 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); 198 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
369 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, 199 __ui_browser__line_arrow(browser,
200 pcnt_width + 2 + notes->widths.addr + width,
370 from, to); 201 from, to);
371 202
372 if (is_fused(ab, cursor)) { 203 if (is_fused(ab, cursor)) {
373 ui_browser__mark_fused(browser, 204 ui_browser__mark_fused(browser,
374 pcnt_width + 3 + ab->addr_width, 205 pcnt_width + 3 + notes->widths.addr + width,
375 from - 1, 206 from - 1,
376 to > from ? true : false); 207 to > from ? true : false);
377 } 208 }
@@ -379,11 +210,11 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
379 210
380static unsigned int annotate_browser__refresh(struct ui_browser *browser) 211static unsigned int annotate_browser__refresh(struct ui_browser *browser)
381{ 212{
382 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 213 struct annotation *notes = browser__annotation(browser);
383 int ret = ui_browser__list_head_refresh(browser); 214 int ret = ui_browser__list_head_refresh(browser);
384 int pcnt_width = annotate_browser__pcnt_width(ab); 215 int pcnt_width = annotation__pcnt_width(notes);
385 216
386 if (annotate_browser__opts.jump_arrows) 217 if (notes->options->jump_arrows)
387 annotate_browser__draw_current_jump(browser); 218 annotate_browser__draw_current_jump(browser);
388 219
389 ui_browser__set_color(browser, HE_COLORSET_NORMAL); 220 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
@@ -425,6 +256,7 @@ static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line
425static void annotate_browser__set_top(struct annotate_browser *browser, 256static void annotate_browser__set_top(struct annotate_browser *browser,
426 struct annotation_line *pos, u32 idx) 257 struct annotation_line *pos, u32 idx)
427{ 258{
259 struct annotation *notes = browser__annotation(&browser->b);
428 unsigned back; 260 unsigned back;
429 261
430 ui_browser__refresh_dimensions(&browser->b); 262 ui_browser__refresh_dimensions(&browser->b);
@@ -434,7 +266,7 @@ static void annotate_browser__set_top(struct annotate_browser *browser,
434 while (browser->b.top_idx != 0 && back != 0) { 266 while (browser->b.top_idx != 0 && back != 0) {
435 pos = list_entry(pos->node.prev, struct annotation_line, node); 267 pos = list_entry(pos->node.prev, struct annotation_line, node);
436 268
437 if (disasm_line__filter(&browser->b, &pos->node)) 269 if (annotation_line__filter(pos, notes))
438 continue; 270 continue;
439 271
440 --browser->b.top_idx; 272 --browser->b.top_idx;
@@ -448,16 +280,12 @@ static void annotate_browser__set_top(struct annotate_browser *browser,
448static void annotate_browser__set_rb_top(struct annotate_browser *browser, 280static void annotate_browser__set_rb_top(struct annotate_browser *browser,
449 struct rb_node *nd) 281 struct rb_node *nd)
450{ 282{
451 struct browser_line *bpos; 283 struct annotation *notes = browser__annotation(&browser->b);
452 struct annotation_line *pos; 284 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
453 u32 idx; 285 u32 idx = pos->idx;
454
455 pos = rb_entry(nd, struct annotation_line, rb_node);
456 bpos = browser_line(pos);
457 286
458 idx = bpos->idx; 287 if (notes->options->hide_src_code)
459 if (annotate_browser__opts.hide_src_code) 288 idx = pos->idx_asm;
460 idx = bpos->idx_asm;
461 annotate_browser__set_top(browser, pos, idx); 289 annotate_browser__set_top(browser, pos, idx);
462 browser->curr_hot = nd; 290 browser->curr_hot = nd;
463} 291}
@@ -505,47 +333,47 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
505 333
506static bool annotate_browser__toggle_source(struct annotate_browser *browser) 334static bool annotate_browser__toggle_source(struct annotate_browser *browser)
507{ 335{
336 struct annotation *notes = browser__annotation(&browser->b);
508 struct annotation_line *al; 337 struct annotation_line *al;
509 struct browser_line *bl;
510 off_t offset = browser->b.index - browser->b.top_idx; 338 off_t offset = browser->b.index - browser->b.top_idx;
511 339
512 browser->b.seek(&browser->b, offset, SEEK_CUR); 340 browser->b.seek(&browser->b, offset, SEEK_CUR);
513 al = list_entry(browser->b.top, struct annotation_line, node); 341 al = list_entry(browser->b.top, struct annotation_line, node);
514 bl = browser_line(al);
515 342
516 if (annotate_browser__opts.hide_src_code) { 343 if (notes->options->hide_src_code) {
517 if (bl->idx_asm < offset) 344 if (al->idx_asm < offset)
518 offset = bl->idx; 345 offset = al->idx;
519 346
520 browser->b.nr_entries = browser->nr_entries; 347 browser->b.nr_entries = notes->nr_entries;
521 annotate_browser__opts.hide_src_code = false; 348 notes->options->hide_src_code = false;
522 browser->b.seek(&browser->b, -offset, SEEK_CUR); 349 browser->b.seek(&browser->b, -offset, SEEK_CUR);
523 browser->b.top_idx = bl->idx - offset; 350 browser->b.top_idx = al->idx - offset;
524 browser->b.index = bl->idx; 351 browser->b.index = al->idx;
525 } else { 352 } else {
526 if (bl->idx_asm < 0) { 353 if (al->idx_asm < 0) {
527 ui_helpline__puts("Only available for assembly lines."); 354 ui_helpline__puts("Only available for assembly lines.");
528 browser->b.seek(&browser->b, -offset, SEEK_CUR); 355 browser->b.seek(&browser->b, -offset, SEEK_CUR);
529 return false; 356 return false;
530 } 357 }
531 358
532 if (bl->idx_asm < offset) 359 if (al->idx_asm < offset)
533 offset = bl->idx_asm; 360 offset = al->idx_asm;
534 361
535 browser->b.nr_entries = browser->nr_asm_entries; 362 browser->b.nr_entries = notes->nr_asm_entries;
536 annotate_browser__opts.hide_src_code = true; 363 notes->options->hide_src_code = true;
537 browser->b.seek(&browser->b, -offset, SEEK_CUR); 364 browser->b.seek(&browser->b, -offset, SEEK_CUR);
538 browser->b.top_idx = bl->idx_asm - offset; 365 browser->b.top_idx = al->idx_asm - offset;
539 browser->b.index = bl->idx_asm; 366 browser->b.index = al->idx_asm;
540 } 367 }
541 368
542 return true; 369 return true;
543} 370}
544 371
545static void annotate_browser__init_asm_mode(struct annotate_browser *browser) 372static void ui_browser__init_asm_mode(struct ui_browser *browser)
546{ 373{
547 ui_browser__reset_index(&browser->b); 374 struct annotation *notes = browser__annotation(browser);
548 browser->b.nr_entries = browser->nr_asm_entries; 375 ui_browser__reset_index(browser);
376 browser->nr_entries = notes->nr_asm_entries;
549} 377}
550 378
551#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 379#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
@@ -556,6 +384,15 @@ static int sym_title(struct symbol *sym, struct map *map, char *title,
556 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); 384 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
557} 385}
558 386
387/*
388 * This can be called from external jumps, i.e. jumps from one functon
389 * to another, like from the kernel's entry_SYSCALL_64 function to the
390 * swapgs_restore_regs_and_return_to_usermode() function.
391 *
392 * So all we check here is that dl->ops.target.sym is set, if it is, just
393 * go to that function and when exiting from its disassembly, come back
394 * to the calling function.
395 */
559static bool annotate_browser__callq(struct annotate_browser *browser, 396static bool annotate_browser__callq(struct annotate_browser *browser,
560 struct perf_evsel *evsel, 397 struct perf_evsel *evsel,
561 struct hist_browser_timer *hbt) 398 struct hist_browser_timer *hbt)
@@ -563,35 +400,25 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
563 struct map_symbol *ms = browser->b.priv; 400 struct map_symbol *ms = browser->b.priv;
564 struct disasm_line *dl = disasm_line(browser->selection); 401 struct disasm_line *dl = disasm_line(browser->selection);
565 struct annotation *notes; 402 struct annotation *notes;
566 struct addr_map_symbol target = {
567 .map = ms->map,
568 .addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
569 };
570 char title[SYM_TITLE_MAX_SIZE]; 403 char title[SYM_TITLE_MAX_SIZE];
571 404
572 if (!ins__is_call(&dl->ins)) 405 if (!dl->ops.target.sym) {
573 return false;
574
575 if (map_groups__find_ams(&target) ||
576 map__rip_2objdump(target.map, target.map->map_ip(target.map,
577 target.addr)) !=
578 dl->ops.target.addr) {
579 ui_helpline__puts("The called function was not found."); 406 ui_helpline__puts("The called function was not found.");
580 return true; 407 return true;
581 } 408 }
582 409
583 notes = symbol__annotation(target.sym); 410 notes = symbol__annotation(dl->ops.target.sym);
584 pthread_mutex_lock(&notes->lock); 411 pthread_mutex_lock(&notes->lock);
585 412
586 if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) { 413 if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) {
587 pthread_mutex_unlock(&notes->lock); 414 pthread_mutex_unlock(&notes->lock);
588 ui__warning("Not enough memory for annotating '%s' symbol!\n", 415 ui__warning("Not enough memory for annotating '%s' symbol!\n",
589 target.sym->name); 416 dl->ops.target.sym->name);
590 return true; 417 return true;
591 } 418 }
592 419
593 pthread_mutex_unlock(&notes->lock); 420 pthread_mutex_unlock(&notes->lock);
594 symbol__tui_annotate(target.sym, target.map, evsel, hbt); 421 symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt);
595 sym_title(ms->sym, ms->map, title, sizeof(title)); 422 sym_title(ms->sym, ms->map, title, sizeof(title));
596 ui_browser__show_title(&browser->b, title); 423 ui_browser__show_title(&browser->b, title);
597 return true; 424 return true;
@@ -601,23 +428,23 @@ static
601struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, 428struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
602 s64 offset, s64 *idx) 429 s64 offset, s64 *idx)
603{ 430{
604 struct map_symbol *ms = browser->b.priv; 431 struct annotation *notes = browser__annotation(&browser->b);
605 struct symbol *sym = ms->sym;
606 struct annotation *notes = symbol__annotation(sym);
607 struct disasm_line *pos; 432 struct disasm_line *pos;
608 433
609 *idx = 0; 434 *idx = 0;
610 list_for_each_entry(pos, &notes->src->source, al.node) { 435 list_for_each_entry(pos, &notes->src->source, al.node) {
611 if (pos->al.offset == offset) 436 if (pos->al.offset == offset)
612 return pos; 437 return pos;
613 if (!disasm_line__filter(&browser->b, &pos->al.node)) 438 if (!annotation_line__filter(&pos->al, notes))
614 ++*idx; 439 ++*idx;
615 } 440 }
616 441
617 return NULL; 442 return NULL;
618} 443}
619 444
620static bool annotate_browser__jump(struct annotate_browser *browser) 445static bool annotate_browser__jump(struct annotate_browser *browser,
446 struct perf_evsel *evsel,
447 struct hist_browser_timer *hbt)
621{ 448{
622 struct disasm_line *dl = disasm_line(browser->selection); 449 struct disasm_line *dl = disasm_line(browser->selection);
623 u64 offset; 450 u64 offset;
@@ -626,6 +453,11 @@ static bool annotate_browser__jump(struct annotate_browser *browser)
626 if (!ins__is_jump(&dl->ins)) 453 if (!ins__is_jump(&dl->ins))
627 return false; 454 return false;
628 455
456 if (dl->ops.target.outside) {
457 annotate_browser__callq(browser, evsel, hbt);
458 return true;
459 }
460
629 offset = dl->ops.target.offset; 461 offset = dl->ops.target.offset;
630 dl = annotate_browser__find_offset(browser, offset, &idx); 462 dl = annotate_browser__find_offset(browser, offset, &idx);
631 if (dl == NULL) { 463 if (dl == NULL) {
@@ -642,14 +474,12 @@ static
642struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser, 474struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
643 char *s, s64 *idx) 475 char *s, s64 *idx)
644{ 476{
645 struct map_symbol *ms = browser->b.priv; 477 struct annotation *notes = browser__annotation(&browser->b);
646 struct symbol *sym = ms->sym;
647 struct annotation *notes = symbol__annotation(sym);
648 struct annotation_line *al = browser->selection; 478 struct annotation_line *al = browser->selection;
649 479
650 *idx = browser->b.index; 480 *idx = browser->b.index;
651 list_for_each_entry_continue(al, &notes->src->source, node) { 481 list_for_each_entry_continue(al, &notes->src->source, node) {
652 if (disasm_line__filter(&browser->b, &al->node)) 482 if (annotation_line__filter(al, notes))
653 continue; 483 continue;
654 484
655 ++*idx; 485 ++*idx;
@@ -681,14 +511,12 @@ static
681struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, 511struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
682 char *s, s64 *idx) 512 char *s, s64 *idx)
683{ 513{
684 struct map_symbol *ms = browser->b.priv; 514 struct annotation *notes = browser__annotation(&browser->b);
685 struct symbol *sym = ms->sym;
686 struct annotation *notes = symbol__annotation(sym);
687 struct annotation_line *al = browser->selection; 515 struct annotation_line *al = browser->selection;
688 516
689 *idx = browser->b.index; 517 *idx = browser->b.index;
690 list_for_each_entry_continue_reverse(al, &notes->src->source, node) { 518 list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
691 if (disasm_line__filter(&browser->b, &al->node)) 519 if (annotation_line__filter(al, notes))
692 continue; 520 continue;
693 521
694 --*idx; 522 --*idx;
@@ -764,19 +592,6 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
764 return __annotate_browser__search_reverse(browser); 592 return __annotate_browser__search_reverse(browser);
765} 593}
766 594
767static void annotate_browser__update_addr_width(struct annotate_browser *browser)
768{
769 if (annotate_browser__opts.use_offset)
770 browser->target_width = browser->min_addr_width;
771 else
772 browser->target_width = browser->max_addr_width;
773
774 browser->addr_width = browser->target_width;
775
776 if (annotate_browser__opts.show_nr_jumps)
777 browser->addr_width += browser->jumps_width + 1;
778}
779
780static int annotate_browser__run(struct annotate_browser *browser, 595static int annotate_browser__run(struct annotate_browser *browser,
781 struct perf_evsel *evsel, 596 struct perf_evsel *evsel,
782 struct hist_browser_timer *hbt) 597 struct hist_browser_timer *hbt)
@@ -784,6 +599,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
784 struct rb_node *nd = NULL; 599 struct rb_node *nd = NULL;
785 struct map_symbol *ms = browser->b.priv; 600 struct map_symbol *ms = browser->b.priv;
786 struct symbol *sym = ms->sym; 601 struct symbol *sym = ms->sym;
602 struct annotation *notes = symbol__annotation(ms->sym);
787 const char *help = "Press 'h' for help on key bindings"; 603 const char *help = "Press 'h' for help on key bindings";
788 int delay_secs = hbt ? hbt->refresh : 0; 604 int delay_secs = hbt ? hbt->refresh : 0;
789 int key; 605 int key;
@@ -858,6 +674,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
858 "t Circulate percent, total period, samples view\n" 674 "t Circulate percent, total period, samples view\n"
859 "/ Search string\n" 675 "/ Search string\n"
860 "k Toggle line numbers\n" 676 "k Toggle line numbers\n"
677 "P Print to [symbol_name].annotation file.\n"
861 "r Run available scripts\n" 678 "r Run available scripts\n"
862 "? Search string backwards\n"); 679 "? Search string backwards\n");
863 continue; 680 continue;
@@ -867,8 +684,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
867 continue; 684 continue;
868 } 685 }
869 case 'k': 686 case 'k':
870 annotate_browser__opts.show_linenr = 687 notes->options->show_linenr = !notes->options->show_linenr;
871 !annotate_browser__opts.show_linenr;
872 break; 688 break;
873 case 'H': 689 case 'H':
874 nd = browser->curr_hot; 690 nd = browser->curr_hot;
@@ -878,15 +694,15 @@ static int annotate_browser__run(struct annotate_browser *browser,
878 ui_helpline__puts(help); 694 ui_helpline__puts(help);
879 continue; 695 continue;
880 case 'o': 696 case 'o':
881 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset; 697 notes->options->use_offset = !notes->options->use_offset;
882 annotate_browser__update_addr_width(browser); 698 annotation__update_column_widths(notes);
883 continue; 699 continue;
884 case 'j': 700 case 'j':
885 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows; 701 notes->options->jump_arrows = !notes->options->jump_arrows;
886 continue; 702 continue;
887 case 'J': 703 case 'J':
888 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps; 704 notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
889 annotate_browser__update_addr_width(browser); 705 annotation__update_column_widths(notes);
890 continue; 706 continue;
891 case '/': 707 case '/':
892 if (annotate_browser__search(browser, delay_secs)) { 708 if (annotate_browser__search(browser, delay_secs)) {
@@ -912,7 +728,7 @@ show_help:
912 browser->b.height, 728 browser->b.height,
913 browser->b.index, 729 browser->b.index,
914 browser->b.top_idx, 730 browser->b.top_idx,
915 browser->nr_asm_entries); 731 notes->nr_asm_entries);
916 } 732 }
917 continue; 733 continue;
918 case K_ENTER: 734 case K_ENTER:
@@ -928,22 +744,25 @@ show_help:
928 goto show_sup_ins; 744 goto show_sup_ins;
929 else if (ins__is_ret(&dl->ins)) 745 else if (ins__is_ret(&dl->ins))
930 goto out; 746 goto out;
931 else if (!(annotate_browser__jump(browser) || 747 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
932 annotate_browser__callq(browser, evsel, hbt))) { 748 annotate_browser__callq(browser, evsel, hbt))) {
933show_sup_ins: 749show_sup_ins:
934 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); 750 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
935 } 751 }
936 continue; 752 continue;
937 } 753 }
754 case 'P':
755 map_symbol__annotation_dump(ms, evsel);
756 continue;
938 case 't': 757 case 't':
939 if (annotate_browser__opts.show_total_period) { 758 if (notes->options->show_total_period) {
940 annotate_browser__opts.show_total_period = false; 759 notes->options->show_total_period = false;
941 annotate_browser__opts.show_nr_samples = true; 760 notes->options->show_nr_samples = true;
942 } else if (annotate_browser__opts.show_nr_samples) 761 } else if (notes->options->show_nr_samples)
943 annotate_browser__opts.show_nr_samples = false; 762 notes->options->show_nr_samples = false;
944 else 763 else
945 annotate_browser__opts.show_total_period = true; 764 notes->options->show_total_period = true;
946 annotate_browser__update_addr_width(browser); 765 annotation__update_column_widths(notes);
947 continue; 766 continue;
948 case K_LEFT: 767 case K_LEFT:
949 case K_ESC: 768 case K_ESC:
@@ -965,12 +784,6 @@ out:
965int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, 784int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
966 struct hist_browser_timer *hbt) 785 struct hist_browser_timer *hbt)
967{ 786{
968 /* Set default value for show_total_period and show_nr_samples */
969 annotate_browser__opts.show_total_period =
970 symbol_conf.show_total_period;
971 annotate_browser__opts.show_nr_samples =
972 symbol_conf.show_nr_samples;
973
974 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); 787 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
975} 788}
976 789
@@ -984,129 +797,11 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
984 return map_symbol__tui_annotate(&he->ms, evsel, hbt); 797 return map_symbol__tui_annotate(&he->ms, evsel, hbt);
985} 798}
986 799
987
988static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
989{
990 unsigned n_insn = 0;
991 u64 offset;
992
993 for (offset = start; offset <= end; offset++) {
994 if (browser->offsets[offset])
995 n_insn++;
996 }
997 return n_insn;
998}
999
1000static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
1001 struct cyc_hist *ch)
1002{
1003 unsigned n_insn;
1004 u64 offset;
1005
1006 n_insn = count_insn(browser, start, end);
1007 if (n_insn && ch->num && ch->cycles) {
1008 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
1009
1010 /* Hide data when there are too many overlaps. */
1011 if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
1012 return;
1013
1014 for (offset = start; offset <= end; offset++) {
1015 struct annotation_line *al = browser->offsets[offset];
1016
1017 if (al)
1018 al->ipc = ipc;
1019 }
1020 }
1021}
1022
1023/*
1024 * This should probably be in util/annotate.c to share with the tty
1025 * annotate, but right now we need the per byte offsets arrays,
1026 * which are only here.
1027 */
1028static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
1029 struct symbol *sym)
1030{
1031 u64 offset;
1032 struct annotation *notes = symbol__annotation(sym);
1033
1034 if (!notes->src || !notes->src->cycles_hist)
1035 return;
1036
1037 pthread_mutex_lock(&notes->lock);
1038 for (offset = 0; offset < size; ++offset) {
1039 struct cyc_hist *ch;
1040
1041 ch = &notes->src->cycles_hist[offset];
1042 if (ch && ch->cycles) {
1043 struct annotation_line *al;
1044
1045 if (ch->have_start)
1046 count_and_fill(browser, ch->start, offset, ch);
1047 al = browser->offsets[offset];
1048 if (al && ch->num_aggr)
1049 al->cycles = ch->cycles_aggr / ch->num_aggr;
1050 browser->have_cycles = true;
1051 }
1052 }
1053 pthread_mutex_unlock(&notes->lock);
1054}
1055
1056static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1057 size_t size)
1058{
1059 u64 offset;
1060 struct map_symbol *ms = browser->b.priv;
1061 struct symbol *sym = ms->sym;
1062
1063 /* PLT symbols contain external offsets */
1064 if (strstr(sym->name, "@plt"))
1065 return;
1066
1067 for (offset = 0; offset < size; ++offset) {
1068 struct annotation_line *al = browser->offsets[offset];
1069 struct disasm_line *dl;
1070 struct browser_line *blt;
1071
1072 dl = disasm_line(al);
1073
1074 if (!disasm_line__is_valid_jump(dl, sym))
1075 continue;
1076
1077 al = browser->offsets[dl->ops.target.offset];
1078
1079 /*
1080 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
1081 * have to adjust to the previous offset?
1082 */
1083 if (al == NULL)
1084 continue;
1085
1086 blt = browser_line(al);
1087 if (++blt->jump_sources > browser->max_jump_sources)
1088 browser->max_jump_sources = blt->jump_sources;
1089
1090 ++browser->nr_jumps;
1091 }
1092}
1093
1094static inline int width_jumps(int n)
1095{
1096 if (n >= 100)
1097 return 5;
1098 if (n / 10)
1099 return 2;
1100 return 1;
1101}
1102
1103int symbol__tui_annotate(struct symbol *sym, struct map *map, 800int symbol__tui_annotate(struct symbol *sym, struct map *map,
1104 struct perf_evsel *evsel, 801 struct perf_evsel *evsel,
1105 struct hist_browser_timer *hbt) 802 struct hist_browser_timer *hbt)
1106{ 803{
1107 struct annotation_line *al; 804 struct annotation *notes = symbol__annotation(sym);
1108 struct annotation *notes;
1109 size_t size;
1110 struct map_symbol ms = { 805 struct map_symbol ms = {
1111 .map = map, 806 .map = map,
1112 .sym = sym, 807 .sym = sym,
@@ -1122,26 +817,14 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
1122 }, 817 },
1123 }; 818 };
1124 int ret = -1, err; 819 int ret = -1, err;
1125 int nr_pcnt = 1;
1126 820
1127 if (sym == NULL) 821 if (sym == NULL)
1128 return -1; 822 return -1;
1129 823
1130 size = symbol__size(sym);
1131
1132 if (map->dso->annotate_warned) 824 if (map->dso->annotate_warned)
1133 return -1; 825 return -1;
1134 826
1135 browser.offsets = zalloc(size * sizeof(struct annotation_line *)); 827 err = symbol__annotate2(sym, map, evsel, &annotation__default_options, &browser.arch);
1136 if (browser.offsets == NULL) {
1137 ui__error("Not enough memory!");
1138 return -1;
1139 }
1140
1141 if (perf_evsel__is_group_event(evsel))
1142 nr_pcnt = evsel->nr_members;
1143
1144 err = symbol__annotate(sym, map, evsel, sizeof(struct browser_line), &browser.arch);
1145 if (err) { 828 if (err) {
1146 char msg[BUFSIZ]; 829 char msg[BUFSIZ];
1147 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); 830 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
@@ -1149,110 +832,21 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
1149 goto out_free_offsets; 832 goto out_free_offsets;
1150 } 833 }
1151 834
1152 symbol__calc_percent(sym, evsel);
1153
1154 ui_helpline__push("Press ESC to exit"); 835 ui_helpline__push("Press ESC to exit");
1155 836
1156 notes = symbol__annotation(sym); 837 browser.b.width = notes->max_line_len;
1157 browser.start = map__rip_2objdump(map, sym->start); 838 browser.b.nr_entries = notes->nr_entries;
1158
1159 list_for_each_entry(al, &notes->src->source, node) {
1160 struct browser_line *bpos;
1161 size_t line_len = strlen(al->line);
1162
1163 if (browser.b.width < line_len)
1164 browser.b.width = line_len;
1165 bpos = browser_line(al);
1166 bpos->idx = browser.nr_entries++;
1167 if (al->offset != -1) {
1168 bpos->idx_asm = browser.nr_asm_entries++;
1169 /*
1170 * FIXME: short term bandaid to cope with assembly
1171 * routines that comes with labels in the same column
1172 * as the address in objdump, sigh.
1173 *
1174 * E.g. copy_user_generic_unrolled
1175 */
1176 if (al->offset < (s64)size)
1177 browser.offsets[al->offset] = al;
1178 } else
1179 bpos->idx_asm = -1;
1180 }
1181
1182 annotate_browser__mark_jump_targets(&browser, size);
1183 annotate__compute_ipc(&browser, size, sym);
1184
1185 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
1186 browser.max_addr_width = hex_width(sym->end);
1187 browser.jumps_width = width_jumps(browser.max_jump_sources);
1188 browser.nr_events = nr_pcnt;
1189 browser.b.nr_entries = browser.nr_entries;
1190 browser.b.entries = &notes->src->source, 839 browser.b.entries = &notes->src->source,
1191 browser.b.width += 18; /* Percentage */ 840 browser.b.width += 18; /* Percentage */
1192 841
1193 if (annotate_browser__opts.hide_src_code) 842 if (notes->options->hide_src_code)
1194 annotate_browser__init_asm_mode(&browser); 843 ui_browser__init_asm_mode(&browser.b);
1195
1196 annotate_browser__update_addr_width(&browser);
1197 844
1198 ret = annotate_browser__run(&browser, evsel, hbt); 845 ret = annotate_browser__run(&browser, evsel, hbt);
1199 846
1200 annotated_source__purge(notes->src); 847 annotated_source__purge(notes->src);
1201 848
1202out_free_offsets: 849out_free_offsets:
1203 free(browser.offsets); 850 zfree(&notes->offsets);
1204 return ret; 851 return ret;
1205} 852}
1206
1207#define ANNOTATE_CFG(n) \
1208 { .name = #n, .value = &annotate_browser__opts.n, }
1209
1210/*
1211 * Keep the entries sorted, they are bsearch'ed
1212 */
1213static struct annotate_config {
1214 const char *name;
1215 bool *value;
1216} annotate__configs[] = {
1217 ANNOTATE_CFG(hide_src_code),
1218 ANNOTATE_CFG(jump_arrows),
1219 ANNOTATE_CFG(show_linenr),
1220 ANNOTATE_CFG(show_nr_jumps),
1221 ANNOTATE_CFG(show_nr_samples),
1222 ANNOTATE_CFG(show_total_period),
1223 ANNOTATE_CFG(use_offset),
1224};
1225
1226#undef ANNOTATE_CFG
1227
1228static int annotate_config__cmp(const void *name, const void *cfgp)
1229{
1230 const struct annotate_config *cfg = cfgp;
1231
1232 return strcmp(name, cfg->name);
1233}
1234
1235static int annotate__config(const char *var, const char *value,
1236 void *data __maybe_unused)
1237{
1238 struct annotate_config *cfg;
1239 const char *name;
1240
1241 if (!strstarts(var, "annotate."))
1242 return 0;
1243
1244 name = var + 9;
1245 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
1246 sizeof(struct annotate_config), annotate_config__cmp);
1247
1248 if (cfg == NULL)
1249 ui__warning("%s variable unknown, ignoring...", var);
1250 else
1251 *cfg->value = perf_config_bool(name, value);
1252 return 0;
1253}
1254
1255void annotate_browser__init(void)
1256{
1257 perf_config(annotate__config, NULL);
1258}