shithub: bench9

ref: a7f13757d67c3169a938c95d2db667d1bd4ee407
dir: /b.c/

View raw version
#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;

typedef struct Res {
	ulong ax, bx, cx, dx;
}Res;

Res cpuid(ulong ax, ulong cx);

void _tend(uvlong *c);
void _tendp(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, "%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)
{
	Res r;
	int i;

	fmtinstall(L'σ', σfmt);
	fmtinstall(L'τ', τfmt);

	if(tend == nil){
		r = cpuid(0x80000001, 2);
		tend = (r.dx & (1<<27)) != 0 ? _tendp : _tend;
	}

	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);
	}
}