ref: 1046ee01c738fea18079cfbb2eb305b1e572b03b
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Tue Oct 27 20:04:40 EDT 2020
first
--- /dev/null
+++ b/b.c
@@ -1,0 +1,186 @@
+#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;
+ uvlong nsall;
+
+ b = va_arg(f->args, B*);
+ nsall = cycles2ns(b->tout - b->t0);
+
+ return fmtprint(f, "%zd", nsall/b->med.ns);
+}
+
+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);
+ }
+}
--- /dev/null
+++ b/b.h
@@ -1,0 +1,34 @@
+typedef struct B B;
+typedef struct Cns Cns;
+
+struct Cns {
+ uvlong c;
+ uvlong ns;
+};
+
+#pragma varargck type "σ" B*
+#pragma varargck type "τ" Cns
+
+struct B {
+ uvlong n;
+ uvlong tin;
+ uvlong tout;
+ uvlong step;
+ uvlong t0;
+ Cns tot, avg, med, min, max;
+ Cns p96, p98, p99;
+ u32int *c;
+ int nc, ic;
+ char *name;
+};
+
+/* private */
+void benchstep(B *b);
+void _tstart(uvlong *c);
+void _tend(uvlong *c);
+
+/* public */
+void benchinit(B *b, char *name);
+void benchprint(B *b, int nb, int fd);
+#define benchin(b) do{ _tstart(&(b)->tin); }while(0)
+#define benchout(b) do{ _tend(&(b)->tout); benchstep(b); }while(0)
--- /dev/null
+++ b/b_amd64.s
@@ -1,0 +1,13 @@
+TEXT _tstart(SB), 1, $0
+ LFENCE
+ RDTSC
+ MOVL AX, 0(RARG)
+ MOVL DX, 4(RARG)
+ RET
+
+TEXT _tend(SB), 1, $0
+ RDTSC
+ MOVL AX, 0(RARG)
+ MOVL DX, 4(RARG)
+ CPUID
+ RET
--- /dev/null
+++ b/main.c
@@ -1,0 +1,123 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "b.h"
+
+static void
+proc(void *)
+{
+ threadexits(nil);
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ B group[10], *b;
+ uchar d[1];
+ int f;
+
+ ARGBEGIN{
+ }ARGEND
+
+ b = &group[0];
+
+ f = open("/dev/null", OREAD);
+ benchinit(b, "read/1");
+ while(b->n > 0){
+ benchin(b);
+ read(f, d, 1);
+ benchout(b);
+ }
+
+ b++;
+ benchinit(b, "read/0");
+ while(b->n > 0){
+ benchin(b);
+ read(f, d, 0);
+ benchout(b);
+ }
+ close(f);
+
+ b++;
+ benchinit(b, "sin(n)");
+ while(b->n > 0){
+ benchin(b);
+ sin(b->n);
+ benchout(b);
+ }
+
+ b++;
+ benchinit(b, "cos(n)");
+ while(b->n > 0){
+ benchin(b);
+ cos(b->n);
+ benchout(b);
+ }
+
+ b++;
+ benchinit(b, "tan(n)");
+ while(b->n > 0){
+ benchin(b);
+ tan(b->n);
+ benchout(b);
+ }
+
+ b++;
+ benchinit(b, "sleep(0)");
+ while(b->n > 0){
+ benchin(b);
+ sleep(0);
+ benchout(b);
+ }
+
+ b++;
+ benchinit(b, "proccreate");
+ while(b->n > 0){
+ benchin(b);
+ proccreate(proc, (void*)b->n, 1024);
+ benchout(b);
+ }
+
+ b++;
+ benchinit(b, "memmove(4k)");
+ while(b->n > 0){
+ char *x, *y;
+ x = malloc(4096);
+ y = malloc(4096);
+ benchin(b);
+ memmove(x, y, 4096);
+ benchout(b);
+ free(x);
+ free(y);
+ }
+
+ b++;
+ benchinit(b, "memmove(64k)");
+ while(b->n > 0){
+ char *x, *y;
+ x = malloc(65536);
+ y = malloc(65536);
+ benchin(b);
+ memmove(x, y, 65536);
+ benchout(b);
+ free(x);
+ free(y);
+ }
+
+ b++;
+ benchinit(b, "memmove(256k)");
+ while(b->n > 0){
+ char *x, *y;
+ x = malloc(256*1024);
+ y = malloc(256*1024);
+ benchin(b);
+ memmove(x, y, 256*1024);
+ benchout(b);
+ free(x);
+ free(y);
+ }
+
+ benchprint(group, nelem(group), 1);
+
+ threadexitsall(nil);
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,16 @@
+</$objtype/mkfile
+
+TARG=bench9
+BIN=/$objtype/bin
+
+HFILES=\
+ b.h\
+
+OFILES=\
+ b.$O\
+ b_$objtype.$O\
+ main.$O\
+
+default:V: all
+
+</sys/src/cmd/mkone