1 #include "../browser.h"
2 #include "../helpline.h"
3 #include "../libslang.h"
4 #include "../../annotate.h"
5 #include "../../hist.h"
6 #include "../../sort.h"
7 #include "../../symbol.h"
10 static void ui__error_window(const char *fmt
, ...)
15 newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt
, ap
);
19 struct annotate_browser
{
21 struct rb_root entries
;
22 struct rb_node
*curr_hot
;
23 struct objdump_line
*selection
;
29 struct objdump_line_rb_node
{
30 struct rb_node rb_node
;
37 struct objdump_line_rb_node
*objdump_line__rb(struct objdump_line
*self
)
39 return (struct objdump_line_rb_node
*)(self
+ 1);
42 static bool objdump_line__filter(struct ui_browser
*browser
, void *entry
)
44 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
46 if (ab
->hide_src_code
) {
47 struct objdump_line
*ol
= list_entry(entry
, struct objdump_line
, node
);
48 return ol
->offset
== -1;
54 static void annotate_browser__write(struct ui_browser
*self
, void *entry
, int row
)
56 struct annotate_browser
*ab
= container_of(self
, struct annotate_browser
, b
);
57 struct objdump_line
*ol
= list_entry(entry
, struct objdump_line
, node
);
58 bool current_entry
= ui_browser__is_current_entry(self
, row
);
59 int width
= self
->width
;
61 if (ol
->offset
!= -1) {
62 struct objdump_line_rb_node
*olrb
= objdump_line__rb(ol
);
63 ui_browser__set_percent_color(self
, olrb
->percent
, current_entry
);
64 slsmg_printf(" %7.2f ", olrb
->percent
);
66 ui_browser__set_percent_color(self
, 0, current_entry
);
67 slsmg_write_nstring(" ", 9);
70 SLsmg_write_char(':');
71 slsmg_write_nstring(" ", 8);
73 slsmg_write_nstring(" ", width
- 18);
75 slsmg_write_nstring(ol
->line
, width
- 18);
78 ui_browser__set_color(self
, HE_COLORSET_CODE
);
83 static double objdump_line__calc_percent(struct objdump_line
*self
,
84 struct symbol
*sym
, int evidx
)
88 if (self
->offset
!= -1) {
89 int len
= sym
->end
- sym
->start
;
90 unsigned int hits
= 0;
91 struct annotation
*notes
= symbol__annotation(sym
);
92 struct source_line
*src_line
= notes
->src
->lines
;
93 struct sym_hist
*h
= annotation__histogram(notes
, evidx
);
94 s64 offset
= self
->offset
;
95 struct objdump_line
*next
;
97 next
= objdump__get_next_ip_line(¬es
->src
->source
, self
);
98 while (offset
< (s64
)len
&&
99 (next
== NULL
|| offset
< next
->offset
)) {
101 percent
+= src_line
[offset
].percent
;
103 hits
+= h
->addr
[offset
];
108 * If the percentage wasn't already calculated in
109 * symbol__get_source_line, do it now:
111 if (src_line
== NULL
&& h
->sum
)
112 percent
= 100.0 * hits
/ h
->sum
;
118 static void objdump__insert_line(struct rb_root
*self
,
119 struct objdump_line_rb_node
*line
)
121 struct rb_node
**p
= &self
->rb_node
;
122 struct rb_node
*parent
= NULL
;
123 struct objdump_line_rb_node
*l
;
127 l
= rb_entry(parent
, struct objdump_line_rb_node
, rb_node
);
128 if (line
->percent
< l
->percent
)
133 rb_link_node(&line
->rb_node
, parent
, p
);
134 rb_insert_color(&line
->rb_node
, self
);
137 static void annotate_browser__set_top(struct annotate_browser
*self
,
140 struct objdump_line_rb_node
*rbpos
;
141 struct objdump_line
*pos
;
144 ui_browser__refresh_dimensions(&self
->b
);
145 back
= self
->b
.height
/ 2;
146 rbpos
= rb_entry(nd
, struct objdump_line_rb_node
, rb_node
);
147 pos
= ((struct objdump_line
*)rbpos
) - 1;
148 self
->b
.top_idx
= self
->b
.index
= rbpos
->idx
;
150 while (self
->b
.top_idx
!= 0 && back
!= 0) {
151 pos
= list_entry(pos
->node
.prev
, struct objdump_line
, node
);
161 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
164 struct map_symbol
*ms
= browser
->b
.priv
;
165 struct symbol
*sym
= ms
->sym
;
166 struct annotation
*notes
= symbol__annotation(sym
);
167 struct objdump_line
*pos
;
169 browser
->entries
= RB_ROOT
;
171 pthread_mutex_lock(¬es
->lock
);
173 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
174 struct objdump_line_rb_node
*rbpos
= objdump_line__rb(pos
);
175 rbpos
->percent
= objdump_line__calc_percent(pos
, sym
, evidx
);
176 if (rbpos
->percent
< 0.01) {
177 RB_CLEAR_NODE(&rbpos
->rb_node
);
180 objdump__insert_line(&browser
->entries
, rbpos
);
182 pthread_mutex_unlock(¬es
->lock
);
184 browser
->curr_hot
= rb_last(&browser
->entries
);
187 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
189 struct objdump_line
*ol
;
190 struct objdump_line_rb_node
*olrb
;
191 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
193 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
194 ol
= list_entry(browser
->b
.top
, struct objdump_line
, node
);
195 olrb
= objdump_line__rb(ol
);
197 if (browser
->hide_src_code
) {
198 if (olrb
->idx_asm
< offset
)
201 browser
->b
.nr_entries
= browser
->nr_entries
;
202 browser
->hide_src_code
= false;
203 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
204 browser
->b
.top_idx
= olrb
->idx
- offset
;
205 browser
->b
.index
= olrb
->idx
;
207 if (olrb
->idx_asm
< 0) {
208 ui_helpline__puts("Only available for assembly lines.");
209 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
213 if (olrb
->idx_asm
< offset
)
214 offset
= olrb
->idx_asm
;
216 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
217 browser
->hide_src_code
= true;
218 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
219 browser
->b
.top_idx
= olrb
->idx_asm
- offset
;
220 browser
->b
.index
= olrb
->idx_asm
;
226 static int annotate_browser__run(struct annotate_browser
*self
, int evidx
,
227 int nr_events
, void(*timer
)(void *arg
),
228 void *arg
, int delay_secs
)
230 struct rb_node
*nd
= NULL
;
231 struct map_symbol
*ms
= self
->b
.priv
;
232 struct symbol
*sym
= ms
->sym
;
233 const char *help
= "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
234 "H: Hottest, -> Line action, S -> Toggle source "
238 if (ui_browser__show(&self
->b
, sym
->name
, help
) < 0)
241 annotate_browser__calc_percent(self
, evidx
);
244 annotate_browser__set_top(self
, self
->curr_hot
);
249 key
= ui_browser__run(&self
->b
, delay_secs
);
251 if (delay_secs
!= 0) {
252 annotate_browser__calc_percent(self
, evidx
);
254 * Current line focus got out of the list of most active
255 * lines, NULL it so that if TAB|UNTAB is pressed, we
256 * move to curr_hot (current hottest line).
258 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
265 * FIXME we need to check if it was
266 * es.reason == NEWT_EXIT_TIMER
272 symbol__annotate_decay_histogram(sym
, evidx
);
278 nd
= rb_last(&self
->entries
);
286 nd
= rb_first(&self
->entries
);
294 if (annotate_browser__toggle_source(self
))
295 ui_helpline__puts(help
);
299 if (self
->selection
== NULL
) {
300 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
304 if (self
->selection
->offset
== -1) {
305 ui_helpline__puts("Actions are only available for assembly lines.");
308 char *s
= strstr(self
->selection
->line
, "callq ");
309 struct annotation
*notes
;
310 struct symbol
*target
;
314 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
320 ui_helpline__puts("Invallid callq instruction.");
324 ip
= strtoull(s
, NULL
, 16);
325 ip
= ms
->map
->map_ip(ms
->map
, ip
);
326 target
= map__find_symbol(ms
->map
, ip
, NULL
);
327 if (target
== NULL
) {
328 ui_helpline__puts("The called function was not found.");
332 notes
= symbol__annotation(target
);
333 pthread_mutex_lock(¬es
->lock
);
335 if (notes
->src
== NULL
&&
336 symbol__alloc_hist(target
, nr_events
) < 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
, nr_events
,
345 timer
, arg
, delay_secs
);
349 case NEWT_KEY_ESCAPE
:
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
, int nr_events
,
366 void(*timer
)(void *arg
), void *arg
, int delay_secs
)
368 return symbol__tui_annotate(he
->ms
.sym
, he
->ms
.map
, evidx
, nr_events
,
369 timer
, arg
, delay_secs
);
372 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
, int evidx
,
373 int nr_events
, 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
,
396 if (map
->dso
->annotate_warned
)
399 if (symbol__annotate(sym
, map
, sizeof(struct objdump_line_rb_node
)) < 0) {
400 ui__error_window(ui_helpline__last_msg
);
404 ui_helpline__push("Press <- or ESC to exit");
406 notes
= symbol__annotation(sym
);
408 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
409 struct objdump_line_rb_node
*rbpos
;
410 size_t line_len
= strlen(pos
->line
);
412 if (browser
.b
.width
< line_len
)
413 browser
.b
.width
= line_len
;
414 rbpos
= objdump_line__rb(pos
);
415 rbpos
->idx
= browser
.nr_entries
++;
416 if (pos
->offset
!= -1)
417 rbpos
->idx_asm
= browser
.nr_asm_entries
++;
422 browser
.b
.nr_entries
= browser
.nr_entries
;
423 browser
.b
.entries
= ¬es
->src
->source
,
424 browser
.b
.width
+= 18; /* Percentage */
425 ret
= annotate_browser__run(&browser
, evidx
, nr_events
,
426 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
);