#include "mem_config.h"
#include <inttypes.h>
#include "ms_stats.h"
#define array_size(x) (sizeof(x) / sizeof((x)[0]))
static
int
ms_local_log2(uint64_t value);
static
uint64_t ms_get_events(ms_stat_t *stat);
static
int
ms_local_log2(uint64_t value)
{
int
result= 0;
while
(result <= 63 && ((uint64_t)1 << result) < value)
{
result++;
}
return
result;
}
void
ms_init_stats(ms_stat_t *stat,
const
char
*name)
{
memset
(stat, 0,
sizeof
(*stat));
stat->name= (
char
*)name;
stat->min_time= (uint64_t)-1;
stat->max_time= 0;
stat->period_min_time= (uint64_t)-1;
stat->period_max_time= 0;
stat->log_product= 0;
stat->total_time= 0;
stat->pre_total_time= 0;
stat->squares= 0;
stat->pre_squares= 0;
stat->pre_events= 0;
stat->pre_log_product= 0;
stat->get_miss= 0;
stat->pre_get_miss= 0;
}
void
ms_record_event(ms_stat_t *stat, uint64_t total_time,
int
get_miss)
{
stat->total_time+= total_time;
if
(total_time < stat->min_time)
{
stat->min_time= total_time;
}
if
(total_time > stat->max_time)
{
stat->max_time= total_time;
}
if
(total_time < stat->period_min_time)
{
stat->period_min_time= total_time;
}
if
(total_time > stat->period_max_time)
{
stat->period_max_time= total_time;
}
if
(get_miss)
{
stat->get_miss++;
}
stat->dist[ms_local_log2(total_time)]++;
stat->squares+= (
double
)(total_time * total_time);
if
(total_time != 0)
{
stat->log_product+=
log
((
double
)total_time);
}
}
static
uint64_t ms_get_events(ms_stat_t *stat)
{
uint64_t events= 0;
for
(uint32_t i= 0; i < array_size(stat->dist); i++)
{
events+= stat->dist[i];
}
return
events;
}
void
ms_dump_stats(ms_stat_t *stat)
{
uint64_t events= 0;
int
max_non_zero= 0;
int
min_non_zero= 0;
double
average= 0;
for
(uint32_t i= 0; i < array_size(stat->dist); i++)
{
events+= stat->dist[i];
if
(stat->dist[i] != 0)
{
max_non_zero= (
int
)i;
}
}
if
(events == 0)
{
return
;
}
average= (
double
)(stat->total_time / events);
printf
(
"%s Statistics (%lld events)\n"
, stat->name, (
long
long
)events);
printf
(
" Min: %8lld\n"
, (
long
long
)stat->min_time);
printf
(
" Max: %8lld\n"
, (
long
long
)stat->max_time);
printf
(
" Avg: %8lld\n"
, (
long
long
)(stat->total_time / events));
printf
(
" Geo: %8.2lf\n"
,
exp
(stat->log_product / (
double
)events));
if
(events > 1)
{
printf
(
" Std: %8.2lf\n"
,
sqrt
((stat->squares - (
double
)events * average
* average) / ((
double
)events - 1)));
}
printf
(
" Log2 Dist:"
);
for
(
int
i= 0; i <= max_non_zero - 4; i+= 4)
{
if
((stat->dist[i + 0] != 0)
|| (stat->dist[i + 1] != 0)
|| (stat->dist[i + 2] != 0)
|| (stat->dist[i + 3] != 0))
{
min_non_zero= i;
break
;
}
}
for
(
int
i= min_non_zero; i <= max_non_zero; i++)
{
if
((i % 4) == 0)
{
printf
(
"\n %2d:"
, (
int
)i);
}
printf
(
" %6"
PRIu64 , stat->dist[i]);
}
printf
(
"\n\n"
);
}
void
ms_dump_format_stats(ms_stat_t *stat,
int
run_time,
int
freq,
int
obj_size)
{
uint64_t events= 0;
double
global_average= 0;
uint64_t global_tps= 0;
double
global_rate= 0;
double
global_std= 0;
double
global_log= 0;
double
period_average= 0;
uint64_t period_tps= 0;
double
period_rate= 0;
double
period_std= 0;
double
period_log= 0;
if
((events= ms_get_events(stat)) == 0)
{
return
;
}
global_average= (
double
)(stat->total_time / events);
global_tps= events / (uint64_t)run_time;
global_rate= (
double
)events * obj_size / 1024 / 1024 / run_time;
global_std=
sqrt
((stat->squares - (
double
)events * global_average
* global_average) / (
double
)(events - 1));
global_log=
exp
(stat->log_product / (
double
)events);
uint64_t diff_time= stat->total_time - stat->pre_total_time;
uint64_t diff_events= events - stat->pre_events;
if
(diff_events >= 1)
{
period_average= (
double
)(diff_time / diff_events);
period_tps= diff_events / (uint64_t)freq;
period_rate= (
double
)diff_events * obj_size / 1024 / 1024 / freq;
double
diff_squares= (
double
)stat->squares - (
double
)stat->pre_squares;
period_std=
sqrt
((diff_squares - (
double
)diff_events * period_average
* period_average) / (
double
)(diff_events - 1));
double
diff_log_product= stat->log_product - stat->pre_log_product;
period_log=
exp
(diff_log_product / (
double
)diff_events);
}
printf
(
"%s Statistics\n"
, stat->name);
printf
(
"%-8s %-8s %-12s %-12s %-10s %-10s %-8s %-10s %-10s %-10s %-10s\n"
,
"Type"
,
"Time(s)"
,
"Ops"
,
"TPS(ops/s)"
,
"Net(M/s)"
,
"Get_miss"
,
"Min(us)"
,
"Max(us)"
,
"Avg(us)"
,
"Std_dev"
,
"Geo_dist"
);
printf
(
"%-8s %-8d %-12llu %-12lld %-10.1f %-10lld %-8lld %-10lld %-10lld %-10.2f %.2f\n"
,
"Period"
,
freq,
(
long
long
)diff_events,
(
long
long
)period_tps,
global_rate,
(
long
long
)(stat->get_miss - stat->pre_get_miss),
(
long
long
)stat->period_min_time,
(
long
long
)stat->period_max_time,
(
long
long
)period_average,
period_std,
period_log);
printf
(
"%-8s %-8d %-12llu %-12lld %-10.1f %-10lld %-8lld %-10lld %-10lld %-10.2f %.2f\n\n"
,
"Global"
,
run_time,
(
long
long
)events,
(
long
long
)global_tps,
period_rate,
(
long
long
)stat->get_miss,
(
long
long
)stat->min_time,
(
long
long
)stat->max_time,
(
long
long
)global_average,
global_std,
global_log);
stat->pre_events= events;
stat->pre_squares= (uint64_t)stat->squares;
stat->pre_total_time= stat->total_time;
stat->pre_log_product= stat->log_product;
stat->period_min_time= (uint64_t)-1;
stat->period_max_time= 0;
stat->pre_get_miss= stat->get_miss;
}