1 #include "../../util.h"
2 #include "../browser.h"
3 #include "../helpline.h"
4 #include "../libslang.h"
7 #include "../../annotate.h"
8 #include "../../hist.h"
9 #include "../../sort.h"
10 #include "../../symbol.h"
14 struct annotate_browser
{
16 struct rb_root entries
;
17 struct rb_node
*curr_hot
;
18 struct objdump_line
*selection
;
24 struct objdump_line_rb_node
{
25 struct rb_node rb_node
;
32 struct objdump_line_rb_node
*objdump_line__rb(struct objdump_line
*self
)
34 return (struct objdump_line_rb_node
*)(self
+ 1);
37 static bool objdump_line__filter(struct ui_browser
*browser
, void *entry
)
39 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
41 if (ab
->hide_src_code
) {
42 struct objdump_line
*ol
= list_entry(entry
, struct objdump_line
, node
);
43 return ol
->offset
== -1;
49 static void annotate_browser__write(struct ui_browser
*self
, void *entry
, int row
)
51 struct annotate_browser
*ab
= container_of(self
, struct annotate_browser
, b
);
52 struct objdump_line
*ol
= list_entry(entry
, struct objdump_line
, node
);
53 bool current_entry
= ui_browser__is_current_entry(self
, row
);
54 int width
= self
->width
;
56 if (ol
->offset
!= -1) {
57 struct objdump_line_rb_node
*olrb
= objdump_line__rb(ol
);
58 ui_browser__set_percent_color(self
, olrb
->percent
, current_entry
);
59 slsmg_printf(" %7.2f ", olrb
->percent
);
61 ui_browser__set_percent_color(self
, 0, current_entry
);
62 slsmg_write_nstring(" ", 9);
65 SLsmg_write_char(':');
66 slsmg_write_nstring(" ", 8);
68 /* The scroll bar isn't being used */
69 if (!self
->navkeypressed
)
72 if (!ab
->hide_src_code
&& ol
->offset
!= -1)
73 if (!current_entry
|| (self
->use_navkeypressed
&&
74 !self
->navkeypressed
))
75 ui_browser__set_color(self
, HE_COLORSET_CODE
);
78 slsmg_write_nstring(" ", width
- 18);
80 slsmg_write_nstring(ol
->line
, width
- 18);
86 static double objdump_line__calc_percent(struct objdump_line
*self
,
87 struct symbol
*sym
, int evidx
)
91 if (self
->offset
!= -1) {
92 int len
= sym
->end
- sym
->start
;
93 unsigned int hits
= 0;
94 struct annotation
*notes
= symbol__annotation(sym
);
95 struct source_line
*src_line
= notes
->src
->lines
;
96 struct sym_hist
*h
= annotation__histogram(notes
, evidx
);
97 s64 offset
= self
->offset
;
98 struct objdump_line
*next
;
100 next
= objdump__get_next_ip_line(¬es
->src
->source
, self
);
101 while (offset
< (s64
)len
&&
102 (next
== NULL
|| offset
< next
->offset
)) {
104 percent
+= src_line
[offset
].percent
;
106 hits
+= h
->addr
[offset
];
111 * If the percentage wasn't already calculated in
112 * symbol__get_source_line, do it now:
114 if (src_line
== NULL
&& h
->sum
)
115 percent
= 100.0 * hits
/ h
->sum
;
121 static void objdump__insert_line(struct rb_root
*self
,
122 struct objdump_line_rb_node
*line
)
124 struct rb_node
**p
= &self
->rb_node
;
125 struct rb_node
*parent
= NULL
;
126 struct objdump_line_rb_node
*l
;
130 l
= rb_entry(parent
, struct objdump_line_rb_node
, rb_node
);
131 if (line
->percent
< l
->percent
)
136 rb_link_node(&line
->rb_node
, parent
, p
);
137 rb_insert_color(&line
->rb_node
, self
);
140 static void annotate_browser__set_top(struct annotate_browser
*self
,
143 struct objdump_line_rb_node
*rbpos
;
144 struct objdump_line
*pos
;
147 ui_browser__refresh_dimensions(&self
->b
);
148 back
= self
->b
.height
/ 2;
149 rbpos
= rb_entry(nd
, struct objdump_line_rb_node
, rb_node
);
150 pos
= ((struct objdump_line
*)rbpos
) - 1;
151 self
->b
.top_idx
= self
->b
.index
= rbpos
->idx
;
153 while (self
->b
.top_idx
!= 0 && back
!= 0) {
154 pos
= list_entry(pos
->node
.prev
, struct objdump_line
, node
);
164 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
167 struct map_symbol
*ms
= browser
->b
.priv
;
168 struct symbol
*sym
= ms
->sym
;
169 struct annotation
*notes
= symbol__annotation(sym
);
170 struct objdump_line
*pos
;
172 browser
->entries
= RB_ROOT
;
174 pthread_mutex_lock(¬es
->lock
);
176 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
177 struct objdump_line_rb_node
*rbpos
= objdump_line__rb(pos
);
178 rbpos
->percent
= objdump_line__calc_percent(pos
, sym
, evidx
);
179 if (rbpos
->percent
< 0.01) {
180 RB_CLEAR_NODE(&rbpos
->rb_node
);
183 objdump__insert_line(&browser
->entries
, rbpos
);
185 pthread_mutex_unlock(¬es
->lock
);
187 browser
->curr_hot
= rb_last(&browser
->entries
);
190 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
192 struct objdump_line
*ol
;
193 struct objdump_line_rb_node
*olrb
;
194 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
196 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
197 ol
= list_entry(browser
->b
.top
, struct objdump_line
, node
);
198 olrb
= objdump_line__rb(ol
);
200 if (browser
->hide_src_code
) {
201 if (olrb
->idx_asm
< offset
)
204 browser
->b
.nr_entries
= browser
->nr_entries
;
205 browser
->hide_src_code
= false;
206 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
207 browser
->b
.top_idx
= olrb
->idx
- offset
;
208 browser
->b
.index
= olrb
->idx
;
210 if (olrb
->idx_asm
< 0) {
211 ui_helpline__puts("Only available for assembly lines.");
212 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
216 if (olrb
->idx_asm
< offset
)
217 offset
= olrb
->idx_asm
;
219 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
220 browser
->hide_src_code
= true;
221 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
222 browser
->b
.top_idx
= olrb
->idx_asm
- offset
;
223 browser
->b
.index
= olrb
->idx_asm
;
229 static int annotate_browser__run(struct annotate_browser
*self
, int evidx
,
230 void(*timer
)(void *arg
),
231 void *arg
, int delay_secs
)
233 struct rb_node
*nd
= NULL
;
234 struct map_symbol
*ms
= self
->b
.priv
;
235 struct symbol
*sym
= ms
->sym
;
236 const char *help
= "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
237 "H: Hottest, -> Line action, S -> Toggle source "
241 if (ui_browser__show(&self
->b
, sym
->name
, help
) < 0)
244 annotate_browser__calc_percent(self
, evidx
);
247 annotate_browser__set_top(self
, self
->curr_hot
);
252 key
= ui_browser__run(&self
->b
, delay_secs
);
254 if (delay_secs
!= 0) {
255 annotate_browser__calc_percent(self
, evidx
);
257 * Current line focus got out of the list of most active
258 * lines, NULL it so that if TAB|UNTAB is pressed, we
259 * move to curr_hot (current hottest line).
261 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
271 symbol__annotate_decay_histogram(sym
, evidx
);
277 nd
= rb_last(&self
->entries
);
285 nd
= rb_first(&self
->entries
);
295 if (annotate_browser__toggle_source(self
))
296 ui_helpline__puts(help
);
300 if (self
->selection
== NULL
) {
301 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
305 if (self
->selection
->offset
== -1) {
306 ui_helpline__puts("Actions are only available for assembly lines.");
309 char *s
= strstr(self
->selection
->line
, "callq ");
310 struct annotation
*notes
;
311 struct symbol
*target
;
315 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
321 ui_helpline__puts("Invallid callq instruction.");
325 ip
= strtoull(s
, NULL
, 16);
326 ip
= ms
->map
->map_ip(ms
->map
, ip
);
327 target
= map__find_symbol(ms
->map
, ip
, NULL
);
328 if (target
== NULL
) {
329 ui_helpline__puts("The called function was not found.");
333 notes
= symbol__annotation(target
);
334 pthread_mutex_lock(¬es
->lock
);
336 if (notes
->src
== NULL
&& symbol__alloc_hist(target
) < 0) {
337 pthread_mutex_unlock(¬es
->lock
);
338 ui__warning("Not enough memory for annotating '%s' symbol!\n",
343 pthread_mutex_unlock(¬es
->lock
);
344 symbol__tui_annotate(target
, ms
->map
, evidx
,
345 timer
, arg
, delay_secs
);
358 annotate_browser__set_top(self
, nd
);
361 ui_browser__hide(&self
->b
);
365 int hist_entry__tui_annotate(struct hist_entry
*he
, int evidx
,
366 void(*timer
)(void *arg
), void *arg
, int delay_secs
)
368 return symbol__tui_annotate(he
->ms
.sym
, he
->ms
.map
, evidx
,
369 timer
, arg
, delay_secs
);
372 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
, int evidx
,
373 void(*timer
)(void *arg
), void *arg
,
376 struct objdump_line
*pos
, *n
;
377 struct annotation
*notes
;
378 struct map_symbol ms
= {
382 struct annotate_browser browser
= {
384 .refresh
= ui_browser__list_head_refresh
,
385 .seek
= ui_browser__list_head_seek
,
386 .write
= annotate_browser__write
,
387 .filter
= objdump_line__filter
,
389 .use_navkeypressed
= true,
397 if (map
->dso
->annotate_warned
)
400 if (symbol__annotate(sym
, map
, sizeof(struct objdump_line_rb_node
)) < 0) {
401 ui__error("%s", ui_helpline__last_msg
);
405 ui_helpline__push("Press <- or ESC to exit");
407 notes
= symbol__annotation(sym
);
409 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
410 struct objdump_line_rb_node
*rbpos
;
411 size_t line_len
= strlen(pos
->line
);
413 if (browser
.b
.width
< line_len
)
414 browser
.b
.width
= line_len
;
415 rbpos
= objdump_line__rb(pos
);
416 rbpos
->idx
= browser
.nr_entries
++;
417 if (pos
->offset
!= -1)
418 rbpos
->idx_asm
= browser
.nr_asm_entries
++;
423 browser
.b
.nr_entries
= browser
.nr_entries
;
424 browser
.b
.entries
= ¬es
->src
->source
,
425 browser
.b
.width
+= 18; /* Percentage */
426 ret
= annotate_browser__run(&browser
, evidx
, timer
, arg
, delay_secs
);
427 list_for_each_entry_safe(pos
, n
, ¬es
->src
->source
, node
) {
428 list_del(&pos
->node
);
429 objdump_line__free(pos
);