ref: bbdcad5c85ca1a0daa21bf1f8f70ea9394cb7a02
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; typedef struct Res { ulong ax, bx, cx, dx; }Res; Res cpuid(ulong ax, ulong cx); void _tstart(uvlong *c); void _tend(uvlong *c); void _tstartp(uvlong *c); void _tendp(uvlong *c); void (*tstart)(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(tstart == nil){ r = cpuid(0x80000001, 2); if((r.dx & (1<<27)) != 0){ tstart = _tstartp; tend = _tendp; }else{ tstart = _tstart; tend = _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); } }