139 lines
2.8 KiB
C
139 lines
2.8 KiB
C
#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;
|
|
}
|