2012-09-17 16:31:14 +08:00
# include <math.h>
# include "stat.h"
2015-06-26 11:29:16 +02:00
# include "evlist.h"
2015-06-04 15:50:55 +02:00
# include "evsel.h"
2015-06-26 11:29:16 +02:00
# include "thread_map.h"
2012-09-17 16:31:14 +08:00
void update_stats ( struct stats * stats , u64 val )
{
double delta ;
stats - > n + + ;
delta = val - stats - > mean ;
stats - > mean + = delta / stats - > n ;
stats - > M2 + = delta * ( val - stats - > mean ) ;
2013-08-02 14:05:40 -06:00
if ( val > stats - > max )
stats - > max = val ;
if ( val < stats - > min )
stats - > min = val ;
2012-09-17 16:31:14 +08:00
}
double avg_stats ( struct stats * stats )
{
return stats - > mean ;
}
/*
* http : //en.wikipedia.org/wiki/Algorithms_for_calculating_variance
*
* ( \ Sum n_i ^ 2 ) - ( ( \ Sum n_i ) ^ 2 ) / n
* s ^ 2 = - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* n - 1
*
* http : //en.wikipedia.org/wiki/Stddev
*
* The std dev of the mean is related to the std dev by :
*
* s
* s_mean = - - - - - - -
* sqrt ( n )
*
*/
double stddev_stats ( struct stats * stats )
{
double variance , variance_mean ;
2013-05-25 18:24:48 -06:00
if ( stats - > n < 2 )
2012-09-17 16:31:14 +08:00
return 0.0 ;
variance = stats - > M2 / ( stats - > n - 1 ) ;
variance_mean = variance / stats - > n ;
return sqrt ( variance_mean ) ;
}
double rel_stddev_stats ( double stddev , double avg )
{
double pct = 0.0 ;
if ( avg )
pct = 100.0 * stddev / avg ;
return pct ;
}
2015-06-04 15:50:55 +02:00
bool __perf_evsel_stat__is ( struct perf_evsel * evsel ,
enum perf_stat_evsel_id id )
{
2015-10-16 12:41:03 +02:00
struct perf_stat_evsel * ps = evsel - > priv ;
2015-06-04 15:50:55 +02:00
return ps - > id = = id ;
}
# define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name
static const char * id_str [ PERF_STAT_EVSEL_ID__MAX ] = {
2015-06-03 16:25:52 +02:00
ID ( NONE , x ) ,
ID ( CYCLES_IN_TX , cpu / cycles - t / ) ,
ID ( TRANSACTION_START , cpu / tx - start / ) ,
ID ( ELISION_START , cpu / el - start / ) ,
ID ( CYCLES_IN_TX_CP , cpu / cycles - ct / ) ,
2016-05-24 12:52:37 -07:00
ID ( TOPDOWN_TOTAL_SLOTS , topdown - total - slots ) ,
ID ( TOPDOWN_SLOTS_ISSUED , topdown - slots - issued ) ,
ID ( TOPDOWN_SLOTS_RETIRED , topdown - slots - retired ) ,
ID ( TOPDOWN_FETCH_BUBBLES , topdown - fetch - bubbles ) ,
ID ( TOPDOWN_RECOVERY_BUBBLES , topdown - recovery - bubbles ) ,
2015-06-04 15:50:55 +02:00
} ;
# undef ID
void perf_stat_evsel_id_init ( struct perf_evsel * evsel )
{
2015-10-16 12:41:03 +02:00
struct perf_stat_evsel * ps = evsel - > priv ;
2015-06-04 15:50:55 +02:00
int i ;
/* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
for ( i = 0 ; i < PERF_STAT_EVSEL_ID__MAX ; i + + ) {
if ( ! strcmp ( perf_evsel__name ( evsel ) , id_str [ i ] ) ) {
ps - > id = i ;
break ;
}
}
}
2015-06-14 10:19:26 +02:00
2016-01-20 12:56:35 +01:00
static void perf_evsel__reset_stat_priv ( struct perf_evsel * evsel )
2015-06-26 11:29:14 +02:00
{
int i ;
2015-10-16 12:41:03 +02:00
struct perf_stat_evsel * ps = evsel - > priv ;
2015-06-26 11:29:14 +02:00
for ( i = 0 ; i < 3 ; i + + )
init_stats ( & ps - > res_stats [ i ] ) ;
perf_stat_evsel_id_init ( evsel ) ;
}
2016-01-20 12:56:35 +01:00
static int perf_evsel__alloc_stat_priv ( struct perf_evsel * evsel )
2015-06-26 11:29:14 +02:00
{
2015-10-16 12:41:03 +02:00
evsel - > priv = zalloc ( sizeof ( struct perf_stat_evsel ) ) ;
2015-06-26 11:29:14 +02:00
if ( evsel - > priv = = NULL )
return - ENOMEM ;
perf_evsel__reset_stat_priv ( evsel ) ;
return 0 ;
}
2016-01-20 12:56:35 +01:00
static void perf_evsel__free_stat_priv ( struct perf_evsel * evsel )
2015-06-26 11:29:14 +02:00
{
zfree ( & evsel - > priv ) ;
}
2015-06-26 11:29:15 +02:00
2016-01-20 12:56:35 +01:00
static int perf_evsel__alloc_prev_raw_counts ( struct perf_evsel * evsel ,
int ncpus , int nthreads )
2015-06-26 11:29:15 +02:00
{
struct perf_counts * counts ;
counts = perf_counts__new ( ncpus , nthreads ) ;
if ( counts )
evsel - > prev_raw_counts = counts ;
return counts ? 0 : - ENOMEM ;
}
2016-01-20 12:56:35 +01:00
static void perf_evsel__free_prev_raw_counts ( struct perf_evsel * evsel )
2015-06-26 11:29:15 +02:00
{
perf_counts__delete ( evsel - > prev_raw_counts ) ;
evsel - > prev_raw_counts = NULL ;
}
2015-06-26 11:29:16 +02:00
2016-01-20 12:56:35 +01:00
static int perf_evsel__alloc_stats ( struct perf_evsel * evsel , bool alloc_raw )
2015-06-26 11:29:17 +02:00
{
int ncpus = perf_evsel__nr_cpus ( evsel ) ;
int nthreads = thread_map__nr ( evsel - > threads ) ;
if ( perf_evsel__alloc_stat_priv ( evsel ) < 0 | |
perf_evsel__alloc_counts ( evsel , ncpus , nthreads ) < 0 | |
( alloc_raw & & perf_evsel__alloc_prev_raw_counts ( evsel , ncpus , nthreads ) < 0 ) )
return - ENOMEM ;
return 0 ;
}
2015-06-26 11:29:16 +02:00
int perf_evlist__alloc_stats ( struct perf_evlist * evlist , bool alloc_raw )
{
struct perf_evsel * evsel ;
2016-06-23 11:26:15 -03:00
evlist__for_each_entry ( evlist , evsel ) {
2015-06-26 11:29:17 +02:00
if ( perf_evsel__alloc_stats ( evsel , alloc_raw ) )
2015-06-26 11:29:16 +02:00
goto out_free ;
}
return 0 ;
out_free :
perf_evlist__free_stats ( evlist ) ;
return - 1 ;
}
void perf_evlist__free_stats ( struct perf_evlist * evlist )
{
struct perf_evsel * evsel ;
2016-06-23 11:26:15 -03:00
evlist__for_each_entry ( evlist , evsel ) {
2015-06-26 11:29:16 +02:00
perf_evsel__free_stat_priv ( evsel ) ;
perf_evsel__free_counts ( evsel ) ;
perf_evsel__free_prev_raw_counts ( evsel ) ;
}
}
void perf_evlist__reset_stats ( struct perf_evlist * evlist )
{
struct perf_evsel * evsel ;
2016-06-23 11:26:15 -03:00
evlist__for_each_entry ( evlist , evsel ) {
2015-06-26 11:29:16 +02:00
perf_evsel__reset_stat_priv ( evsel ) ;
perf_evsel__reset_counts ( evsel ) ;
}
}
2015-07-21 14:31:27 +02:00
static void zero_per_pkg ( struct perf_evsel * counter )
{
if ( counter - > per_pkg_mask )
memset ( counter - > per_pkg_mask , 0 , MAX_NR_CPUS ) ;
}
2015-09-03 15:23:40 +02:00
static int check_per_pkg ( struct perf_evsel * counter ,
struct perf_counts_values * vals , int cpu , bool * skip )
2015-07-21 14:31:27 +02:00
{
unsigned long * mask = counter - > per_pkg_mask ;
struct cpu_map * cpus = perf_evsel__cpus ( counter ) ;
int s ;
* skip = false ;
if ( ! counter - > per_pkg )
return 0 ;
if ( cpu_map__empty ( cpus ) )
return 0 ;
if ( ! mask ) {
mask = zalloc ( MAX_NR_CPUS ) ;
if ( ! mask )
return - ENOMEM ;
counter - > per_pkg_mask = mask ;
}
2015-09-03 15:23:40 +02:00
/*
* we do not consider an event that has not run as a good
* instance to mark a package as used ( skip = 1 ) . Otherwise
* we may run into a situation where the first CPU in a package
* is not running anything , yet the second is , and this function
* would mark the package as used after the first CPU and would
* not read the values from the second CPU .
*/
if ( ! ( vals - > run & & vals - > ena ) )
return 0 ;
2015-10-16 12:41:15 +02:00
s = cpu_map__get_socket ( cpus , cpu , NULL ) ;
2015-07-21 14:31:27 +02:00
if ( s < 0 )
return - 1 ;
* skip = test_and_set_bit ( s , mask ) = = 1 ;
return 0 ;
}
static int
process_counter_values ( struct perf_stat_config * config , struct perf_evsel * evsel ,
int cpu , int thread ,
struct perf_counts_values * count )
{
struct perf_counts_values * aggr = & evsel - > counts - > aggr ;
static struct perf_counts_values zero ;
bool skip = false ;
2015-09-03 15:23:40 +02:00
if ( check_per_pkg ( evsel , count , cpu , & skip ) ) {
2015-07-21 14:31:27 +02:00
pr_err ( " failed to read per-pkg counter \n " ) ;
return - 1 ;
}
if ( skip )
count = & zero ;
switch ( config - > aggr_mode ) {
case AGGR_THREAD :
case AGGR_CORE :
case AGGR_SOCKET :
case AGGR_NONE :
if ( ! evsel - > snapshot )
perf_evsel__compute_deltas ( evsel , cpu , thread , count ) ;
perf_counts_values__scale ( count , config - > scale , NULL ) ;
if ( config - > aggr_mode = = AGGR_NONE )
perf_stat__update_shadow_stats ( evsel , count - > values , cpu ) ;
break ;
case AGGR_GLOBAL :
aggr - > val + = count - > val ;
if ( config - > scale ) {
aggr - > ena + = count - > ena ;
aggr - > run + = count - > run ;
}
2015-10-16 12:41:04 +02:00
case AGGR_UNSET :
2015-07-21 14:31:27 +02:00
default :
break ;
}
return 0 ;
}
static int process_counter_maps ( struct perf_stat_config * config ,
struct perf_evsel * counter )
{
int nthreads = thread_map__nr ( counter - > threads ) ;
int ncpus = perf_evsel__nr_cpus ( counter ) ;
int cpu , thread ;
if ( counter - > system_wide )
nthreads = 1 ;
for ( thread = 0 ; thread < nthreads ; thread + + ) {
for ( cpu = 0 ; cpu < ncpus ; cpu + + ) {
if ( process_counter_values ( config , counter , cpu , thread ,
perf_counts ( counter - > counts , cpu , thread ) ) )
return - 1 ;
}
}
return 0 ;
}
int perf_stat_process_counter ( struct perf_stat_config * config ,
struct perf_evsel * counter )
{
struct perf_counts_values * aggr = & counter - > counts - > aggr ;
2015-10-16 12:41:03 +02:00
struct perf_stat_evsel * ps = counter - > priv ;
2015-07-21 14:31:27 +02:00
u64 * count = counter - > counts - > aggr . values ;
2016-05-05 16:04:04 -07:00
u64 val ;
2015-07-21 14:31:27 +02:00
int i , ret ;
aggr - > val = aggr - > ena = aggr - > run = 0 ;
perf stat: Fix interval output values
We broke interval data displays with commit:
3f416f22d1e2 ("perf stat: Do not clean event's private stats")
This commit removed stats cleaning, which is important for '-r' option
to carry counters data over the whole run. But it's necessary to clean
it for interval mode, otherwise the displayed value is avg of all
previous values.
Before:
$ perf stat -e cycles -a -I 1000 record
# time counts unit events
1.000240796 75,216,287 cycles
2.000512791 107,823,524 cycles
$ perf stat report
# time counts unit events
1.000240796 75,216,287 cycles
2.000512791 91,519,906 cycles
Now:
$ perf stat report
# time counts unit events
1.000240796 75,216,287 cycles
2.000512791 107,823,524 cycles
Notice the second value being bigger (91,.. < 107,..).
This could be easily verified by using perf script which displays raw
stat data:
$ perf script
CPU THREAD VAL ENA RUN TIME EVENT
0 -1 23855779 1000209530 1000209530 1000240796 cycles
1 -1 33340397 1000224964 1000224964 1000240796 cycles
2 -1 15835415 1000226695 1000226695 1000240796 cycles
3 -1 2184696 1000228245 1000228245 1000240796 cycles
0 -1 97014312 2000514533 2000514533 2000512791 cycles
1 -1 46121497 2000543795 2000543795 2000512791 cycles
2 -1 32269530 2000543566 2000543566 2000512791 cycles
3 -1 7634472 2000544108 2000544108 2000512791 cycles
The sum of the first 4 values is the first interval aggregated value:
23855779 + 33340397 + 15835415 + 2184696 = 75,216,287
The sum of the second 4 values minus first value is the second interval
aggregated value:
97014312 + 46121497 + 32269530 + 7634472 - 75216287 = 107,823,524
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1454485436-20639-1-git-send-email-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-02-03 08:43:56 +01:00
/*
* We calculate counter ' s data every interval ,
* and the display code shows ps - > res_stats
* avg value . We need to zero the stats for
* interval mode , otherwise overall avg running
* averages will be shown for each interval .
*/
if ( config - > interval )
init_stats ( ps - > res_stats ) ;
2015-07-21 14:31:27 +02:00
if ( counter - > per_pkg )
zero_per_pkg ( counter ) ;
ret = process_counter_maps ( config , counter ) ;
if ( ret )
return ret ;
if ( config - > aggr_mode ! = AGGR_GLOBAL )
return 0 ;
if ( ! counter - > snapshot )
perf_evsel__compute_deltas ( counter , - 1 , - 1 , aggr ) ;
perf_counts_values__scale ( aggr , config - > scale , & counter - > counts - > scaled ) ;
for ( i = 0 ; i < 3 ; i + + )
update_stats ( & ps - > res_stats [ i ] , count [ i ] ) ;
if ( verbose ) {
fprintf ( config - > output , " %s: % " PRIu64 " % " PRIu64 " % " PRIu64 " \n " ,
perf_evsel__name ( counter ) , count [ 0 ] , count [ 1 ] , count [ 2 ] ) ;
}
/*
* Save the full runtime - to allow normalization during printout :
*/
2016-05-05 16:04:04 -07:00
val = counter - > scale * * count ;
perf_stat__update_shadow_stats ( counter , & val , 0 ) ;
2015-07-21 14:31:27 +02:00
return 0 ;
}
2015-10-25 15:51:32 +01:00
int perf_event__process_stat_event ( struct perf_tool * tool __maybe_unused ,
union perf_event * event ,
struct perf_session * session )
{
struct perf_counts_values count ;
struct stat_event * st = & event - > stat ;
struct perf_evsel * counter ;
count . val = st - > val ;
count . ena = st - > ena ;
count . run = st - > run ;
counter = perf_evlist__id2evsel ( session - > evlist , st - > id ) ;
if ( ! counter ) {
pr_err ( " Failed to resolve counter for stat event. \n " ) ;
return - EINVAL ;
}
* perf_counts ( counter - > counts , st - > cpu , st - > thread ) = count ;
counter - > supported = true ;
return 0 ;
}
2015-10-25 15:51:35 +01:00
size_t perf_event__fprintf_stat ( union perf_event * event , FILE * fp )
{
struct stat_event * st = ( struct stat_event * ) event ;
size_t ret ;
ret = fprintf ( fp , " \n ... id % " PRIu64 " , cpu %d, thread %d \n " ,
st - > id , st - > cpu , st - > thread ) ;
ret + = fprintf ( fp , " ... value % " PRIu64 " , enabled % " PRIu64 " , running % " PRIu64 " \n " ,
st - > val , st - > ena , st - > run ) ;
return ret ;
}
size_t perf_event__fprintf_stat_round ( union perf_event * event , FILE * fp )
{
struct stat_round_event * rd = ( struct stat_round_event * ) event ;
size_t ret ;
ret = fprintf ( fp , " \n ... time % " PRIu64 " , type %s \n " , rd - > time ,
rd - > type = = PERF_STAT_ROUND_TYPE__FINAL ? " FINAL " : " INTERVAL " ) ;
return ret ;
}
size_t perf_event__fprintf_stat_config ( union perf_event * event , FILE * fp )
{
struct perf_stat_config sc ;
size_t ret ;
perf_event__read_stat_config ( & sc , & event - > stat_config ) ;
ret = fprintf ( fp , " \n " ) ;
ret + = fprintf ( fp , " ... aggr_mode %d \n " , sc . aggr_mode ) ;
ret + = fprintf ( fp , " ... scale %d \n " , sc . scale ) ;
ret + = fprintf ( fp , " ... interval %u \n " , sc . interval ) ;
return ret ;
}