2012-09-03 06:53:06 +04:00
# include <math.h>
# include "../util/hist.h"
# include "../util/util.h"
# include "../util/sort.h"
2013-01-22 13:09:34 +04:00
# include "../util/evsel.h"
2012-09-03 06:53:06 +04:00
/* hist period print (hpp) functions */
2013-01-22 13:09:34 +04:00
typedef int ( * hpp_snprint_fn ) ( char * buf , size_t size , const char * fmt , . . . ) ;
2012-09-03 06:53:06 +04:00
2013-02-04 16:32:55 +04:00
static int __hpp__fmt ( struct perf_hpp * hpp , struct hist_entry * he ,
u64 ( * get_field ) ( struct hist_entry * ) ,
const char * fmt , hpp_snprint_fn print_fn ,
bool fmt_percent )
2012-09-03 06:53:06 +04:00
{
2013-01-22 13:09:34 +04:00
int ret ;
2012-10-04 16:49:40 +04:00
struct hists * hists = he - > hists ;
2012-09-03 06:53:06 +04:00
2013-02-04 16:32:55 +04:00
if ( fmt_percent ) {
double percent = 0.0 ;
2012-09-03 06:53:07 +04:00
2013-02-04 16:32:55 +04:00
if ( hists - > stats . total_period )
percent = 100.0 * get_field ( he ) /
hists - > stats . total_period ;
ret = print_fn ( hpp - > buf , hpp - > size , fmt , percent ) ;
} else
ret = print_fn ( hpp - > buf , hpp - > size , fmt , get_field ( he ) ) ;
2013-01-22 13:09:37 +04:00
if ( symbol_conf . event_group ) {
int prev_idx , idx_delta ;
struct perf_evsel * evsel = hists_to_evsel ( hists ) ;
struct hist_entry * pair ;
int nr_members = evsel - > nr_members ;
if ( nr_members < = 1 )
return ret ;
prev_idx = perf_evsel__group_idx ( evsel ) ;
list_for_each_entry ( pair , & he - > pairs . head , pairs . node ) {
u64 period = get_field ( pair ) ;
u64 total = pair - > hists - > stats . total_period ;
if ( ! total )
continue ;
evsel = hists_to_evsel ( pair - > hists ) ;
idx_delta = perf_evsel__group_idx ( evsel ) - prev_idx - 1 ;
while ( idx_delta - - ) {
/*
* zero - fill group members in the middle which
* have no sample
*/
ret + = print_fn ( hpp - > buf + ret , hpp - > size - ret ,
2013-02-04 16:32:55 +04:00
fmt , 0 ) ;
2013-01-22 13:09:37 +04:00
}
2013-02-04 16:32:55 +04:00
if ( fmt_percent )
ret + = print_fn ( hpp - > buf + ret , hpp - > size - ret ,
fmt , 100.0 * period / total ) ;
else
ret + = print_fn ( hpp - > buf + ret , hpp - > size - ret ,
fmt , period ) ;
2013-01-22 13:09:37 +04:00
prev_idx = perf_evsel__group_idx ( evsel ) ;
}
idx_delta = nr_members - prev_idx - 1 ;
while ( idx_delta - - ) {
/*
* zero - fill group members at last which have no sample
*/
ret + = print_fn ( hpp - > buf + ret , hpp - > size - ret ,
2013-02-04 16:32:55 +04:00
fmt , 0 ) ;
2013-01-22 13:09:37 +04:00
}
}
2013-01-22 13:09:34 +04:00
return ret ;
2012-09-03 06:53:06 +04:00
}
2013-01-22 13:09:34 +04:00
# define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
static int hpp__header_ # # _type ( struct perf_hpp * hpp ) \
{ \
int len = _min_width ; \
\
2013-01-22 13:09:37 +04:00
if ( symbol_conf . event_group ) { \
struct perf_evsel * evsel = hpp - > ptr ; \
\
len = max ( len , evsel - > nr_members * _unit_width ) ; \
} \
2013-01-22 13:09:34 +04:00
return scnprintf ( hpp - > buf , hpp - > size , " %*s " , len , _str ) ; \
2012-09-03 06:53:06 +04:00
}
2013-01-22 13:09:34 +04:00
# define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
static int hpp__width_ # # _type ( struct perf_hpp * hpp __maybe_unused ) \
{ \
int len = _min_width ; \
\
2013-01-22 13:09:37 +04:00
if ( symbol_conf . event_group ) { \
struct perf_evsel * evsel = hpp - > ptr ; \
\
len = max ( len , evsel - > nr_members * _unit_width ) ; \
} \
2013-01-22 13:09:34 +04:00
return len ; \
2012-09-03 06:53:06 +04:00
}
2013-01-22 13:09:34 +04:00
# define __HPP_COLOR_PERCENT_FN(_type, _field) \
static u64 he_get_ # # _field ( struct hist_entry * he ) \
{ \
return he - > stat . _field ; \
} \
\
static int hpp__color_ # # _type ( struct perf_hpp * hpp , struct hist_entry * he ) \
{ \
2013-02-04 16:32:55 +04:00
return __hpp__fmt ( hpp , he , he_get_ # # _field , " %6.2f%% " , \
( hpp_snprint_fn ) percent_color_snprintf , true ) ; \
2012-09-03 06:53:06 +04:00
}
2013-01-22 13:09:34 +04:00
# define __HPP_ENTRY_PERCENT_FN(_type, _field) \
static int hpp__entry_ # # _type ( struct perf_hpp * hpp , struct hist_entry * he ) \
{ \
const char * fmt = symbol_conf . field_sep ? " %.2f " : " %6.2f%% " ; \
2013-02-04 16:32:55 +04:00
return __hpp__fmt ( hpp , he , he_get_ # # _field , fmt , \
scnprintf , true ) ; \
2012-09-03 06:53:06 +04:00
}
2013-01-22 13:09:34 +04:00
# define __HPP_ENTRY_RAW_FN(_type, _field) \
static u64 he_get_raw_ # # _field ( struct hist_entry * he ) \
{ \
return he - > stat . _field ; \
} \
\
static int hpp__entry_ # # _type ( struct perf_hpp * hpp , struct hist_entry * he ) \
{ \
const char * fmt = symbol_conf . field_sep ? " % " PRIu64 : " %11 " PRIu64 ; \
2013-02-04 16:32:55 +04:00
return __hpp__fmt ( hpp , he , he_get_raw_ # # _field , fmt , scnprintf , false ) ; \
2012-09-03 06:53:06 +04:00
}
2013-01-22 13:09:34 +04:00
# define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
__HPP_HEADER_FN ( _type , _str , _min_width , _unit_width ) \
__HPP_WIDTH_FN ( _type , _min_width , _unit_width ) \
__HPP_COLOR_PERCENT_FN ( _type , _field ) \
__HPP_ENTRY_PERCENT_FN ( _type , _field )
2012-09-03 06:53:06 +04:00
2013-01-22 13:09:34 +04:00
# define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
__HPP_HEADER_FN ( _type , _str , _min_width , _unit_width ) \
__HPP_WIDTH_FN ( _type , _min_width , _unit_width ) \
__HPP_ENTRY_RAW_FN ( _type , _field )
2012-09-03 06:53:06 +04:00
2012-10-04 16:49:40 +04:00
2013-01-22 13:09:34 +04:00
HPP_PERCENT_FNS ( overhead , " Overhead " , period , 8 , 8 )
HPP_PERCENT_FNS ( overhead_sys , " sys " , period_sys , 8 , 8 )
HPP_PERCENT_FNS ( overhead_us , " usr " , period_us , 8 , 8 )
HPP_PERCENT_FNS ( overhead_guest_sys , " guest sys " , period_guest_sys , 9 , 8 )
HPP_PERCENT_FNS ( overhead_guest_us , " guest usr " , period_guest_us , 9 , 8 )
2012-09-03 06:53:06 +04:00
2013-01-22 13:09:34 +04:00
HPP_RAW_FNS ( samples , " Samples " , nr_events , 12 , 12 )
HPP_RAW_FNS ( period , " Period " , period , 12 , 12 )
2012-09-03 06:53:07 +04:00
2012-09-03 06:53:06 +04:00
2012-10-04 16:49:37 +04:00
static int hpp__header_baseline ( struct perf_hpp * hpp )
{
return scnprintf ( hpp - > buf , hpp - > size , " Baseline " ) ;
}
static int hpp__width_baseline ( struct perf_hpp * hpp __maybe_unused )
{
return 8 ;
}
static double baseline_percent ( struct hist_entry * he )
{
2012-10-25 20:42:45 +04:00
struct hist_entry * pair = hist_entry__next_pair ( he ) ;
2012-10-04 16:49:37 +04:00
struct hists * pair_hists = pair ? pair - > hists : NULL ;
double percent = 0.0 ;
if ( pair ) {
u64 total_period = pair_hists - > stats . total_period ;
2012-10-04 16:49:41 +04:00
u64 base_period = pair - > stat . period ;
2012-10-04 16:49:37 +04:00
percent = 100.0 * base_period / total_period ;
}
return percent ;
}
static int hpp__color_baseline ( struct perf_hpp * hpp , struct hist_entry * he )
{
double percent = baseline_percent ( he ) ;
2013-01-22 13:09:34 +04:00
if ( hist_entry__has_pairs ( he ) | | symbol_conf . field_sep )
2012-10-05 18:44:47 +04:00
return percent_color_snprintf ( hpp - > buf , hpp - > size , " %6.2f%% " , percent ) ;
else
return scnprintf ( hpp - > buf , hpp - > size , " " ) ;
2012-10-04 16:49:37 +04:00
}
static int hpp__entry_baseline ( struct perf_hpp * hpp , struct hist_entry * he )
{
double percent = baseline_percent ( he ) ;
const char * fmt = symbol_conf . field_sep ? " %.2f " : " %6.2f%% " ;
2012-10-25 20:42:45 +04:00
if ( hist_entry__has_pairs ( he ) | | symbol_conf . field_sep )
2012-10-05 18:44:47 +04:00
return scnprintf ( hpp - > buf , hpp - > size , fmt , percent ) ;
else
return scnprintf ( hpp - > buf , hpp - > size , " " ) ;
2012-10-04 16:49:37 +04:00
}
2012-10-05 18:44:44 +04:00
static int hpp__header_period_baseline ( struct perf_hpp * hpp )
{
const char * fmt = symbol_conf . field_sep ? " %s " : " %12s " ;
return scnprintf ( hpp - > buf , hpp - > size , fmt , " Period Base " ) ;
}
static int hpp__width_period_baseline ( struct perf_hpp * hpp __maybe_unused )
{
return 12 ;
}
static int hpp__entry_period_baseline ( struct perf_hpp * hpp , struct hist_entry * he )
{
2012-10-25 20:42:45 +04:00
struct hist_entry * pair = hist_entry__next_pair ( he ) ;
2012-10-05 18:44:44 +04:00
u64 period = pair ? pair - > stat . period : 0 ;
const char * fmt = symbol_conf . field_sep ? " % " PRIu64 : " %12 " PRIu64 ;
return scnprintf ( hpp - > buf , hpp - > size , fmt , period ) ;
}
2013-01-22 13:09:34 +04:00
2012-09-03 06:53:06 +04:00
static int hpp__header_delta ( struct perf_hpp * hpp )
{
2012-09-03 06:53:07 +04:00
const char * fmt = symbol_conf . field_sep ? " %s " : " %7s " ;
return scnprintf ( hpp - > buf , hpp - > size , fmt , " Delta " ) ;
2012-09-03 06:53:06 +04:00
}
2012-09-11 02:15:03 +04:00
static int hpp__width_delta ( struct perf_hpp * hpp __maybe_unused )
2012-09-03 06:53:06 +04:00
{
return 7 ;
}
static int hpp__entry_delta ( struct perf_hpp * hpp , struct hist_entry * he )
{
2012-11-28 17:52:40 +04:00
struct hist_entry * pair = hist_entry__next_pair ( he ) ;
2012-09-03 06:53:07 +04:00
const char * fmt = symbol_conf . field_sep ? " %s " : " %7.7s " ;
char buf [ 32 ] = " " ;
2012-11-28 17:52:40 +04:00
double diff = 0.0 ;
2012-09-03 06:53:06 +04:00
2012-11-28 17:52:40 +04:00
if ( pair ) {
if ( he - > diff . computed )
diff = he - > diff . period_ratio_delta ;
else
diff = perf_diff__compute_delta ( he , pair ) ;
} else
diff = perf_diff__period_percent ( he , he - > stat . period ) ;
2012-09-03 06:53:06 +04:00
2012-09-03 06:53:07 +04:00
if ( fabs ( diff ) > = 0.01 )
scnprintf ( buf , sizeof ( buf ) , " %+4.2F%% " , diff ) ;
2012-09-03 06:53:06 +04:00
2012-09-03 06:53:07 +04:00
return scnprintf ( hpp - > buf , hpp - > size , fmt , buf ) ;
2012-09-03 06:53:06 +04:00
}
2012-10-05 18:44:41 +04:00
static int hpp__header_ratio ( struct perf_hpp * hpp )
{
const char * fmt = symbol_conf . field_sep ? " %s " : " %14s " ;
return scnprintf ( hpp - > buf , hpp - > size , fmt , " Ratio " ) ;
}
static int hpp__width_ratio ( struct perf_hpp * hpp __maybe_unused )
{
return 14 ;
}
static int hpp__entry_ratio ( struct perf_hpp * hpp , struct hist_entry * he )
{
2012-11-28 17:52:40 +04:00
struct hist_entry * pair = hist_entry__next_pair ( he ) ;
2012-10-05 18:44:41 +04:00
const char * fmt = symbol_conf . field_sep ? " %s " : " %14s " ;
char buf [ 32 ] = " " ;
2012-11-28 17:52:40 +04:00
double ratio = 0.0 ;
2012-10-05 18:44:42 +04:00
2012-11-28 17:52:40 +04:00
if ( pair ) {
if ( he - > diff . computed )
ratio = he - > diff . period_ratio ;
else
ratio = perf_diff__compute_ratio ( he , pair ) ;
}
2012-10-05 18:44:41 +04:00
if ( ratio > 0.0 )
scnprintf ( buf , sizeof ( buf ) , " %+14.6F " , ratio ) ;
return scnprintf ( hpp - > buf , hpp - > size , fmt , buf ) ;
}
2012-10-05 18:44:43 +04:00
static int hpp__header_wdiff ( struct perf_hpp * hpp )
{
const char * fmt = symbol_conf . field_sep ? " %s " : " %14s " ;
return scnprintf ( hpp - > buf , hpp - > size , fmt , " Weighted diff " ) ;
}
static int hpp__width_wdiff ( struct perf_hpp * hpp __maybe_unused )
{
return 14 ;
}
static int hpp__entry_wdiff ( struct perf_hpp * hpp , struct hist_entry * he )
{
2012-11-28 17:52:40 +04:00
struct hist_entry * pair = hist_entry__next_pair ( he ) ;
2012-10-05 18:44:43 +04:00
const char * fmt = symbol_conf . field_sep ? " %s " : " %14s " ;
char buf [ 32 ] = " " ;
2012-11-28 17:52:40 +04:00
s64 wdiff = 0 ;
2012-10-05 18:44:43 +04:00
2012-11-28 17:52:40 +04:00
if ( pair ) {
if ( he - > diff . computed )
wdiff = he - > diff . wdiff ;
else
wdiff = perf_diff__compute_wdiff ( he , pair ) ;
}
2012-10-05 18:44:43 +04:00
if ( wdiff ! = 0 )
scnprintf ( buf , sizeof ( buf ) , " %14ld " , wdiff ) ;
return scnprintf ( hpp - > buf , hpp - > size , fmt , buf ) ;
}
2012-10-05 18:44:45 +04:00
static int hpp__header_formula ( struct perf_hpp * hpp )
{
const char * fmt = symbol_conf . field_sep ? " %s " : " %70s " ;
return scnprintf ( hpp - > buf , hpp - > size , fmt , " Formula " ) ;
}
static int hpp__width_formula ( struct perf_hpp * hpp __maybe_unused )
{
return 70 ;
}
static int hpp__entry_formula ( struct perf_hpp * hpp , struct hist_entry * he )
{
2012-11-28 17:52:41 +04:00
struct hist_entry * pair = hist_entry__next_pair ( he ) ;
2012-10-05 18:44:45 +04:00
const char * fmt = symbol_conf . field_sep ? " %s " : " %-70s " ;
char buf [ 96 ] = " " ;
2012-11-28 17:52:41 +04:00
if ( pair )
perf_diff__formula ( he , pair , buf , sizeof ( buf ) ) ;
2012-10-05 18:44:45 +04:00
return scnprintf ( hpp - > buf , hpp - > size , fmt , buf ) ;
}
2012-10-13 02:06:16 +04:00
# define HPP__COLOR_PRINT_FNS(_name) \
{ \
. header = hpp__header_ # # _name , \
. width = hpp__width_ # # _name , \
. color = hpp__color_ # # _name , \
. entry = hpp__entry_ # # _name \
}
2012-09-03 06:53:06 +04:00
2012-10-13 02:06:16 +04:00
# define HPP__PRINT_FNS(_name) \
{ \
. header = hpp__header_ # # _name , \
. width = hpp__width_ # # _name , \
. entry = hpp__entry_ # # _name \
}
2012-09-03 06:53:06 +04:00
struct perf_hpp_fmt perf_hpp__format [ ] = {
2012-10-13 02:06:16 +04:00
HPP__COLOR_PRINT_FNS ( baseline ) ,
HPP__COLOR_PRINT_FNS ( overhead ) ,
HPP__COLOR_PRINT_FNS ( overhead_sys ) ,
HPP__COLOR_PRINT_FNS ( overhead_us ) ,
HPP__COLOR_PRINT_FNS ( overhead_guest_sys ) ,
HPP__COLOR_PRINT_FNS ( overhead_guest_us ) ,
HPP__PRINT_FNS ( samples ) ,
HPP__PRINT_FNS ( period ) ,
HPP__PRINT_FNS ( period_baseline ) ,
HPP__PRINT_FNS ( delta ) ,
HPP__PRINT_FNS ( ratio ) ,
HPP__PRINT_FNS ( wdiff ) ,
HPP__PRINT_FNS ( formula )
2012-09-03 06:53:06 +04:00
} ;
2012-10-13 02:06:16 +04:00
LIST_HEAD ( perf_hpp__list ) ;
2013-01-22 13:09:34 +04:00
2012-09-03 06:53:06 +04:00
# undef HPP__COLOR_PRINT_FNS
# undef HPP__PRINT_FNS
2013-01-22 13:09:34 +04:00
# undef HPP_PERCENT_FNS
# undef HPP_RAW_FNS
# undef __HPP_HEADER_FN
# undef __HPP_WIDTH_FN
# undef __HPP_COLOR_PERCENT_FN
# undef __HPP_ENTRY_PERCENT_FN
# undef __HPP_ENTRY_RAW_FN
2012-10-04 16:49:39 +04:00
void perf_hpp__init ( void )
2012-09-03 06:53:06 +04:00
{
if ( symbol_conf . show_cpu_utilization ) {
2012-10-13 02:06:16 +04:00
perf_hpp__column_enable ( PERF_HPP__OVERHEAD_SYS ) ;
perf_hpp__column_enable ( PERF_HPP__OVERHEAD_US ) ;
2012-09-03 06:53:06 +04:00
if ( perf_guest ) {
2012-10-13 02:06:16 +04:00
perf_hpp__column_enable ( PERF_HPP__OVERHEAD_GUEST_SYS ) ;
perf_hpp__column_enable ( PERF_HPP__OVERHEAD_GUEST_US ) ;
2012-09-03 06:53:06 +04:00
}
}
if ( symbol_conf . show_nr_samples )
2012-10-13 02:06:16 +04:00
perf_hpp__column_enable ( PERF_HPP__SAMPLES ) ;
2012-09-03 06:53:06 +04:00
if ( symbol_conf . show_total_period )
2012-10-13 02:06:16 +04:00
perf_hpp__column_enable ( PERF_HPP__PERIOD ) ;
2012-10-04 16:49:39 +04:00
}
2012-09-03 06:53:06 +04:00
2012-10-13 02:06:16 +04:00
void perf_hpp__column_register ( struct perf_hpp_fmt * format )
{
list_add_tail ( & format - > list , & perf_hpp__list ) ;
}
void perf_hpp__column_enable ( unsigned col )
2012-10-04 16:49:39 +04:00
{
BUG_ON ( col > = PERF_HPP__MAX_INDEX ) ;
2012-10-13 02:06:16 +04:00
perf_hpp__column_register ( & perf_hpp__format [ col ] ) ;
2012-09-03 06:53:06 +04:00
}
static inline void advance_hpp ( struct perf_hpp * hpp , int inc )
{
hpp - > buf + = inc ;
hpp - > size - = inc ;
}
int hist_entry__period_snprintf ( struct perf_hpp * hpp , struct hist_entry * he ,
bool color )
{
const char * sep = symbol_conf . field_sep ;
2012-10-13 02:06:16 +04:00
struct perf_hpp_fmt * fmt ;
2012-09-03 06:53:06 +04:00
char * start = hpp - > buf ;
2012-10-13 02:06:16 +04:00
int ret ;
2012-10-04 16:49:37 +04:00
bool first = true ;
2012-09-03 06:53:06 +04:00
if ( symbol_conf . exclude_other & & ! he - > parent )
return 0 ;
2012-10-13 02:06:16 +04:00
perf_hpp__for_each_format ( fmt ) {
2012-10-21 00:14:10 +04:00
/*
* If there ' s no field_sep , we still need
* to display initial ' ' .
*/
2012-10-04 16:49:37 +04:00
if ( ! sep | | ! first ) {
2012-09-03 06:53:06 +04:00
ret = scnprintf ( hpp - > buf , hpp - > size , " %s " , sep ? : " " ) ;
advance_hpp ( hpp , ret ) ;
2012-10-21 00:14:10 +04:00
} else
2012-10-04 16:49:37 +04:00
first = false ;
2012-09-03 06:53:06 +04:00
2012-10-13 02:06:16 +04:00
if ( color & & fmt - > color )
ret = fmt - > color ( hpp , he ) ;
2012-09-03 06:53:06 +04:00
else
2012-10-13 02:06:16 +04:00
ret = fmt - > entry ( hpp , he ) ;
2012-09-03 06:53:06 +04:00
advance_hpp ( hpp , ret ) ;
}
return hpp - > buf - start ;
}
int hist_entry__sort_snprintf ( struct hist_entry * he , char * s , size_t size ,
struct hists * hists )
{
const char * sep = symbol_conf . field_sep ;
struct sort_entry * se ;
int ret = 0 ;
list_for_each_entry ( se , & hist_entry__sort_list , list ) {
if ( se - > elide )
continue ;
ret + = scnprintf ( s + ret , size - ret , " %s " , sep ? : " " ) ;
ret + = se - > se_snprintf ( he , s + ret , size - ret ,
hists__col_len ( hists , se - > se_width_idx ) ) ;
}
return ret ;
}
2012-09-03 06:53:08 +04:00
/*
* See hists__fprintf to match the column widths
*/
unsigned int hists__sort_list_width ( struct hists * hists )
{
2012-10-13 02:06:16 +04:00
struct perf_hpp_fmt * fmt ;
2012-09-03 06:53:08 +04:00
struct sort_entry * se ;
2012-10-13 02:06:16 +04:00
int i = 0 , ret = 0 ;
2013-01-22 13:09:37 +04:00
struct perf_hpp dummy_hpp = {
. ptr = hists_to_evsel ( hists ) ,
} ;
2012-09-03 06:53:08 +04:00
2012-10-13 02:06:16 +04:00
perf_hpp__for_each_format ( fmt ) {
2012-09-03 06:53:08 +04:00
if ( i )
ret + = 2 ;
2013-01-22 13:09:37 +04:00
ret + = fmt - > width ( & dummy_hpp ) ;
2012-09-03 06:53:08 +04:00
}
list_for_each_entry ( se , & hist_entry__sort_list , list )
if ( ! se - > elide )
ret + = 2 + hists__col_len ( hists , se - > se_width_idx ) ;
if ( verbose ) /* Addr + origin */
ret + = 3 + BITS_PER_LONG / 4 ;
return ret ;
}