summaryrefslogtreecommitdiff
path: root/sys/src/libdtracy/agg.c
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2018-12-08 15:07:53 +0000
committeraiju <devnull@localhost>2018-12-08 15:07:53 +0000
commit58fa29447b845f91dfc2a6734f525ed47375393b (patch)
treee2ee80e7728e26bc74e1f667ea48968b11a24fc6 /sys/src/libdtracy/agg.c
parent03e60450c2acc20866867cc5d3649aaed07d0326 (diff)
dtracy: add support for aggregations
Diffstat (limited to 'sys/src/libdtracy/agg.c')
-rw-r--r--sys/src/libdtracy/agg.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/sys/src/libdtracy/agg.c b/sys/src/libdtracy/agg.c
new file mode 100644
index 000000000..d374ed913
--- /dev/null
+++ b/sys/src/libdtracy/agg.c
@@ -0,0 +1,138 @@
+#include <u.h>
+#include <libc.h>
+#include <dtracy.h>
+
+int
+dtaunpackid(DTAgg *a)
+{
+ a->type = a->id >> 28 & 15;
+ a->keysize = a->id >> 13 & 0x7ff8;
+ switch(a->type){
+ case AGGCNT:
+ case AGGSUM:
+ case AGGMIN:
+ case AGGMAX:
+ a->recsize = 8 + a->keysize + 8;
+ return 0;
+ case AGGAVG:
+ a->recsize = 8 + a->keysize + 16;
+ return 0;
+ case AGGSTD:
+ a->recsize = 8 + a->keysize + 32;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+static u64int
+hash(uchar *s, int n, int m)
+{
+ u64int h;
+ int i;
+
+ h = 0xcbf29ce484222325ULL;
+ for(i = 0; i < n; i++){
+ h ^= s[i];
+ h *= 0x100000001b3ULL;
+ }
+ for(; i < m; i++)
+ h *= 0x100000001b3ULL;
+ return h;
+}
+
+static int
+keyeq(uchar *a, uchar *b, int n, int m)
+{
+ int i;
+
+ for(i = 0; i < n; i++)
+ if(a[i] != b[i])
+ return 0;
+ for(; i < m; i++)
+ if(a[i] != 0)
+ return 0;
+ return 1;
+}
+
+/* calculate v*v with 128 bits precision and add it to the 128-bit word at q */
+static void
+addsquare(u64int *q, s64int v)
+{
+ u32int v0;
+ s32int v1;
+ s64int s0, s1, s2;
+ u64int r;
+
+ v0 = v;
+ v1 = v>>32;
+ s0 = (s64int)v0 * (s64int)v0;
+ s1 = (s64int)v0 * (s64int)v1;
+ s2 = (s64int)v1 * (s64int)v1;
+ r = s0 + (s1<<33);
+ if(r < (u64int)s0) q[1]++;
+ q[0] += r;
+ if(q[0] < r) q[1]++;
+ q[1] += s2 + (s1>>31);
+}
+
+static void
+updaterecord(int type, u64int *q, s64int val)
+{
+ switch(type){
+ case AGGCNT: q[0] += 1; break;
+ case AGGSUM: q[0] += val; break;
+ case AGGAVG: q[0] += val; q[1]++; break;
+ case AGGMIN: if(val < q[0]) q[0] = val; break;
+ case AGGMAX: if(val > q[0]) q[0] = val; break;
+ case AGGSTD: q[0] += val; q[1]++; addsquare(&q[2], val); break;
+ }
+}
+
+static void
+createrecord(int type, u64int *q, s64int val)
+{
+ switch(type){
+ case AGGCNT: q[0] = 1; break;
+ case AGGSUM: case AGGMIN: case AGGMAX: q[0] = val; break;
+ case AGGAVG: q[0] = val; q[1] = 1; break;
+ case AGGSTD: q[0] = val; q[1] = 1; q[2] = 0; q[3] = 0; addsquare(&q[2], val); break;
+ }
+}
+
+/* runs in probe context */
+void
+dtarecord(DTChan *ch, int mach, DTAgg *a, uchar *key, int nkey, s64int val)
+{
+ u64int h;
+ u32int *p, *q;
+ DTBuf *c;
+
+ c = ch->aggwrbufs[mach];
+ h = hash(key, nkey, a->keysize);
+ p = (u32int*)(c->data + DTABUCKETS + (h % DTANUMBUCKETS) * 4);
+ while(*p != DTANIL){
+ assert((uint)*p < DTABUCKETS);
+ q = (u32int*)(c->data + *p);
+ if(q[1] == a->id && keyeq((uchar*)(q + 2), key, nkey, a->keysize) == 0){
+ updaterecord(a->type, (u64int*)(q + 2 + a->keysize / 4), val);
+ return;
+ }
+ p = q;
+ }
+ if(c->wr + a->recsize > DTABUCKETS)
+ return;
+ *p = c->wr;
+ q = (u32int*)(c->data + c->wr);
+ q[0] = DTANIL;
+ q[1] = a->id;
+ if(nkey == a->keysize)
+ memmove(&q[2], key, nkey);
+ else if(nkey > a->keysize){
+ memmove(&q[2], key, nkey);
+ memset((uchar*)q + 8 + nkey, 0, a->keysize - nkey);
+ }else
+ memmove(&q[2], key, a->keysize);
+ createrecord(a->type, (u64int*)(q + 2 + a->keysize / 4), val);
+ c->wr += a->recsize;
+}