]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/dtracy/agg.c
fix filetype detecton by suffix so that multiple dots dont confuse it. (thanks kvik)
[plan9front.git] / sys / src / cmd / dtracy / agg.c
1 #include <u.h>
2 #include <libc.h>
3 #include <dtracy.h>
4 #include <bio.h>
5 #include <avl.h>
6 #include <mp.h>
7 #include "dat.h"
8 #include "fns.h"
9
10 typedef struct ANode ANode;
11
12 struct ANode {
13         Avl;
14         s64int val, cnt;
15         u64int sq[2];
16         int keysize;
17         uchar key[1];
18 };
19
20 Agg *aggs;
21 static Avltree **trees;
22 static ANode *key;
23 int interrupted;
24
25 static int
26 aggcmp(Avl *ap, Avl *bp)
27 {
28         ANode *a, *b;
29         
30         a = (ANode *) ap;
31         b = (ANode *) bp;
32         return memcmp(a->key, b->key, a->keysize);
33 }
34
35 static void
36 createrecord(int type, ANode *n, s64int *q)
37 {
38         switch(type){
39         case AGGCNT: n->cnt = q[0]; break;
40         case AGGSUM: case AGGMIN: case AGGMAX: n->val = q[0]; break;
41         case AGGAVG: n->cnt = q[1]; n->val = q[0]; break;
42         case AGGSTD: n->cnt = q[1]; n->val = q[0]; n->sq[0] = q[2]; n->sq[1] = q[3]; break;
43         default: abort();
44         }
45 }
46
47 static void
48 updaterecord(int type, ANode *n, s64int *q)
49 {
50         u64int r;
51
52         switch(type){
53         case AGGCNT: n->cnt += q[0]; break;
54         case AGGSUM: n->val += q[0]; break;
55         case AGGAVG: n->cnt += q[1]; n->val += q[0]; break;
56         case AGGSTD:
57                 n->cnt += q[1];
58                 n->val += q[0];
59                 r = n->sq[0] + q[2];
60                 if(r < q[2]) n->sq[1]++;
61                 n->sq[0] = r;
62                 n->sq[1] += q[3];
63                 break;
64         default: abort();
65         }
66 }
67
68
69 int
70 aggparsebuf(uchar *p, int n)
71 {
72         uchar *e;
73         Agg *a;
74         u32int id;
75         Avltree *tp;
76         ANode *np;
77         
78         e = p + n;
79         for(; p + 8 < e; p += a->recsize){
80                 id = *(u32int*)&p[4];
81                 if((u16int)id >= aggid){
82                 inval:
83                         fprint(2, "invalid record in aggregation buffer\n");
84                         return -1;
85                 }
86                 a = &aggs[(u16int)id];
87                 if(a->type != id>>28) goto inval;
88                 if(a->keysize != (id>>13&0x7ff8)) goto inval;
89                 if(p + a->recsize > e) goto inval;
90                 tp = trees[(u16int)id];
91                 key->keysize = a->keysize;
92                 memcpy(key->key, &p[8], a->keysize);
93                 np = (ANode *) avllookup(tp, key, 0);
94                 if(np == nil){
95                         np = emalloc(sizeof(ANode) - 1 + a->keysize);
96                         *np = *key;
97                         createrecord(a->type, np, (s64int*)&p[8+a->keysize]);
98                         avlinsert(tp, np);
99                 }else
100                         updaterecord(a->type, np, (s64int*)&p[8+a->keysize]);
101         }
102         return 0;
103 }
104
105 void
106 agginit(void)
107 {
108         int i, m;
109         
110         trees = emalloc(sizeof(Avltree *) * aggid);
111         m = 0;
112         for(i = 0; i < aggid; i++){
113                 trees[i] = avlcreate(aggcmp);
114                 if(aggs[i].keysize > m)
115                         m = aggs[i].keysize;
116         }
117         key = emalloc(sizeof(ANode) - 1 + m);
118 }
119
120 int
121 aggnote(void *, char *note)
122 {
123         if(strcmp(note, "interrupt") != 0 || interrupted)
124                 return 0;
125         interrupted = 1;
126         return 1;
127 }
128
129 void
130 aggkeyprint(Fmt *f, Agg *, ANode *a)
131 {
132         fmtprint(f, "%20lld ", *(u64int*)a->key);
133 }
134
135 static double
136 variance(ANode *a)
137 {
138         mpint *x, *y, *z;
139         double r;
140         
141         x = vtomp(a->val, nil);
142         y = uvtomp(a->sq[0], nil);
143         z = vtomp(a->sq[1], nil);
144         mpleft(z, 64, z);
145         mpadd(z, y, y);
146         vtomp(a->cnt, z);
147         mpmul(x, x, x);
148         mpmul(y, z, y);
149         mpsub(y, x, x);
150         r = mptod(x) / a->cnt;
151         mpfree(x);
152         mpfree(y);
153         mpfree(z);
154         return r;
155 }
156
157 void
158 aggvalprint(Fmt *f, int type, ANode *a)
159 {
160         double x, s;
161
162         switch(type){
163         case AGGCNT: fmtprint(f, "%20lld", a->cnt); break;
164         case AGGSUM: case AGGMIN: case AGGMAX: fmtprint(f, "%20lld", a->val); break;
165         case AGGAVG: fmtprint(f, "%20g", (double)a->val / a->cnt); break;
166         case AGGSTD:
167                 x = (double)a->val / a->cnt;
168                 s = variance(a);
169                 if(s < 0)
170                         fmtprint(f, "%20g %20s", x, "NaN");
171                 else{
172                         fmtprint(f, "%20g %20g", x, sqrt(s));
173                 }
174                 break;
175         default:
176                 abort();
177         }
178 }
179
180 void
181 aggdump(void)
182 {
183         Fmt f;
184         char buf[8192];
185         int i;
186         ANode *a;
187         
188         fmtfdinit(&f, 1, buf, sizeof(buf));
189         for(i = 0; i < aggid; i++){
190                 a = (ANode *) avlmin(trees[i]);
191                 for(; a != nil; a = (ANode *) avlnext(a)){
192                         fmtprint(&f, "%s\t", aggs[i].name);
193                         aggkeyprint(&f, &aggs[i], a);
194                         aggvalprint(&f, aggs[i].type, a);
195                         fmtprint(&f, "\n");
196                 }
197         }
198         fmtfdflush(&f);
199 }