ref: 05188cb08b4304e34a7d822bb0f80ef5b780aa72
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;
#if defined(__386__) || defined(__amd64__)
typedef struct Res {
ulong ax, bx, cx, dx;
}Res;
Res cpuid(ulong ax, ulong cx);
void _tendp(uvlong *c);
#endif
void _tend(uvlong *c);
void (*tend)(uvlong *c);
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, "%ulld", OneS/(b->tot.ns/b->ic));
}
static int
τfmt(Fmt *f)
{
Cns c;
c = va_arg(f->args, Cns);
return fmtprint(f, "%ulld", c.ns);
}
B *
benchinit(B *b, char *name)
{
int i;
fmtinstall(L'σ', σfmt);
fmtinstall(L'τ', τfmt);
if(tend == nil){
tend = _tend;
#if defined(__386__) || defined(__amd64__)
Res r;
r = cpuid(0x80000001, 2);
if(r.dx & (1<<27))
tend = _tendp;
#endif
}
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;
}
return b;
}
B *
benchadd(Bgr *gr, char *name)
{
B **gb, *b;
if((gb = realloc(gr->b, (gr->nb+1)*sizeof(b))) == nil)
return nil;
gr->b = gb;
if((b = malloc(sizeof(*b)+strlen(name)+1)) == nil)
return nil;
gr->b[gr->nb++] = b;
return benchinit(b, strcpy((char*)(b+1), name));
}
Bgr *
benchinitgr(Bgr *gr, char *name)
{
gr->name = name;
gr->b = nil;
gr->nb = 0;
return gr;
}
void
benchprintgr(Bgr *gr, int fd)
{
fprint(fd, "%s\n", gr->name);
benchprint(gr->b, gr->nb, fd);
}
void
benchfreegr(Bgr *gr)
{
int i;
for(i = 0; i < gr->nb; i++)
free(gr->b[i]);
}
void
bseparator(int fd)
{
fprint(fd, "\n");
}
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.c = m;
b->med.ns = cycles2ns(b->med.c);
b->avg.c = b->tot.c / b->step;
b->avg.ns = cycles2ns(b->avg.c);
b->min.c = b->c[0];
b->min.ns = cycles2ns(b->min.c);
b->max.c = b->c[b->ic-1];
b->max.ns = cycles2ns(b->max.c);
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->n < 1 || b->tout <= b->tin)
return;
if(b->step == 0)
b->t0 = b->tin;
b->step++;
b->n--;
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);
}
}
int
benchwire(int cpu)
{
char t[64];
int r, f;
r = -1;
snprint(t, sizeof(t), "/proc/%d/ctl", getpid());
if((f = open(t, OWRITE)) >= 0){
if(fprint(f, "wired %d\n", cpu) >= 8)
r = 0;
close(f);
}
return r;
}