ref: 03bf5f5359c5a4919b97bc5f7843341f4a43f42d
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 _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); } B * 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; } 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.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->n < 1) return; 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); } } 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; }