ref: 02f047daee598f22e641365d01934973b14f89f3
dir: /b.c/
#include <u.h> #include <libc.h> #include <tos.h> #include "b.h" #define MAX(a,b) ((a)>(b)?(a):(b)) enum { Btime = 1000000000ULL/10ULL, Bstepmin = 100, }; static uvlong adj; uvlong cycles2ns(uvlong x) { uvlong div; /* this is ugly */ for(div = 1000000000ULL; 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", 1000000000ULL/(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; 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]); b->p96.ns = cycles2ns(b->c[b->ic*96 / 100]); b->p98.ns = cycles2ns(b->c[b->ic*98 / 100]); b->p99.ns = cycles2ns(b->c[b->ic*99 / 100]); } 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", "99%", "98%", "96%", "med", "avg", "min"}; static int w[] = {16, 8, 8, 8, 8, 8, 8, 8}; static int off[] = { 0, 0, offsetof(B, p99), offsetof(B, p98), offsetof(B, p96), offsetof(B, med), offsetof(B, avg), offsetof(B, min), }; char t[32], *s, *p; int i, j, n; 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++]) p[sprint(p, "%s", header[j])] = ' '; *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]; p[snprint(p, sizeof(t), "%σ ", &b[i])] = ' '; p += w[1]; for(j = 2; j < nelem(header); p += w[j], j++) p[sprint(p, "%τ ", *(Cns*)((char*)(b+i) + off[j]))] = ' '; *p = 0; fprint(fd, "%s\n", s); } }