diff options
Diffstat (limited to 'tools/perf/ui/browsers/annotate.c')
-rw-r--r-- | tools/perf/ui/browsers/annotate.c | 702 |
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 | |||
28 | struct browser_line { | ||
29 | u32 idx; | ||
30 | int idx_asm; | ||
31 | int jump_sources; | ||
32 | }; | ||
33 | |||
34 | static 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 | |||
47 | struct arch; | 24 | struct arch; |
48 | 25 | ||
49 | struct annotate_browser { | 26 | struct 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 | ||
72 | static inline struct browser_line *browser_line(struct annotation_line *al) | 36 | static 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 | ||
80 | static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, | 42 | static 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 | ||
92 | static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, | 49 | static 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 | ||
104 | static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, | 62 | static 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 | ||
111 | static int annotate_browser__pcnt_width(struct annotate_browser *ab) | 68 | static 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 | ||
116 | static int annotate_browser__cycles_width(struct annotate_browser *ab) | 73 | static 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 | ||
121 | static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, | 78 | static 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); | 83 | static 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 | ||
147 | static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) | 92 | static 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 | ||
282 | static 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 | |||
293 | static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor) | 123 | static 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 | ||
380 | static unsigned int annotate_browser__refresh(struct ui_browser *browser) | 211 | static 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 | |||
425 | static void annotate_browser__set_top(struct annotate_browser *browser, | 256 | static 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, | |||
448 | static void annotate_browser__set_rb_top(struct annotate_browser *browser, | 280 | static 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 | ||
506 | static bool annotate_browser__toggle_source(struct annotate_browser *browser) | 334 | static 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 | ||
545 | static void annotate_browser__init_asm_mode(struct annotate_browser *browser) | 372 | static 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 | */ | ||
559 | static bool annotate_browser__callq(struct annotate_browser *browser, | 396 | static 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(¬es->lock); | 411 | pthread_mutex_lock(¬es->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(¬es->lock); | 414 | pthread_mutex_unlock(¬es->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(¬es->lock); | 420 | pthread_mutex_unlock(¬es->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 | |||
601 | struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, | 428 | struct 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, ¬es->src->source, al.node) { | 435 | list_for_each_entry(pos, ¬es->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 | ||
620 | static bool annotate_browser__jump(struct annotate_browser *browser) | 445 | static 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 | |||
642 | struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser, | 474 | struct 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, ¬es->src->source, node) { | 481 | list_for_each_entry_continue(al, ¬es->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 | |||
681 | struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, | 511 | struct 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, ¬es->src->source, node) { | 518 | list_for_each_entry_continue_reverse(al, ¬es->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 | ||
767 | static 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 | |||
780 | static int annotate_browser__run(struct annotate_browser *browser, | 595 | static 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))) { |
933 | show_sup_ins: | 749 | show_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: | |||
965 | int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, | 784 | int 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 | |||
988 | static 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 | |||
1000 | static 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 | */ | ||
1028 | static 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(¬es->lock); | ||
1038 | for (offset = 0; offset < size; ++offset) { | ||
1039 | struct cyc_hist *ch; | ||
1040 | |||
1041 | ch = ¬es->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(¬es->lock); | ||
1054 | } | ||
1055 | |||
1056 | static 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 | |||
1094 | static 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 | |||
1103 | int symbol__tui_annotate(struct symbol *sym, struct map *map, | 800 | int 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, ¬es->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 = ¬es->src->source, | 839 | browser.b.entries = ¬es->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 | ||
1202 | out_free_offsets: | 849 | out_free_offsets: |
1203 | free(browser.offsets); | 850 | zfree(¬es->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 | */ | ||
1213 | static 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 | |||
1228 | static 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 | |||
1235 | static 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 | |||
1255 | void annotate_browser__init(void) | ||
1256 | { | ||
1257 | perf_config(annotate__config, NULL); | ||
1258 | } | ||