166 lines
5.8 KiB
C
166 lines
5.8 KiB
C
/*
|
|
* histogram.h
|
|
*
|
|
* Created on: Sep 28, 2010
|
|
* Author: sears
|
|
*/
|
|
#ifndef HISTOGRAM_H_
|
|
#define HISTOGRAM_H_
|
|
|
|
#include <stasis/common.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
#include <stasis/util/log2.h>
|
|
#include <stasis/util/time.h>
|
|
|
|
/** @todo move to a .c */
|
|
static inline void stasis_histogram_thread_destroy(void * p) { free (p); }
|
|
|
|
#define DECLARE_HISTOGRAM_64(x) \
|
|
stasis_histogram_64_t x; \
|
|
extern void stasis_histogram_ctor_##x() __attribute__((constructor)); \
|
|
void stasis_histogram_ctor_##x(void) { stasis_histogram_64_clear(&x); \
|
|
pthread_key_create(&(x.tls), stasis_histogram_thread_destroy); \
|
|
stasis_auto_histogram_count++; \
|
|
stasis_auto_histograms = realloc(stasis_auto_histograms, sizeof(void*)*stasis_auto_histogram_count); \
|
|
stasis_auto_histogram_names = realloc(stasis_auto_histogram_names, sizeof(void*)*stasis_auto_histogram_count); \
|
|
stasis_auto_histograms[stasis_auto_histogram_count - 1] = &x; \
|
|
stasis_auto_histogram_names[stasis_auto_histogram_count - 1] = __FILE__":"#x; \
|
|
}
|
|
|
|
// extern void stasis_histogram_dtor_##x() __attribute__((destructor));
|
|
// void stasis_histogram_dtor_##x(void) { /*printf("%s: Histogram %s\n", __FILE__, #x);*/
|
|
// stasis_histogram_pretty_print_64(&x); }
|
|
|
|
typedef struct {
|
|
uint64_t buckets[64];
|
|
pthread_key_t tls;
|
|
} stasis_histogram_64_t;
|
|
|
|
extern stasis_histogram_64_t**stasis_auto_histograms;
|
|
extern char** stasis_auto_histogram_names;
|
|
extern int stasis_auto_histogram_count;
|
|
|
|
typedef struct {
|
|
uint64_t buckets[32];
|
|
pthread_key_t tls;
|
|
} stasis_histogram_32_t;
|
|
|
|
static inline void stasis_histogram_64_clear(stasis_histogram_64_t * hist) {
|
|
for(int i = 0; i < 64; i++) { hist->buckets[i] = 0; }
|
|
}
|
|
static inline void stasis_histogram_32_clear(stasis_histogram_32_t * hist) {
|
|
for(int i = 0; i < 32; i++) { hist->buckets[i] = 0; }
|
|
}
|
|
|
|
static inline void stasis_histogram_insert_log_uint64_t(stasis_histogram_64_t* hist, uint64_t val) {
|
|
hist->buckets[stasis_log_2_64(val)]++;
|
|
}
|
|
static inline void stasis_histogram_insert_log_uint32_t(stasis_histogram_32_t* hist, uint64_t val) {
|
|
hist->buckets[stasis_log_2_32(val)]++;
|
|
}
|
|
static inline void stasis_histogram_insert_log_timeval(stasis_histogram_64_t* hist, const struct timeval val) {
|
|
hist->buckets[stasis_log_2_timeval(val)]++;
|
|
}
|
|
|
|
static inline void stasis_histogram_tick(stasis_histogram_64_t* hist) {
|
|
struct timeval * val = pthread_getspecific(hist->tls);
|
|
if(!val) { val = malloc(sizeof(*val)); pthread_setspecific(hist->tls, val); }
|
|
gettimeofday(val,0);
|
|
}
|
|
static inline void stasis_histogram_tock(stasis_histogram_64_t* hist) {
|
|
struct timeval * val = pthread_getspecific(hist->tls);
|
|
assert(val);
|
|
struct timeval now;
|
|
gettimeofday(&now,0);
|
|
stasis_histogram_insert_log_timeval(hist, stasis_subtract_timeval(now, *val));
|
|
}
|
|
|
|
static inline uint64_t stasis_histogram_earth_movers_distance_64(stasis_histogram_64_t* a, stasis_histogram_64_t* b) {
|
|
double moved_so_far = 0.0;
|
|
double in_shovel = 0.0;
|
|
double a_mass = 0.0, b_mass = 0.0;
|
|
for(int i = 0; i < 64; i++) {
|
|
a_mass += ((double)a->buckets[i]);
|
|
b_mass += ((double)b->buckets[i]);
|
|
}
|
|
if(a_mass == 0.0 || b_mass == 0.0) { return (uint64_t)-1; }
|
|
for(int i = 0; i < 64; i++) {
|
|
in_shovel += (b_mass * (double)a->buckets[i]) - ((double)b->buckets[i]);
|
|
moved_so_far += (in_shovel >= 0 ? in_shovel : -in_shovel);
|
|
}
|
|
return moved_so_far / a_mass;
|
|
}
|
|
|
|
static inline uint64_t stasis_histogram_earth_movers_distance_32(stasis_histogram_32_t* a, stasis_histogram_32_t* b) {
|
|
double moved_so_far = 0.0;
|
|
double in_shovel = 0.0;
|
|
double a_mass = 0.0, b_mass = 0.0;
|
|
for(int i = 0; i < 32; i++) {
|
|
a_mass += ((double)stasis_log_2_64(a->buckets[i]));
|
|
b_mass += ((double)stasis_log_2_64(b->buckets[i]));
|
|
}
|
|
if(a_mass == 0.0 || b_mass == 0.0) { return (uint64_t)-1; }
|
|
for(int i = 0; i < 32; i++) {
|
|
in_shovel += (b_mass * (double)stasis_log_2_64(a->buckets[i])) - ((double)stasis_log_2_64(b->buckets[i]));
|
|
moved_so_far += (in_shovel >= 0 ? in_shovel : -in_shovel);
|
|
}
|
|
return moved_so_far / a_mass;
|
|
}
|
|
/** @todo move all of these to a .c */
|
|
static inline void stasis_histogram_pretty_print_64(stasis_histogram_64_t* a);
|
|
static inline void stasis_histogram_pretty_print_32(stasis_histogram_32_t* a);
|
|
void stasis_histograms_auto_dump(void);
|
|
|
|
void stasis_histogram_pretty_print_64(stasis_histogram_64_t* a) {
|
|
uint8_t logs[64];
|
|
int max_log = 0;
|
|
for(int i = 0; i < 64; i++) {
|
|
logs[i] = stasis_log_2_64(a->buckets[i]);
|
|
if(logs[i] > max_log) { max_log = logs[i]; }
|
|
}
|
|
for(int i = max_log; i > 0; i--) {
|
|
if(!(i % 10)) {
|
|
printf("2^%2d ", i);
|
|
} else {
|
|
printf(" ");
|
|
}
|
|
for(int j = 0; j < 64; j++) {
|
|
printf(logs[j] >= i ? "#" : " ");
|
|
}
|
|
printf("\n");
|
|
}
|
|
if(max_log == 0) {
|
|
printf("[empty]\n");
|
|
} else {
|
|
printf(" us ms s ks Ms\n");
|
|
}
|
|
}
|
|
void stasis_histogram_pretty_print_32(stasis_histogram_32_t* a) {
|
|
uint8_t logs[32];
|
|
int max_log = 0;
|
|
for(int i = 0; i < 32; i++) {
|
|
logs[i] = stasis_log_2_64(a->buckets[i]);
|
|
if(logs[i] > max_log) { max_log = logs[i]; }
|
|
}
|
|
for(int i = max_log; i >= 0; i--) {
|
|
if(!(i % 10)) {
|
|
printf("2^%2d ", i);
|
|
} else {
|
|
printf(" ");
|
|
}
|
|
for(int j = 0; j < 32; j++) {
|
|
printf(logs[j] >= i ? "#" : " ");
|
|
}
|
|
printf("\n");
|
|
}
|
|
if(max_log == 0) {
|
|
printf("[empty]\n");
|
|
} else {
|
|
//01234567890123456789012345678901234567890
|
|
printf(" us ms s ks Ms\n");
|
|
}
|
|
}
|
|
|
|
#endif /* HISTOGRAM_H_ */
|