2012-12-21 17:20:13 +09:00
# include "../evlist.h"
# include "../cache.h"
# include "../evsel.h"
# include "../sort.h"
# include "../hist.h"
# include "../helpline.h"
# include "gtk.h"
# define MAX_COLUMNS 32
2014-03-03 10:14:04 +09:00
static int __percent_color_snprintf ( struct perf_hpp * hpp , const char * fmt , . . . )
2013-01-22 18:09:36 +09:00
{
int ret = 0 ;
2014-07-31 14:47:36 +09:00
int len ;
2014-03-03 10:14:03 +09:00
va_list args ;
double percent ;
2013-01-22 18:09:36 +09:00
const char * markup ;
2014-03-03 10:14:04 +09:00
char * buf = hpp - > buf ;
size_t size = hpp - > size ;
2013-01-22 18:09:36 +09:00
2014-03-03 10:14:03 +09:00
va_start ( args , fmt ) ;
2014-07-31 14:47:36 +09:00
len = va_arg ( args , int ) ;
2014-03-03 10:14:03 +09:00
percent = va_arg ( args , double ) ;
va_end ( args ) ;
2013-01-22 18:09:36 +09:00
markup = perf_gtk__get_percent_color ( percent ) ;
if ( markup )
ret + = scnprintf ( buf , size , markup ) ;
2014-07-31 14:47:36 +09:00
ret + = scnprintf ( buf + ret , size - ret , fmt , len , percent ) ;
2013-01-22 18:09:36 +09:00
if ( markup )
ret + = scnprintf ( buf + ret , size - ret , " </span> " ) ;
return ret ;
}
# define __HPP_COLOR_PERCENT_FN(_type, _field) \
static u64 he_get_ # # _field ( struct hist_entry * he ) \
2012-12-21 17:20:13 +09:00
{ \
2013-01-22 18:09:36 +09:00
return he - > stat . _field ; \
} \
2012-12-21 17:20:13 +09:00
\
2014-07-31 14:47:38 +09:00
static int perf_gtk__hpp_color_ # # _type ( struct perf_hpp_fmt * fmt , \
2013-01-31 23:31:11 +01:00
struct perf_hpp * hpp , \
2013-01-22 18:09:36 +09:00
struct hist_entry * he ) \
{ \
2014-07-31 14:47:38 +09:00
return hpp__fmt ( fmt , hpp , he , he_get_ # # _field , " %*.2f%% " , \
__percent_color_snprintf , true ) ; \
2012-12-21 17:20:13 +09:00
}
2013-10-30 16:15:23 +09:00
# define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
static u64 he_get_acc_ # # _field ( struct hist_entry * he ) \
{ \
return he - > stat_acc - > _field ; \
} \
\
2016-03-22 13:09:37 -03:00
static int perf_gtk__hpp_color_ # # _type ( struct perf_hpp_fmt * fmt , \
2013-10-30 16:15:23 +09:00
struct perf_hpp * hpp , \
struct hist_entry * he ) \
{ \
2014-07-31 14:47:38 +09:00
return hpp__fmt_acc ( fmt , hpp , he , he_get_acc_ # # _field , " %*.2f%% " , \
__percent_color_snprintf , true ) ; \
2013-10-30 16:15:23 +09:00
}
2013-01-22 18:09:36 +09:00
__HPP_COLOR_PERCENT_FN ( overhead , period )
__HPP_COLOR_PERCENT_FN ( overhead_sys , period_sys )
__HPP_COLOR_PERCENT_FN ( overhead_us , period_us )
__HPP_COLOR_PERCENT_FN ( overhead_guest_sys , period_guest_sys )
__HPP_COLOR_PERCENT_FN ( overhead_guest_us , period_guest_us )
2013-10-30 16:15:23 +09:00
__HPP_COLOR_ACC_PERCENT_FN ( overhead_acc , period )
2012-12-21 17:20:13 +09:00
2013-01-22 18:09:36 +09:00
# undef __HPP_COLOR_PERCENT_FN
2012-12-21 17:20:13 +09:00
void perf_gtk__init_hpp ( void )
{
perf_hpp__format [ PERF_HPP__OVERHEAD ] . color =
perf_gtk__hpp_color_overhead ;
perf_hpp__format [ PERF_HPP__OVERHEAD_SYS ] . color =
perf_gtk__hpp_color_overhead_sys ;
perf_hpp__format [ PERF_HPP__OVERHEAD_US ] . color =
perf_gtk__hpp_color_overhead_us ;
perf_hpp__format [ PERF_HPP__OVERHEAD_GUEST_SYS ] . color =
perf_gtk__hpp_color_overhead_guest_sys ;
perf_hpp__format [ PERF_HPP__OVERHEAD_GUEST_US ] . color =
perf_gtk__hpp_color_overhead_guest_us ;
2013-10-30 16:15:23 +09:00
perf_hpp__format [ PERF_HPP__OVERHEAD_ACC ] . color =
perf_gtk__hpp_color_overhead_acc ;
2012-12-21 17:20:13 +09:00
}
2015-11-09 14:45:45 +09:00
static void perf_gtk__add_callchain_flat ( struct rb_root * root , GtkTreeStore * store ,
GtkTreeIter * parent , int col , u64 total )
{
struct rb_node * nd ;
bool has_single_node = ( rb_first ( root ) = = rb_last ( root ) ) ;
for ( nd = rb_first ( root ) ; nd ; nd = rb_next ( nd ) ) {
struct callchain_node * node ;
struct callchain_list * chain ;
GtkTreeIter iter , new_parent ;
bool need_new_parent ;
node = rb_entry ( nd , struct callchain_node , rb_node ) ;
new_parent = * parent ;
need_new_parent = ! has_single_node ;
callchain_node__make_parent_list ( node ) ;
list_for_each_entry ( chain , & node - > parent_val , list ) {
char buf [ 128 ] ;
gtk_tree_store_append ( store , & iter , & new_parent ) ;
callchain_node__scnprintf_value ( node , buf , sizeof ( buf ) , total ) ;
gtk_tree_store_set ( store , & iter , 0 , buf , - 1 ) ;
callchain_list__sym_name ( chain , buf , sizeof ( buf ) , false ) ;
gtk_tree_store_set ( store , & iter , col , buf , - 1 ) ;
if ( need_new_parent ) {
/*
* Only show the top - most symbol in a callchain
* if it ' s not the only callchain .
*/
new_parent = iter ;
need_new_parent = false ;
}
}
list_for_each_entry ( chain , & node - > val , list ) {
char buf [ 128 ] ;
gtk_tree_store_append ( store , & iter , & new_parent ) ;
callchain_node__scnprintf_value ( node , buf , sizeof ( buf ) , total ) ;
gtk_tree_store_set ( store , & iter , 0 , buf , - 1 ) ;
callchain_list__sym_name ( chain , buf , sizeof ( buf ) , false ) ;
gtk_tree_store_set ( store , & iter , col , buf , - 1 ) ;
if ( need_new_parent ) {
/*
* Only show the top - most symbol in a callchain
* if it ' s not the only callchain .
*/
new_parent = iter ;
need_new_parent = false ;
}
}
}
}
2015-11-09 14:45:46 +09:00
static void perf_gtk__add_callchain_folded ( struct rb_root * root , GtkTreeStore * store ,
GtkTreeIter * parent , int col , u64 total )
{
struct rb_node * nd ;
for ( nd = rb_first ( root ) ; nd ; nd = rb_next ( nd ) ) {
struct callchain_node * node ;
struct callchain_list * chain ;
GtkTreeIter iter ;
char buf [ 64 ] ;
char * str , * str_alloc = NULL ;
bool first = true ;
node = rb_entry ( nd , struct callchain_node , rb_node ) ;
callchain_node__make_parent_list ( node ) ;
list_for_each_entry ( chain , & node - > parent_val , list ) {
char name [ 1024 ] ;
callchain_list__sym_name ( chain , name , sizeof ( name ) , false ) ;
if ( asprintf ( & str , " %s%s%s " ,
first ? " " : str_alloc ,
first ? " " : symbol_conf . field_sep ? : " ; " ,
name ) < 0 )
return ;
first = false ;
free ( str_alloc ) ;
str_alloc = str ;
}
list_for_each_entry ( chain , & node - > val , list ) {
char name [ 1024 ] ;
callchain_list__sym_name ( chain , name , sizeof ( name ) , false ) ;
if ( asprintf ( & str , " %s%s%s " ,
first ? " " : str_alloc ,
first ? " " : symbol_conf . field_sep ? : " ; " ,
name ) < 0 )
return ;
first = false ;
free ( str_alloc ) ;
str_alloc = str ;
}
gtk_tree_store_append ( store , & iter , parent ) ;
callchain_node__scnprintf_value ( node , buf , sizeof ( buf ) , total ) ;
gtk_tree_store_set ( store , & iter , 0 , buf , - 1 ) ;
gtk_tree_store_set ( store , & iter , col , str , - 1 ) ;
free ( str_alloc ) ;
}
}
2015-11-09 14:45:45 +09:00
static void perf_gtk__add_callchain_graph ( struct rb_root * root , GtkTreeStore * store ,
GtkTreeIter * parent , int col , u64 total )
2013-06-04 18:22:13 +09:00
{
struct rb_node * nd ;
bool has_single_node = ( rb_first ( root ) = = rb_last ( root ) ) ;
for ( nd = rb_first ( root ) ; nd ; nd = rb_next ( nd ) ) {
struct callchain_node * node ;
struct callchain_list * chain ;
GtkTreeIter iter , new_parent ;
bool need_new_parent ;
2015-11-09 14:45:39 +09:00
u64 child_total ;
2013-06-04 18:22:13 +09:00
node = rb_entry ( nd , struct callchain_node , rb_node ) ;
new_parent = * parent ;
need_new_parent = ! has_single_node & & ( node - > val_nr > 1 ) ;
list_for_each_entry ( chain , & node - > val , list ) {
char buf [ 128 ] ;
gtk_tree_store_append ( store , & iter , & new_parent ) ;
2015-11-09 14:45:39 +09:00
callchain_node__scnprintf_value ( node , buf , sizeof ( buf ) , total ) ;
2013-06-04 18:22:14 +09:00
gtk_tree_store_set ( store , & iter , 0 , buf , - 1 ) ;
2014-11-12 18:05:23 -08:00
callchain_list__sym_name ( chain , buf , sizeof ( buf ) , false ) ;
2013-06-04 18:22:13 +09:00
gtk_tree_store_set ( store , & iter , col , buf , - 1 ) ;
if ( need_new_parent ) {
/*
* Only show the top - most symbol in a callchain
* if it ' s not the only callchain .
*/
new_parent = iter ;
need_new_parent = false ;
}
}
2013-06-04 18:22:14 +09:00
if ( callchain_param . mode = = CHAIN_GRAPH_REL )
child_total = node - > children_hit ;
else
child_total = total ;
2013-06-04 18:22:13 +09:00
/* Now 'iter' contains info of the last callchain_list */
2015-11-09 14:45:45 +09:00
perf_gtk__add_callchain_graph ( & node - > rb_root , store , & iter , col ,
child_total ) ;
2013-06-04 18:22:13 +09:00
}
}
2015-11-09 14:45:45 +09:00
static void perf_gtk__add_callchain ( struct rb_root * root , GtkTreeStore * store ,
GtkTreeIter * parent , int col , u64 total )
{
if ( callchain_param . mode = = CHAIN_FLAT )
perf_gtk__add_callchain_flat ( root , store , parent , col , total ) ;
2015-11-09 14:45:46 +09:00
else if ( callchain_param . mode = = CHAIN_FOLDED )
perf_gtk__add_callchain_folded ( root , store , parent , col , total ) ;
2015-11-09 14:45:45 +09:00
else
perf_gtk__add_callchain_graph ( root , store , parent , col , total ) ;
}
2013-06-04 18:22:16 +09:00
static void on_row_activated ( GtkTreeView * view , GtkTreePath * path ,
GtkTreeViewColumn * col __maybe_unused ,
gpointer user_data __maybe_unused )
{
bool expanded = gtk_tree_view_row_expanded ( view , path ) ;
if ( expanded )
gtk_tree_view_collapse_row ( view , path ) ;
else
gtk_tree_view_expand_row ( view , path , FALSE ) ;
}
2013-05-14 11:09:04 +09:00
static void perf_gtk__show_hists ( GtkWidget * window , struct hists * hists ,
float min_pcnt )
2012-12-21 17:20:13 +09:00
{
struct perf_hpp_fmt * fmt ;
GType col_types [ MAX_COLUMNS ] ;
GtkCellRenderer * renderer ;
2013-06-04 18:22:12 +09:00
GtkTreeStore * store ;
2012-12-21 17:20:13 +09:00
struct rb_node * nd ;
GtkWidget * view ;
int col_idx ;
2013-06-04 18:22:13 +09:00
int sym_col = - 1 ;
2012-12-21 17:20:13 +09:00
int nr_cols ;
char s [ 512 ] ;
struct perf_hpp hpp = {
. buf = s ,
. size = sizeof ( s ) ,
} ;
nr_cols = 0 ;
2016-01-18 10:24:23 +01:00
hists__for_each_format ( hists , fmt )
2012-12-21 17:20:13 +09:00
col_types [ nr_cols + + ] = G_TYPE_STRING ;
2013-06-04 18:22:12 +09:00
store = gtk_tree_store_newv ( nr_cols , col_types ) ;
2012-12-21 17:20:13 +09:00
view = gtk_tree_view_new ( ) ;
renderer = gtk_cell_renderer_text_new ( ) ;
col_idx = 0 ;
2016-01-18 10:24:23 +01:00
hists__for_each_format ( hists , fmt ) {
2015-12-23 02:07:08 +09:00
if ( perf_hpp__should_skip ( fmt , hists ) )
2014-03-18 13:00:59 +09:00
continue ;
2014-05-23 18:49:33 +09:00
/*
* XXX no way to determine where symcol column is . .
* Just use last column for now .
*/
if ( perf_hpp__is_sort_entry ( fmt ) )
sym_col = col_idx ;
2012-12-21 17:20:13 +09:00
gtk_tree_view_insert_column_with_attributes ( GTK_TREE_VIEW ( view ) ,
2014-07-31 14:47:40 +09:00
- 1 , fmt - > name ,
2012-12-21 17:20:13 +09:00
renderer , " markup " ,
col_idx + + , NULL ) ;
}
2013-06-04 18:22:15 +09:00
for ( col_idx = 0 ; col_idx < nr_cols ; col_idx + + ) {
2013-06-04 18:22:13 +09:00
GtkTreeViewColumn * column ;
2013-06-04 18:22:15 +09:00
column = gtk_tree_view_get_column ( GTK_TREE_VIEW ( view ) , col_idx ) ;
gtk_tree_view_column_set_resizable ( column , TRUE ) ;
if ( col_idx = = sym_col ) {
gtk_tree_view_set_expander_column ( GTK_TREE_VIEW ( view ) ,
column ) ;
}
2013-06-04 18:22:13 +09:00
}
2012-12-21 17:20:13 +09:00
gtk_tree_view_set_model ( GTK_TREE_VIEW ( view ) , GTK_TREE_MODEL ( store ) ) ;
g_object_unref ( GTK_TREE_MODEL ( store ) ) ;
for ( nd = rb_first ( & hists - > entries ) ; nd ; nd = rb_next ( nd ) ) {
struct hist_entry * h = rb_entry ( nd , struct hist_entry , rb_node ) ;
GtkTreeIter iter ;
2014-01-14 11:52:48 +09:00
u64 total = hists__total_period ( h - > hists ) ;
2013-10-31 10:17:39 +09:00
float percent ;
2012-12-21 17:20:13 +09:00
if ( h - > filtered )
continue ;
2013-10-31 10:17:39 +09:00
percent = hist_entry__get_percent_limit ( h ) ;
2013-05-14 11:09:04 +09:00
if ( percent < min_pcnt )
continue ;
2013-06-04 18:22:12 +09:00
gtk_tree_store_append ( store , & iter , NULL ) ;
2012-12-21 17:20:13 +09:00
col_idx = 0 ;
2016-01-18 10:24:23 +01:00
hists__for_each_format ( hists , fmt ) {
2015-12-23 02:07:08 +09:00
if ( perf_hpp__should_skip ( fmt , h - > hists ) )
2014-03-18 13:00:59 +09:00
continue ;
2012-12-21 17:20:13 +09:00
if ( fmt - > color )
2013-01-31 23:31:11 +01:00
fmt - > color ( fmt , & hpp , h ) ;
2012-12-21 17:20:13 +09:00
else
2013-01-31 23:31:11 +01:00
fmt - > entry ( fmt , & hpp , h ) ;
2012-12-21 17:20:13 +09:00
2013-06-04 18:22:12 +09:00
gtk_tree_store_set ( store , & iter , col_idx + + , s , - 1 ) ;
2012-12-21 17:20:13 +09:00
}
2016-05-03 13:54:44 +02:00
if ( symbol_conf . use_callchain & & hists__has ( hists , sym ) ) {
2013-06-04 18:22:14 +09:00
if ( callchain_param . mode = = CHAIN_GRAPH_REL )
2014-05-23 18:49:33 +09:00
total = symbol_conf . cumulate_callchain ?
h - > stat_acc - > period : h - > stat . period ;
2013-06-04 18:22:14 +09:00
2013-06-04 18:22:13 +09:00
perf_gtk__add_callchain ( & h - > sorted_chain , store , & iter ,
2013-06-04 18:22:14 +09:00
sym_col , total ) ;
2013-06-04 18:22:13 +09:00
}
2012-12-21 17:20:13 +09:00
}
2013-06-04 18:22:17 +09:00
gtk_tree_view_set_rules_hint ( GTK_TREE_VIEW ( view ) , TRUE ) ;
2013-06-04 18:22:16 +09:00
g_signal_connect ( view , " row-activated " ,
G_CALLBACK ( on_row_activated ) , NULL ) ;
2012-12-21 17:20:13 +09:00
gtk_container_add ( GTK_CONTAINER ( window ) , view ) ;
}
2016-02-25 00:13:47 +09:00
static void perf_gtk__add_hierarchy_entries ( struct hists * hists ,
struct rb_root * root ,
GtkTreeStore * store ,
GtkTreeIter * parent ,
struct perf_hpp * hpp ,
float min_pcnt )
{
int col_idx = 0 ;
struct rb_node * node ;
struct hist_entry * he ;
struct perf_hpp_fmt * fmt ;
2016-03-07 16:44:51 -03:00
struct perf_hpp_list_node * fmt_node ;
2016-02-25 00:13:47 +09:00
u64 total = hists__total_period ( hists ) ;
2016-03-07 16:44:51 -03:00
int size ;
2016-02-25 00:13:47 +09:00
for ( node = rb_first ( root ) ; node ; node = rb_next ( node ) ) {
GtkTreeIter iter ;
float percent ;
2016-03-07 16:44:46 -03:00
char * bf ;
2016-02-25 00:13:47 +09:00
he = rb_entry ( node , struct hist_entry , rb_node ) ;
if ( he - > filtered )
continue ;
percent = hist_entry__get_percent_limit ( he ) ;
if ( percent < min_pcnt )
continue ;
gtk_tree_store_append ( store , & iter , parent ) ;
col_idx = 0 ;
2016-03-07 16:44:51 -03:00
/* the first hpp_list_node is for overhead columns */
fmt_node = list_first_entry ( & hists - > hpp_formats ,
struct perf_hpp_list_node , list ) ;
perf_hpp_list__for_each_format ( & fmt_node - > hpp , fmt ) {
2016-02-25 00:13:47 +09:00
if ( fmt - > color )
fmt - > color ( fmt , hpp , he ) ;
else
fmt - > entry ( fmt , hpp , he ) ;
gtk_tree_store_set ( store , & iter , col_idx + + , hpp - > buf , - 1 ) ;
}
2016-03-07 16:44:46 -03:00
bf = hpp - > buf ;
2016-03-07 16:44:51 -03:00
size = hpp - > size ;
2016-03-07 16:44:46 -03:00
perf_hpp_list__for_each_format ( he - > hpp_list , fmt ) {
int ret ;
if ( fmt - > color )
ret = fmt - > color ( fmt , hpp , he ) ;
else
ret = fmt - > entry ( fmt , hpp , he ) ;
snprintf ( hpp - > buf + ret , hpp - > size - ret , " " ) ;
advance_hpp ( hpp , ret + 2 ) ;
}
2016-02-25 00:13:47 +09:00
2016-03-07 16:44:51 -03:00
gtk_tree_store_set ( store , & iter , col_idx , ltrim ( rtrim ( bf ) ) , - 1 ) ;
2016-02-25 00:13:47 +09:00
if ( ! he - > leaf ) {
2016-03-07 16:44:51 -03:00
hpp - > buf = bf ;
hpp - > size = size ;
2016-02-25 00:13:47 +09:00
perf_gtk__add_hierarchy_entries ( hists , & he - > hroot_out ,
store , & iter , hpp ,
min_pcnt ) ;
2016-02-26 21:13:20 +09:00
if ( ! hist_entry__has_hierarchy_children ( he , min_pcnt ) ) {
char buf [ 32 ] ;
GtkTreeIter child ;
snprintf ( buf , sizeof ( buf ) , " no entry >= %.2f%% " ,
min_pcnt ) ;
gtk_tree_store_append ( store , & child , & iter ) ;
gtk_tree_store_set ( store , & child , col_idx , buf , - 1 ) ;
}
2016-02-25 00:13:47 +09:00
}
if ( symbol_conf . use_callchain & & he - > leaf ) {
if ( callchain_param . mode = = CHAIN_GRAPH_REL )
total = symbol_conf . cumulate_callchain ?
he - > stat_acc - > period : he - > stat . period ;
perf_gtk__add_callchain ( & he - > sorted_chain , store , & iter ,
col_idx , total ) ;
}
}
}
static void perf_gtk__show_hierarchy ( GtkWidget * window , struct hists * hists ,
float min_pcnt )
{
struct perf_hpp_fmt * fmt ;
2016-03-07 16:44:51 -03:00
struct perf_hpp_list_node * fmt_node ;
2016-02-25 00:13:47 +09:00
GType col_types [ MAX_COLUMNS ] ;
GtkCellRenderer * renderer ;
GtkTreeStore * store ;
GtkWidget * view ;
int col_idx ;
int nr_cols = 0 ;
char s [ 512 ] ;
char buf [ 512 ] ;
2016-03-07 16:44:51 -03:00
bool first_node , first_col ;
2016-02-25 00:13:47 +09:00
struct perf_hpp hpp = {
. buf = s ,
. size = sizeof ( s ) ,
} ;
hists__for_each_format ( hists , fmt ) {
if ( perf_hpp__is_sort_entry ( fmt ) | |
perf_hpp__is_dynamic_entry ( fmt ) )
break ;
col_types [ nr_cols + + ] = G_TYPE_STRING ;
}
col_types [ nr_cols + + ] = G_TYPE_STRING ;
store = gtk_tree_store_newv ( nr_cols , col_types ) ;
view = gtk_tree_view_new ( ) ;
renderer = gtk_cell_renderer_text_new ( ) ;
col_idx = 0 ;
2016-03-07 16:44:51 -03:00
/* the first hpp_list_node is for overhead columns */
fmt_node = list_first_entry ( & hists - > hpp_formats ,
struct perf_hpp_list_node , list ) ;
perf_hpp_list__for_each_format ( & fmt_node - > hpp , fmt ) {
2016-02-25 00:13:47 +09:00
gtk_tree_view_insert_column_with_attributes ( GTK_TREE_VIEW ( view ) ,
- 1 , fmt - > name ,
renderer , " markup " ,
col_idx + + , NULL ) ;
}
/* construct merged column header since sort keys share single column */
buf [ 0 ] = ' \0 ' ;
2016-03-07 16:44:51 -03:00
first_node = true ;
list_for_each_entry_continue ( fmt_node , & hists - > hpp_formats , list ) {
if ( ! first_node )
2016-02-25 00:13:47 +09:00
strcat ( buf , " / " ) ;
2016-03-07 16:44:51 -03:00
first_node = false ;
2016-02-25 00:13:47 +09:00
2016-03-07 16:44:51 -03:00
first_col = true ;
perf_hpp_list__for_each_format ( & fmt_node - > hpp , fmt ) {
if ( perf_hpp__should_skip ( fmt , hists ) )
continue ;
if ( ! first_col )
strcat ( buf , " + " ) ;
first_col = false ;
2016-08-07 17:28:27 +02:00
fmt - > header ( fmt , & hpp , hists , 0 ) ;
2016-03-07 16:44:51 -03:00
strcat ( buf , ltrim ( rtrim ( hpp . buf ) ) ) ;
}
2016-02-25 00:13:47 +09:00
}
gtk_tree_view_insert_column_with_attributes ( GTK_TREE_VIEW ( view ) ,
- 1 , buf ,
renderer , " markup " ,
col_idx + + , NULL ) ;
for ( col_idx = 0 ; col_idx < nr_cols ; col_idx + + ) {
GtkTreeViewColumn * column ;
column = gtk_tree_view_get_column ( GTK_TREE_VIEW ( view ) , col_idx ) ;
gtk_tree_view_column_set_resizable ( column , TRUE ) ;
if ( col_idx = = 0 ) {
gtk_tree_view_set_expander_column ( GTK_TREE_VIEW ( view ) ,
column ) ;
}
}
gtk_tree_view_set_model ( GTK_TREE_VIEW ( view ) , GTK_TREE_MODEL ( store ) ) ;
g_object_unref ( GTK_TREE_MODEL ( store ) ) ;
perf_gtk__add_hierarchy_entries ( hists , & hists - > entries , store ,
NULL , & hpp , min_pcnt ) ;
gtk_tree_view_set_rules_hint ( GTK_TREE_VIEW ( view ) , TRUE ) ;
g_signal_connect ( view , " row-activated " ,
G_CALLBACK ( on_row_activated ) , NULL ) ;
gtk_container_add ( GTK_CONTAINER ( window ) , view ) ;
}
2012-12-21 17:20:13 +09:00
int perf_evlist__gtk_browse_hists ( struct perf_evlist * evlist ,
const char * help ,
2013-05-14 11:09:04 +09:00
struct hist_browser_timer * hbt __maybe_unused ,
float min_pcnt )
2012-12-21 17:20:13 +09:00
{
struct perf_evsel * pos ;
GtkWidget * vbox ;
GtkWidget * notebook ;
GtkWidget * info_bar ;
GtkWidget * statbar ;
GtkWidget * window ;
signal ( SIGSEGV , perf_gtk__signal ) ;
signal ( SIGFPE , perf_gtk__signal ) ;
signal ( SIGINT , perf_gtk__signal ) ;
signal ( SIGQUIT , perf_gtk__signal ) ;
signal ( SIGTERM , perf_gtk__signal ) ;
window = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
gtk_window_set_title ( GTK_WINDOW ( window ) , " perf report " ) ;
g_signal_connect ( window , " delete_event " , gtk_main_quit , NULL ) ;
pgctx = perf_gtk__activate_context ( window ) ;
if ( ! pgctx )
return - 1 ;
vbox = gtk_vbox_new ( FALSE , 0 ) ;
notebook = gtk_notebook_new ( ) ;
2012-12-21 17:20:14 +09:00
gtk_box_pack_start ( GTK_BOX ( vbox ) , notebook , TRUE , TRUE , 0 ) ;
info_bar = perf_gtk__setup_info_bar ( ) ;
if ( info_bar )
gtk_box_pack_start ( GTK_BOX ( vbox ) , info_bar , FALSE , FALSE , 0 ) ;
statbar = perf_gtk__setup_statusbar ( ) ;
gtk_box_pack_start ( GTK_BOX ( vbox ) , statbar , FALSE , FALSE , 0 ) ;
gtk_container_add ( GTK_CONTAINER ( window ) , vbox ) ;
2016-06-23 11:26:15 -03:00
evlist__for_each_entry ( evlist , pos ) {
2014-10-09 13:13:41 -03:00
struct hists * hists = evsel__hists ( pos ) ;
2012-12-21 17:20:13 +09:00
const char * evname = perf_evsel__name ( pos ) ;
GtkWidget * scrolled_window ;
GtkWidget * tab_label ;
2013-01-22 18:09:44 +09:00
char buf [ 512 ] ;
size_t size = sizeof ( buf ) ;
2012-12-21 17:20:13 +09:00
2013-01-22 18:09:44 +09:00
if ( symbol_conf . event_group ) {
if ( ! perf_evsel__is_group_leader ( pos ) )
continue ;
if ( pos - > nr_members > 1 ) {
perf_evsel__group_desc ( pos , buf , size ) ;
evname = buf ;
}
}
2013-01-22 18:09:43 +09:00
2012-12-21 17:20:13 +09:00
scrolled_window = gtk_scrolled_window_new ( NULL , NULL ) ;
gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW ( scrolled_window ) ,
GTK_POLICY_AUTOMATIC ,
GTK_POLICY_AUTOMATIC ) ;
2016-02-25 00:13:47 +09:00
if ( symbol_conf . report_hierarchy )
perf_gtk__show_hierarchy ( scrolled_window , hists , min_pcnt ) ;
else
perf_gtk__show_hists ( scrolled_window , hists , min_pcnt ) ;
2012-12-21 17:20:13 +09:00
tab_label = gtk_label_new ( evname ) ;
gtk_notebook_append_page ( GTK_NOTEBOOK ( notebook ) , scrolled_window , tab_label ) ;
}
gtk_widget_show_all ( window ) ;
perf_gtk__resize_window ( window ) ;
gtk_window_set_position ( GTK_WINDOW ( window ) , GTK_WIN_POS_CENTER ) ;
ui_helpline__push ( help ) ;
gtk_main ( ) ;
perf_gtk__deactivate_context ( & pgctx ) ;
return 0 ;
}