#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); uvlongcycles2ns(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;} voidbenchprintgr(Bgr *gr, int fd){ fprint(fd, "%s\n", gr->name); benchprint(gr->b, gr->nb, fd);} voidbenchfreegr(Bgr *gr){ int i; for(i = 0; i < gr->nb; i++) free(gr->b[i]);} voidbseparator(int fd){ fprint(fd, "\n");} static intccmp(void *a, void *b){ u32int *x, *y; x = a; y = b; return *x < *y ? -1 : (*x > *y ? 1 : 0);} static voidbenchcalc(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]); }} voidbenchstep(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); } }} voidbenchprint(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); }} intbenchwire(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;}
#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;
}