ref: cce6dfb94a75af67751e2fab0d961a004e9e51d5
dir: /b.c/
#include <u.h>
#include <libc.h>
#include <tos.h>
#include "b.h"
#define MAX(a,b) ((a)>(b)?(a):(b))
enum {
OneS = 1000000000ULL,
Btime = OneS/10ULL,
Bstepmin = 100,
};
static uvlong adj;
uvlong
cycles2ns(uvlong x)
{
uvlong div;
/* this is ugly */
for(div = OneS; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL);
return x / (_tos->cyclefreq / div);
}
static int
σfmt(Fmt *f)
{
B *b;
b = va_arg(f->args, B*);
return fmtprint(f, "%zd", OneS/(b->tot.ns/b->ic));
}
static int
τfmt(Fmt *f)
{
Cns c;
c = va_arg(f->args, Cns);
return fmtprint(f, "%zd", c.ns);
}
void
benchinit(B *b, char *name)
{
int i;
fmtinstall(L'σ', σfmt);
fmtinstall(L'τ', τfmt);
memset(b, 0, sizeof(*b));
b->name = name;
b->n = b->nc = Bstepmin;
b->min.c--;
b->c = mallocz(b->nc * sizeof(*b->c), 1);
if(adj == 0){
uvlong v;
for(i = 0, v = 0; i < 100; i++){
uvlong s, e;
_tstart(&s);
_tend(&e);
v += e - s;
}
adj = v / i;
}
}
static int
ccmp(void *a, void *b)
{
u32int *x, *y;
x = a;
y = b;
return *x < *y ? -1 : (*x > *y ? 1 : 0);
}
static void
benchcalc(B *b)
{
uvlong m;
int i, n;
qsort(b->c, b->ic, sizeof(*b->c), ccmp);
if(b->ic & 1)
m = b->c[b->ic/2];
else
m = (b->c[b->ic/2-1] + b->c[b->ic/2])/2;
b->med.ns = cycles2ns(b->med.c = m);
b->avg.ns = cycles2ns(b->avg.c = b->tot.c / b->step);
b->min.ns = cycles2ns(b->min.c = b->c[0]);
b->max.ns = cycles2ns(b->max.c = b->c[b->ic-1]);
for(i = 1; i < 100; i++){
n = MAX(0, b->ic*i/100 - 1);
b->p[i].ns = cycles2ns(b->c[n]);
}
}
void
benchstep(B *b)
{
uvlong c;
if(b->step == 0)
b->t0 = b->tin;
b->step++;
b->n--;
if(b->tout <= b->tin)
sysfatal("%zd ≤ %zd → t₁ ≤ t₀", b->tout, b->tin);
if(b->tout - b->tin < adj) /* sometimes this happens */
adj = b->tout - b->tin;
c = b->tout - b->tin - adj;
if(b->ic >= b->nc){
b->nc *= 2;
b->c = realloc(b->c, b->nc * sizeof(*b->c));
memset(b->c+b->ic, 0, sizeof(*b->c)*(b->nc - b->ic));
}
b->c[b->ic++] = c;
b->tot.c += c;
b->tot.ns = cycles2ns(b->tot.c);
if(b->n == 0){
uvlong nsall = cycles2ns(b->tout - b->t0);
if(nsall < Btime)
b->n = (Btime - nsall) / (nsall / b->step);
if(b->n == 0){
benchcalc(b);
free(b->c);
}
}
}
void
benchprint(B *b, int nb, int fd)
{
static char *header[] = {" ", "op/s", "98%", "96%", "75%", "med", "avg", "min", "max"};
static int w[] = {16, 8, 8, 8, 8, 8, 8, 8, 8};
static int off[] = {
0,
0,
offsetof(B, p[99]),
offsetof(B, p[95]),
offsetof(B, p[75]),
offsetof(B, med),
offsetof(B, avg),
offsetof(B, min),
offsetof(B, max),
};
char t[64], *s, *p;
int i, j, n, x;
for(i = 0; i < nb; i++){
w[0] = MAX(w[0], snprint(t, sizeof(t), "%s ", b[i].name ? b[i].name : ""));
w[1] = MAX(w[1], snprint(t, sizeof(t), "%σ ", &b[i]));
for(j = 2; j < nelem(header); j++)
w[j] = MAX(w[j], snprint(t, sizeof(t), "%τ ", *(Cns*)((char*)(b+i) + off[j])));
}
for(j = n = 0; j < nelem(header); j++)
n += w[j];
s = malloc(n+1);
memset(s, ' ', n);
for(j = 0, p = s; j < nelem(header); p += w[j++]){
x = snprint(t, sizeof(t), "%s ", header[j]);
memmove(p+w[j]-x, t, x);
}
*p = 0;
fprint(fd, "%s\n", s);
for(i = 0; i < nb; i++){
memset(s, ' ', n);
p = s;
p[sprint(p, "%s ", b[i].name)] = ' ';
p += w[0];
x = snprint(t, sizeof(t), "%σ ", b+i);
memmove(p+w[1]-x, t, x);
p += w[1];
for(j = 2; j < nelem(header); p += w[j], j++){
x = snprint(t, sizeof(t), "%τ ", *(Cns*)((char*)(b+i) + off[j]));
memmove(p+w[j]-x, t, x);
}
*p = 0;
fprint(fd, "%s\n", s);
}
}