2010-08-10 14:54:09 -03:00
# include "../browser.h"
# include "../helpline.h"
# include "../libslang.h"
2011-02-04 09:45:46 -02:00
# include "../../annotate.h"
2010-08-10 14:54:09 -03:00
# include "../../hist.h"
# include "../../sort.h"
# include "../../symbol.h"
2011-02-04 09:45:46 -02:00
# include "../../annotate.h"
2010-08-10 14:54:09 -03:00
static void ui__error_window ( const char * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
newtWinMessagev ( ( char * ) " Error " , ( char * ) " Ok " , ( char * ) fmt , ap ) ;
va_end ( ap ) ;
}
2010-08-09 15:30:40 -03:00
struct annotate_browser {
struct ui_browser b ;
struct rb_root entries ;
2010-08-10 15:14:53 -03:00
struct rb_node * curr_hot ;
2010-08-09 15:30:40 -03:00
} ;
struct objdump_line_rb_node {
struct rb_node rb_node ;
double percent ;
u32 idx ;
} ;
static inline
struct objdump_line_rb_node * objdump_line__rb ( struct objdump_line * self )
{
return ( struct objdump_line_rb_node * ) ( self + 1 ) ;
}
2010-08-10 14:54:09 -03:00
static void annotate_browser__write ( struct ui_browser * self , void * entry , int row )
{
struct objdump_line * ol = rb_entry ( entry , struct objdump_line , node ) ;
bool current_entry = ui_browser__is_current_entry ( self , row ) ;
int width = self - > width ;
if ( ol - > offset ! = - 1 ) {
2010-08-09 15:30:40 -03:00
struct objdump_line_rb_node * olrb = objdump_line__rb ( ol ) ;
2010-08-11 14:51:47 -03:00
ui_browser__set_percent_color ( self , olrb - > percent , current_entry ) ;
2010-08-09 15:30:40 -03:00
slsmg_printf ( " %7.2f " , olrb - > percent ) ;
if ( ! current_entry )
2010-08-11 14:51:47 -03:00
ui_browser__set_color ( self , HE_COLORSET_CODE ) ;
2010-08-09 15:30:40 -03:00
} else {
2010-08-11 14:51:47 -03:00
ui_browser__set_percent_color ( self , 0 , current_entry ) ;
2010-08-09 15:30:40 -03:00
slsmg_write_nstring ( " " , 9 ) ;
}
SLsmg_write_char ( ' : ' ) ;
slsmg_write_nstring ( " " , 8 ) ;
if ( ! * ol - > line )
slsmg_write_nstring ( " " , width - 18 ) ;
else
slsmg_write_nstring ( ol - > line , width - 18 ) ;
}
static double objdump_line__calc_percent ( struct objdump_line * self ,
2011-02-04 13:43:24 -02:00
struct symbol * sym , int evidx )
2010-08-09 15:30:40 -03:00
{
double percent = 0.0 ;
if ( self - > offset ! = - 1 ) {
int len = sym - > end - sym - > start ;
2010-08-10 14:54:09 -03:00
unsigned int hits = 0 ;
2011-02-04 09:45:46 -02:00
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-08 13:27:39 -02:00
struct source_line * src_line = notes - > src - > lines ;
2011-02-04 13:43:24 -02:00
struct sym_hist * h = annotation__histogram ( notes , evidx ) ;
2010-08-09 15:30:40 -03:00
s64 offset = self - > offset ;
2011-02-08 13:27:39 -02:00
struct objdump_line * next ;
2010-08-09 15:30:40 -03:00
2011-02-08 13:27:39 -02:00
next = objdump__get_next_ip_line ( & notes - > src - > source , self ) ;
2010-08-10 14:54:09 -03:00
while ( offset < ( s64 ) len & &
( next = = NULL | | offset < next - > offset ) ) {
2011-02-04 09:45:46 -02:00
if ( src_line ) {
percent + = src_line [ offset ] . percent ;
2010-08-10 14:54:09 -03:00
} else
2011-02-04 09:45:46 -02:00
hits + = h - > addr [ offset ] ;
2010-08-10 14:54:09 -03:00
+ + offset ;
}
2011-02-04 09:45:46 -02:00
/*
* If the percentage wasn ' t already calculated in
* symbol__get_source_line , do it now :
*/
if ( src_line = = NULL & & h - > sum )
2010-08-10 14:54:09 -03:00
percent = 100.0 * hits / h - > sum ;
}
2010-08-09 15:30:40 -03:00
return percent ;
}
static void objdump__insert_line ( struct rb_root * self ,
struct objdump_line_rb_node * line )
{
struct rb_node * * p = & self - > rb_node ;
struct rb_node * parent = NULL ;
struct objdump_line_rb_node * l ;
while ( * p ! = NULL ) {
parent = * p ;
l = rb_entry ( parent , struct objdump_line_rb_node , rb_node ) ;
if ( line - > percent < l - > percent )
p = & ( * p ) - > rb_left ;
else
p = & ( * p ) - > rb_right ;
}
rb_link_node ( & line - > rb_node , parent , p ) ;
rb_insert_color ( & line - > rb_node , self ) ;
2010-08-10 14:54:09 -03:00
}
2010-08-10 15:14:53 -03:00
static void annotate_browser__set_top ( struct annotate_browser * self ,
struct rb_node * nd )
{
struct objdump_line_rb_node * rbpos ;
struct objdump_line * pos ;
unsigned back ;
ui_browser__refresh_dimensions ( & self - > b ) ;
back = self - > b . height / 2 ;
rbpos = rb_entry ( nd , struct objdump_line_rb_node , rb_node ) ;
pos = ( ( struct objdump_line * ) rbpos ) - 1 ;
self - > b . top_idx = self - > b . index = rbpos - > idx ;
while ( self - > b . top_idx ! = 0 & & back ! = 0 ) {
pos = list_entry ( pos - > node . prev , struct objdump_line , node ) ;
- - self - > b . top_idx ;
- - back ;
}
self - > b . top = pos ;
self - > curr_hot = nd ;
}
2010-08-11 10:07:43 -03:00
static int annotate_browser__run ( struct annotate_browser * self )
2010-08-10 15:14:53 -03:00
{
struct rb_node * nd ;
2011-02-04 09:45:46 -02:00
struct symbol * sym = self - > b . priv ;
2010-08-11 10:07:43 -03:00
int key ;
2010-08-10 15:14:53 -03:00
2011-02-04 09:45:46 -02:00
if ( ui_browser__show ( & self - > b , sym - > name ,
2010-08-11 10:07:43 -03:00
" <-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples " ) < 0 )
2010-08-10 15:14:53 -03:00
return - 1 ;
2010-08-12 12:37:51 -03:00
/*
* To allow builtin - annotate to cycle thru multiple symbols by
* examining the exit key for this function .
*/
ui_browser__add_exit_key ( & self - > b , NEWT_KEY_RIGHT ) ;
2010-08-10 15:14:53 -03:00
nd = self - > curr_hot ;
if ( nd ) {
2010-08-12 12:37:51 -03:00
int tabs [ ] = { NEWT_KEY_TAB , NEWT_KEY_UNTAB , 0 } ;
ui_browser__add_exit_keys ( & self - > b , tabs ) ;
2010-08-10 15:14:53 -03:00
}
while ( 1 ) {
2010-08-11 10:07:43 -03:00
key = ui_browser__run ( & self - > b ) ;
2010-08-10 15:14:53 -03:00
2010-08-11 10:07:43 -03:00
switch ( key ) {
2010-08-10 15:14:53 -03:00
case NEWT_KEY_TAB :
nd = rb_prev ( nd ) ;
if ( nd = = NULL )
nd = rb_last ( & self - > entries ) ;
annotate_browser__set_top ( self , nd ) ;
break ;
case NEWT_KEY_UNTAB :
nd = rb_next ( nd ) ;
if ( nd = = NULL )
nd = rb_first ( & self - > entries ) ;
annotate_browser__set_top ( self , nd ) ;
break ;
default :
goto out ;
}
}
out :
2010-08-10 15:44:20 -03:00
ui_browser__hide ( & self - > b ) ;
2010-08-11 10:07:43 -03:00
return key ;
2010-08-10 15:14:53 -03:00
}
2011-02-04 13:43:24 -02:00
int hist_entry__tui_annotate ( struct hist_entry * he , int evidx )
2011-02-04 09:45:46 -02:00
{
2011-02-04 13:43:24 -02:00
return symbol__tui_annotate ( he - > ms . sym , he - > ms . map , evidx ) ;
2011-02-04 09:45:46 -02:00
}
2011-02-04 13:43:24 -02:00
int symbol__tui_annotate ( struct symbol * sym , struct map * map , int evidx )
2010-08-10 14:54:09 -03:00
{
struct objdump_line * pos , * n ;
2010-08-09 15:30:40 -03:00
struct objdump_line_rb_node * rbpos ;
2011-02-08 13:27:39 -02:00
struct annotation * notes = symbol__annotation ( sym ) ;
2010-08-09 15:30:40 -03:00
struct annotate_browser browser = {
. b = {
2011-02-08 13:27:39 -02:00
. entries = & notes - > src - > source ,
2010-08-09 15:30:40 -03:00
. refresh = ui_browser__list_head_refresh ,
. seek = ui_browser__list_head_seek ,
. write = annotate_browser__write ,
2011-02-04 09:45:46 -02:00
. priv = sym ,
2010-08-09 15:30:40 -03:00
} ,
2010-08-10 14:54:09 -03:00
} ;
int ret ;
2011-02-04 09:45:46 -02:00
if ( sym = = NULL )
2010-08-10 14:54:09 -03:00
return - 1 ;
2011-02-04 09:45:46 -02:00
if ( map - > dso - > annotate_warned )
2010-08-10 14:54:09 -03:00
return - 1 ;
2011-02-08 13:27:39 -02:00
if ( symbol__annotate ( sym , map , sizeof ( * rbpos ) ) < 0 ) {
2010-08-10 15:58:50 -03:00
ui__error_window ( ui_helpline__last_msg ) ;
2010-08-10 14:54:09 -03:00
return - 1 ;
}
ui_helpline__push ( " Press <- or ESC to exit " ) ;
2011-02-08 13:27:39 -02:00
list_for_each_entry ( pos , & notes - > src - > source , node ) {
2010-08-10 14:54:09 -03:00
size_t line_len = strlen ( pos - > line ) ;
2010-08-09 15:30:40 -03:00
if ( browser . b . width < line_len )
browser . b . width = line_len ;
rbpos = objdump_line__rb ( pos ) ;
rbpos - > idx = browser . b . nr_entries + + ;
2011-02-08 13:27:39 -02:00
rbpos - > percent = objdump_line__calc_percent ( pos , sym , evidx ) ;
2010-08-09 15:30:40 -03:00
if ( rbpos - > percent < 0.01 )
continue ;
objdump__insert_line ( & browser . entries , rbpos ) ;
}
/*
* Position the browser at the hottest line .
*/
2010-08-10 15:14:53 -03:00
browser . curr_hot = rb_last ( & browser . entries ) ;
if ( browser . curr_hot )
annotate_browser__set_top ( & browser , browser . curr_hot ) ;
2010-08-10 14:54:09 -03:00
2010-08-09 15:30:40 -03:00
browser . b . width + = 18 ; /* Percentage */
2010-08-11 10:07:43 -03:00
ret = annotate_browser__run ( & browser ) ;
2011-02-08 13:27:39 -02:00
list_for_each_entry_safe ( pos , n , & notes - > src - > source , node ) {
2010-08-10 14:54:09 -03:00
list_del ( & pos - > node ) ;
objdump_line__free ( pos ) ;
}
return ret ;
}