plan9fox/sys/src/cmd/dtracy/agg.c
2018-12-08 15:07:53 +00:00

200 lines
3.5 KiB
C

#include <u.h>
#include <libc.h>
#include <dtracy.h>
#include <bio.h>
#include <avl.h>
#include <mp.h>
#include "dat.h"
#include "fns.h"
typedef struct ANode ANode;
struct ANode {
Avl;
s64int val, cnt;
u64int sq[2];
int keysize;
uchar key[1];
};
Agg *aggs;
static Avltree **trees;
static ANode *key;
int interrupted;
static int
aggcmp(Avl *ap, Avl *bp)
{
ANode *a, *b;
a = (ANode *) ap;
b = (ANode *) bp;
return memcmp(a->key, b->key, a->keysize);
}
static void
createrecord(int type, ANode *n, s64int *q)
{
switch(type){
case AGGCNT: n->cnt = q[0]; break;
case AGGSUM: case AGGMIN: case AGGMAX: n->val = q[0]; break;
case AGGAVG: n->cnt = q[1]; n->val = q[0]; break;
case AGGSTD: n->cnt = q[1]; n->val = q[0]; n->sq[0] = q[2]; n->sq[1] = q[3]; break;
default: abort();
}
}
static void
updaterecord(int type, ANode *n, s64int *q)
{
u64int r;
switch(type){
case AGGCNT: n->cnt += q[0]; break;
case AGGSUM: n->val += q[0]; break;
case AGGAVG: n->cnt += q[1]; n->val += q[0]; break;
case AGGSTD:
n->cnt += q[1];
n->val += q[0];
r = n->sq[0] + q[2];
if(r < q[2]) n->sq[1]++;
n->sq[0] = r;
n->sq[1] += q[3];
break;
default: abort();
}
}
int
aggparsebuf(uchar *p, int n)
{
uchar *e;
Agg *a;
u32int id;
Avltree *tp;
ANode *np;
e = p + n;
for(; p + 8 < e; p += a->recsize){
id = *(u32int*)&p[4];
if((u16int)id >= aggid){
inval:
fprint(2, "invalid record in aggregation buffer\n");
return -1;
}
a = &aggs[(u16int)id];
if(a->type != id>>28) goto inval;
if(a->keysize != (id>>13&0x7ff8)) goto inval;
if(p + a->recsize > e) goto inval;
tp = trees[(u16int)id];
key->keysize = a->keysize;
memcpy(key->key, &p[8], a->keysize);
np = (ANode *) avllookup(tp, key, 0);
if(np == nil){
np = emalloc(sizeof(ANode) - 1 + a->keysize);
*np = *key;
createrecord(a->type, np, (s64int*)&p[8+a->keysize]);
avlinsert(tp, np);
}else
updaterecord(a->type, np, (s64int*)&p[8+a->keysize]);
}
return 0;
}
void
agginit(void)
{
int i, m;
trees = emalloc(sizeof(Avltree *) * aggid);
m = 0;
for(i = 0; i < aggid; i++){
trees[i] = avlcreate(aggcmp);
if(aggs[i].keysize > m)
m = aggs[i].keysize;
}
key = emalloc(sizeof(ANode) - 1 + m);
}
int
aggnote(void *, char *note)
{
if(strcmp(note, "interrupt") != 0 || interrupted)
return 0;
interrupted = 1;
return 1;
}
void
aggkeyprint(Fmt *f, Agg *, ANode *a)
{
fmtprint(f, "%20lld ", *(u64int*)a->key);
}
static double
variance(ANode *a)
{
mpint *x, *y, *z;
double r;
x = vtomp(a->val, nil);
y = uvtomp(a->sq[0], nil);
z = vtomp(a->sq[1], nil);
mpleft(z, 64, z);
mpadd(z, y, y);
vtomp(a->cnt, z);
mpmul(x, x, x);
mpmul(y, z, y);
mpsub(y, x, x);
r = mptod(x) / a->cnt;
mpfree(x);
mpfree(y);
mpfree(z);
return r;
}
void
aggvalprint(Fmt *f, int type, ANode *a)
{
double x, s;
switch(type){
case AGGCNT: fmtprint(f, "%20lld", a->cnt); break;
case AGGSUM: case AGGMIN: case AGGMAX: fmtprint(f, "%20lld", a->val); break;
case AGGAVG: fmtprint(f, "%20g", (double)a->val / a->cnt); break;
case AGGSTD:
x = (double)a->val / a->cnt;
s = variance(a);
if(s < 0)
fmtprint(f, "%20g %20s", x, "NaN");
else{
fmtprint(f, "%20g %20g", x, sqrt(s));
}
break;
default:
abort();
}
}
void
aggdump(void)
{
Fmt f;
char buf[8192];
int i;
ANode *a;
fmtfdinit(&f, 1, buf, sizeof(buf));
for(i = 0; i < aggid; i++){
a = (ANode *) avlmin(trees[i]);
for(; a != nil; a = (ANode *) avlnext(a)){
fmtprint(&f, "%s\t", aggs[i].name);
aggkeyprint(&f, &aggs[i], a);
aggvalprint(&f, aggs[i].type, a);
fmtprint(&f, "\n");
}
}
fmtfdflush(&f);
}