1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
/*
Copyright (C) 2022 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/
#include "stats.h"
#include "hash_table.h"
#include "xxmalloc.h"
#include <assert.h>
#include <inttypes.h>
#include <stdlib.h>
static struct hash_table *stats = NULL;
static int stats_enabled = 0;
typedef enum {
STATS_INT,
STATS_BIN,
} stats_type_t;
typedef struct {
stats_type_t type;
union {
int64_t value;
unsigned buckets[64];
} v;
} stats_t;
static void stats_init(void)
{
if (!stats) {
stats = hash_table_create(0, 0);
}
}
static stats_t *stats_touch(const char *name, stats_type_t type)
{
assert(name);
stats_init();
stats_t *s = hash_table_lookup(stats, name);
if (s) {
assert(s->type == type);
} else {
s = xxcalloc(1, sizeof(*s));
s->type = type;
int rc = hash_table_insert(stats, name, s);
assert(rc);
}
return s;
}
static size_t log2b(uint64_t n)
{
size_t i = 0;
while (n >>= 1)
++i;
return i;
}
void stats_enable()
{
stats_enabled = 1;
}
void stats_unset(const char *name)
{
if (!stats_enabled)
return;
assert(name);
stats_init();
free(hash_table_remove(stats, name));
}
void stats_set(const char *name, int64_t value)
{
if (!stats_enabled)
return;
stats_t *s = stats_touch(name, STATS_INT);
s->v.value = value;
}
void stats_inc(const char *name, int64_t offset)
{
if (!stats_enabled)
return;
stats_t *s = stats_touch(name, STATS_INT);
s->v.value += offset;
}
void stats_bin(const char *name, uint64_t value)
{
if (!stats_enabled)
return;
stats_t *s = stats_touch(name, STATS_BIN);
++s->v.buckets[log2b(value)];
}
struct jx *stats_get(void)
{
if (!stats_enabled)
return jx_null();
char *k;
stats_t *s;
struct jx *out = jx_object(NULL);
struct jx *log;
stats_init();
hash_table_firstkey(stats);
while (hash_table_nextkey(stats, &k, (void **)&s)) {
switch (s->type) {
case STATS_INT:
jx_insert_integer(out, k, s->v.value);
break;
case STATS_BIN:
log = jx_array(NULL);
for (size_t i = 0; i < 64; i++) {
jx_array_append(log, jx_integer(s->v.buckets[i]));
}
jx_insert(out, jx_string(k), log);
break;
}
}
return out;
}
/* vim: set noexpandtab tabstop=8: */
|