ref: 4cff2af5a4ff459f67aaa9cadf56913171891f95
author: Ori Bernstein <ori@eigenstate.org>
date: Sun May 26 18:25:29 EDT 2024
initial commit
--- /dev/null
+++ b/atomic.c
@@ -1,0 +1,81 @@
+#include <u.h>
+#include <libc.h>
+
+#include "../atomic.h"
+
+void
+test_aget(void)
+{
+ long lv = 42;
+ vlong vv = 42;
+ void *pv = &lv;
+
+ assert(agetl(&lv) == 42);
+ assert(agetv(&vv) == 42);
+ assert(agetp(&pv) == &lv);
+}
+
+void
+test_aset(void)
+{
+ long lv = 42;
+ vlong vv = 42;
+ void *pv = &lv;
+
+ assert(asetl(&lv, 43) == 42);
+ assert(asetv(&vv, 43) == 42);
+ assert(asetp(&pv, &vv) == &lv);
+
+ assert(lv == 43);
+ assert(vv == 43);
+ assert(pv == &vv);
+}
+
+void
+test_ainc(void)
+{
+ long lv = 42;
+ vlong vv = 42;
+
+ assert(aincl(&lv, 1) == 43);
+ assert(aincv(&vv, 1) == 43);
+ assert(lv == 43);
+ assert(vv == 43);
+}
+
+void
+test_acas(void)
+{
+ long lv = 42;
+ vlong vv = 42;
+ void *pv = &lv;
+
+ assert(!acasl(&lv, 1, 1));
+ assert(!acasv(&vv, 1, 1));
+ assert(!acasp(&pv, &vv, &pv));
+ assert(acasl(&lv, 42, 1));
+ assert(acasv(&vv, 42, 1));
+ assert(acasp(&pv, &lv, &vv));
+
+ assert(lv == 1);
+ assert(vv == 1);
+ assert(pv == &vv);
+}
+
+void
+test_coherence(void)
+{
+ /* at least not an illegal instruction */
+ coherence();
+}
+
+void
+main(int, char**)
+{
+ test_aget();
+ test_aset();
+ test_ainc();
+ test_acas();
+ test_coherence();
+ exits(nil);
+}
--- /dev/null
+++ b/basic.rc
@@ -1,0 +1,7 @@
+#!/bin/rc -e
+
+. common.rc
+
+setup
+echo hi > $fs/test
+assert ~ `{cat $fs/test} hi
--- /dev/null
+++ b/build.rc
@@ -1,0 +1,21 @@
+#!/bin/rc -e
+
+. common.rc
+
+setup
+
+cd $fs
+
+# we don't want to clobber the installed
+# libs with something corrupt, so copy
+# them in and bind them over.
+mkdir -p $cputype/lib
+dircp /$cputype/lib $cputype/lib
+bind $cputype/lib /$cputype/lib
+
+# clone our repo
+git/clone /dist/plan9front
+bind plan9front/sys/include /sys/include
+
+cd plan9front/sys/src
+mk all
--- /dev/null
+++ b/common.rc
@@ -1,0 +1,28 @@
+#!/bin/rc
+
+rfork ne
+
+srv=gefstest.$pid
+fs=/n/$srv
+
+fn setup{
+ if(! test -f test.fs){
+ dd -if /dev/zero -of test.fs -bs 1kk -count 2k
+ chmod +t test.fs
+ }
+ ../6.out -r -f test.fs
+ ../6.out -m 32 -Au glenda -f test.fs -n $srv
+ mount -c /srv/$srv $fs
+}
+
+fn assert {
+ st=$status
+ if(! ~ $#st 0){
+ echo $st >[1=2]
+ exit $st
+ }
+}
+
+fn sigexit{
+ unmount $fs
+}
--- /dev/null
+++ b/files.c
@@ -1,0 +1,30 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+void
+main(int argc, char **argv)
+{
+ char buf[128];
+ int i, fd;
+ vlong t, dtC, dtW, dtT;
+ Biobuf *f;
+
+ ARGBEGIN{}ARGEND;
+ if(argc == 0)
+ sysfatal("usage: %s dir", argv0);
+ f = Bfdopen(1, OWRITE);
+ for(i = 0; i < 1000*1000; i++){
+ t = nsec();
+ snprint(buf, sizeof(buf), "%s/f.%d", argv[0], i);
+ fd = create(buf, OREAD, 0666);
+ dtC = nsec() - t;
+ write(fd, "hi\n", 3);
+ dtW = nsec() - t;
+ close(fd);
+ dtT = nsec() - t;
+ Bprint(f, "%lld, %lld, %lld, %lld\n", t, dtC, dtW, dtT);
+ }
+ Bterm(f);
+ exits(nil);
+}
--- /dev/null
+++ b/freplay.c
@@ -1,0 +1,203 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+
+File* ctlfile;
+File* datfile;
+char* mountpt = "/mnt/replay";
+char* srvname = "replay";
+char* logfile;
+char* replayfile;
+char* membuf;
+vlong membufsz;
+vlong replaycount = -1;
+int logfd = -1;
+int replayfd = -1;
+vlong nwrites;
+
+void
+log1(int fd, void *buf, vlong off, vlong sz)
+{
+ char *p, hdr[12];
+
+ p = hdr;
+ PBIT64(p, off); p += 8;
+ PBIT32(p, sz);
+ if(write(fd, hdr, sizeof(hdr)) == -1)
+ sysfatal("write header: %r");
+ if(write(fd, buf, sz) == -1)
+ sysfatal("write data: %r\n");
+}
+
+int
+replay1(int fd)
+{
+ uchar *p, hdr[12];
+ vlong o;
+ int n, r;
+
+ r = readn(fd, hdr, 12);
+ if(r == 0)
+ return 0;
+ if(r != 12)
+ sysfatal("failed to read operation header: %r");
+
+ p = hdr;
+ o = GBIT64(p); p += 8;
+ n = GBIT32(p);
+ if(o + n > membufsz)
+ sysfatal("operation exceeds buffer size");
+ if(readn(fd, membuf + o, n) != n)
+ sysfatal("read op: %r");
+ nwrites++;
+ return 1;
+}
+
+void
+readmembuf(Req *r, void *s, vlong n)
+{
+ r->ofcall.count = r->ifcall.count;
+ if(r->ifcall.offset >= n){
+ r->ofcall.count = 0;
+ return;
+ }
+ if(r->ifcall.offset+r->ofcall.count > n)
+ r->ofcall.count = n - r->ifcall.offset;
+ memmove(r->ofcall.data, (char*)s+r->ifcall.offset, r->ofcall.count);
+}
+
+void
+fsread(Req *r)
+{
+ char buf[128];
+
+ if(r->fid->file == datfile){
+ readmembuf(r, membuf, membufsz);
+ respond(r, nil);
+ }else if(r->fid->file == ctlfile){
+ snprint(buf, sizeof(buf), "writes %lld\n", nwrites);
+ readstr(r, buf);
+ respond(r, nil);
+ }else
+ abort();
+}
+
+void
+fswrite(Req *r)
+{
+ if(r->fid->file == datfile){
+ if(logfile == nil){
+ respond(r, "read-only replay file: no log defined");
+ return;
+ }
+ if(r->ifcall.offset + r->ifcall.count > membufsz){
+ respond(r, "operation exceeds file size");
+ return;
+ }
+ log1(logfd, r->ifcall.data, r->ifcall.offset, r->ifcall.count);
+ memcpy(membuf + r->ifcall.offset, r->ifcall.data, r->ifcall.count);
+ r->ofcall.count = r->ifcall.count;
+ respond(r, nil);
+ nwrites++;
+ }else if(r->fid->file == ctlfile){
+ if(strncmp(r->ifcall.data, "exit", 4) == 0){
+ print("exiting...\n");
+ r->ofcall.count = r->ifcall.count;
+ respond(r, nil);
+ exits(nil);
+ }else if(strncmp(r->ifcall.data, "step", 4) == 0){
+ r->ofcall.count = r->ifcall.count;
+ if(replayfd == -1)
+ respond(r, "no active replay");
+ else if(!replay1(replayfd))
+ respond(r, "no replay left");
+ else
+ respond(r, nil);
+ }else
+ respond(r, "unknown ctl message");
+ }else
+ abort();
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-l log] [-r replay] [-c count] file\n", argv0);
+ exits("usage");
+}
+
+static Srv fs = {
+ .read = fsread,
+ .write = fswrite,
+};
+void
+main(int argc, char *argv[])
+{
+ int fd;
+ vlong n, off;
+ char *uid;
+ Dir *d;
+ int i;
+
+ ARGBEGIN{
+ case 'd':
+ chatty9p++;
+ break;
+ case 'l':
+ logfile = EARGF(usage());
+ break;
+ case 'r':
+ replayfile = EARGF(usage());
+ break;
+ case 'c':
+ replaycount = atoi(EARGF(usage()));
+ break;
+ case 'm':
+ mountpt = EARGF(usage());
+ break;
+ case 's':
+ srvname = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ if(argc != 1)
+ usage();
+
+ if((fd = open(argv[0], OREAD)) == -1)
+ sysfatal("open %s: %r", argv[0]);
+ if((d = dirfstat(fd)) == nil)
+ sysfatal("failed to stat file: %r");
+ if((membuf = sbrk(d->length)) == (void*)-1)
+ sysfatal("failed to allocate buffer: %r");
+ d->length -= (d->length % IOUNIT);
+ memset(membuf, 0, d->length);
+ for(off = 0; off < d->length; off += n)
+ if((n = read(fd, membuf+off, IOUNIT)) <= 0)
+ sysfatal("read %s@%lld: short read: %r", argv[0], off);
+ membufsz = d->length;
+ free(d);
+ if(replayfile != nil){
+ if((replayfd = open(replayfile, OREAD)) == -1)
+ sysfatal("failed to open replay file: %r");
+ for(i = 0; i < replaycount || replaycount == -1; i++)
+ if(replay1(replayfd) == 0)
+ break;
+ print("replayed %d ops\n", i);
+ }
+
+ if(logfile != nil){
+ if((logfd = create(logfile, OWRITE, 0666)) == -1)
+ sysfatal("failed to open log file: %r");
+ }
+ uid = getuser();
+ fs.tree = alloctree(uid, uid, DMDIR|0555, nil);
+ ctlfile = createfile(fs.tree->root, "ctl", uid, 0666, nil);
+ datfile = createfile(fs.tree->root, "data", uid, 0666, nil);
+ datfile->length = membufsz;
+ postmountsrv(&fs, srvname, mountpt, MREPL);
+ exits(nil);
+}
--- /dev/null
+++ b/fsbench-par.c
@@ -1,0 +1,529 @@
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+//#include "bench.h"
+
+typedef struct Bench Bench;
+
+enum {
+ KiB = 1024ULL,
+ MiB = 1024ULL*KiB,
+ GiB = 1024ULL*MiB,
+ Bufsz = 8*1024ULL,
+};
+
+enum {
+ Bps,
+ Fps,
+};
+
+struct Bench {
+ /* internal state */
+ char *name;
+ char *unit;
+ vlong (*fn)(Bench*);
+ vlong reps;
+ vlong resrd;
+ vlong reswr;
+ int nrd;
+ int nwr;
+
+ /* thread state */
+ int reader;
+ vlong i0;
+ vlong i1;
+ char *s0;
+ char *s1;
+};
+
+#define GBIT64(p) ((u32int)(((uchar*)(p))[0]|(((uchar*)(p))[1]<<8)|\
+ (((uchar*)(p))[2]<<16)|(((uchar*)(p))[3]<<24)) |\
+ ((uvlong)(((uchar*)(p))[4]|(((uchar*)(p))[5]<<8)|\
+ (((uchar*)(p))[6]<<16)|(((uchar*)(p))[7]<<24)) << 32))
+vlong
+vrand(vlong n)
+{
+ uchar buf[8];
+ vlong slop, v;
+
+ slop = 0x7fffffffffffffffULL % n;
+ do{
+ prng(buf, 8);
+ v = GBIT64(buf);
+ }while(v <= slop);
+ return v % n;
+}
+
+vlong
+wrfile_la(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i;
+ int fd, n;
+
+ if((fd = create(b->s0, OWRITE, 0666)) == -1)
+ sysfatal("open: %r");
+ for(i = 0; i < b->i0; i += Bufsz)
+ if((n = write(fd, buf, Bufsz)) != Bufsz)
+ sysfatal("write: => %d: %r", n);
+ close(fd);
+ return b->i0/MiB;
+}
+
+vlong
+wrfile_ra(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i, n, j, t, *off;
+ int fd;
+
+ n = b->i0/Bufsz;
+ if((fd = create(b->s0, OWRITE, 0666)) == -1)
+ sysfatal("open: %r");
+ if((off = malloc(n*sizeof(vlong))) == nil)
+ sysfatal("malloc: %r");
+ for(i = 0; i < n; i++)
+ off[i] = i*Bufsz;
+ for (i = n - 1; i > 0; i--) {
+ j = vrand(i+1);
+ t = off[i];
+ off[i] = off[j];
+ off[j] = t;
+ }
+ for(i = 0; i < n; i++)
+ if(pwrite(fd, buf, Bufsz, off[i]) != Bufsz)
+ sysfatal("write: %r");
+ close(fd);
+ return b->i0/MiB;
+}
+
+vlong
+wrfile_rr(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i, n, j, t, *off;
+ int fd;
+
+ n = b->i0/Bufsz;
+ if((fd = create(b->s0, OWRITE, 0666)) == -1)
+ sysfatal("open: %r");
+ if((off = malloc(n*sizeof(vlong))) == nil)
+ sysfatal("malloc: %r");
+ for(i = 0; i < n; i++)
+ off[i] = i*Bufsz;
+ for (i = n - 1; i > 0; i--) {
+ j = vrand(i+1);
+ t = off[i];
+ off[i] = off[j];
+ off[j] = t;
+ }
+ for(i = 0; i < n; i++)
+ if(pwrite(fd, buf, Bufsz, off[i] + vrand(100)) != Bufsz)
+ sysfatal("write: %r");
+ close(fd);
+ return b->i0/MiB;
+}
+
+vlong
+rdfile_la(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i, rep;
+ int fd, n;
+
+ if((fd = open(b->s0, OREAD)) == -1)
+ sysfatal("open: %r");
+ for(rep = 0; rep < b->reps; rep++){
+ seek(fd, 0, 0);
+ for(i = 0; i < b->i0; i += Bufsz)
+ if((n = read(fd, buf, Bufsz)) != Bufsz)
+ sysfatal("write: n=%d, %r", n);
+ }
+ close(fd);
+ return b->reps*(b->i0/MiB);
+}
+
+vlong
+rdfile_ra(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i, rep;
+ uvlong off;
+ int fd;
+
+ if((fd = open(b->s0, OREAD)) == -1)
+ sysfatal("open: %r");
+ for(rep = 0; rep < b->reps; rep++){
+ seek(fd, 0, 0);
+ for(i = 0; i < b->i0; i += Bufsz){
+ off = vrand(b->i0-Bufsz) & ~(Bufsz-1);
+ if(pread(fd, buf, Bufsz, off) != Bufsz)
+ sysfatal("write: %r");
+ }
+ }
+ close(fd);
+ return b->reps*(b->i0/MiB);
+}
+
+QLock donelk;
+Rendez donerz;
+QLock spawnlk;
+Rendez spawnrz;
+
+vlong
+rwfile_lala(Bench *b)
+{
+ char buf[64];
+
+ if(b->reader){
+ return rdfile_la(b);
+ }else{
+ b->s0 = buf;
+ snprint(buf, sizeof(buf), "rwfile.w%d", getpid());
+ return wrfile_la(b);
+ }
+}
+
+//vlong
+//rwfile_lara(Bench *b)
+//{
+// Bench *bb;
+//
+// if((bb = malloc(sizeof(Bench)*(b->i0 + b->i1))) == nil)
+// sysfatal("malloc: %r");
+// for(i = 0; i < b->i0; i++){
+// b[i] = *bb;
+// b[i].s0 = smprint("rwfile.w%d", i);
+// launch(&b[i], wrfile_la);
+// }
+// for(i = 0; i < b->i1; i++){
+// b[i] = *bb;
+// launch(&b[i], rdfile_ra);
+// }
+//}
+//
+//vlong
+//rwfile_rara(Bench *b)
+//{
+// Bench *bb;
+//
+// if((bb = malloc(sizeof(Bench)*(b->i0 + b->i1))) == nil)
+// sysfatal("malloc: %r");
+// for(i = 0; i < b->i0; i++){
+// b[i] = *bb;
+// b[i].s0 = smprint("rwfile.w%d", i);
+// launch(&b[i], wrfile_ra);
+// }
+// for(i = 0; i < b->i1; i++){
+// b[i] = *bb;
+// launch(&b[i], rdfile_ra);
+// }
+//}
+//
+//vlong
+//rwfile_rrrr(Bench *b)
+//{
+// Bench *bb;
+//
+// if((bb = malloc(sizeof(Bench)*(b->i0 + b->i1))) == nil)
+// sysfatal("malloc: %r");
+// for(i = 0; i < b->i0; i++){
+// b[i] = *bb;
+// b[i].s0 = smprint("rwfile.w%d", i);
+// launch(&b[i], wrfile_rr);
+// }
+// for(i = 0; i < b->i1; i++){
+// b[i] = *bb;
+// launch(&b[i], rdfile_rr);
+// }
+//}
+
+vlong
+rdfile_rr(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i, rep;
+ uvlong off;
+ int fd;
+
+ if((fd = open(b->s0, OREAD)) == -1)
+ sysfatal("open: %r");
+ for(rep = 0; rep < 10; rep++){
+ for(i = 0; i < b->i0; i += Bufsz){
+ off = vrand(b->i0-Bufsz);
+ if(pread(fd, buf, Bufsz, off) != Bufsz)
+ sysfatal("read: %r");
+ }
+ }
+ close(fd);
+ return b->reps*(b->i0/MiB);
+}
+
+vlong
+createflat(Bench *b)
+{
+ char buf[Bufsz];
+ int i, fd;
+
+ for(i = 0; i < b->i0; i++){
+ snprint(buf, sizeof(buf), "%d", i);
+ if((fd = create(buf, OWRITE, 0666)) == -1)
+ sysfatal("create: %r");
+ if(b->i0 != 0)
+ write(fd, buf, b->i1);
+ close(fd);
+ }
+ return b->i0;
+}
+
+int
+createlevel(int n, int d)
+{
+ char buf[Bufsz];
+ int i, s, fd;
+
+ s = 0;
+ for(i = 0; i < n; i++){
+ snprint(buf, sizeof(buf), "%d", i);
+ if(d > 0){
+ if((fd = create(buf, OWRITE, 0777|DMDIR)) == -1)
+ sysfatal("create: %r");
+ if(chdir(buf) == -1)
+ sysfatal("chdir %s: %r", buf);
+ s += createlevel(n, d-1);
+ chdir("..");
+ }else{
+ if((fd = create(buf, OWRITE, 0666)) == -1)
+ sysfatal("create: %r");
+ s++;
+ }
+ close(fd);
+ }
+ return s;
+}
+
+vlong
+createhier(Bench *b)
+{
+ return createlevel(b->i0, b->i1);
+}
+
+vlong
+listfiles(Bench *b)
+{
+ char buf[Bufsz];
+ int r, fd;
+
+ if((fd = open(".", OREAD)) == -1)
+ sysfatal("open .: %r");
+ while(1){
+ if((r = read(fd, buf, sizeof(buf))) == -1)
+ sysfatal("read: %r");
+ if(r == 0)
+ break;
+ }
+ close(fd);
+ return b->i0;
+}
+
+vlong
+randopen(Bench *b)
+{
+ char buf[Bufsz];
+ int i, fd;
+
+ for(i = 0; i < b->reps; i++){
+ snprint(buf, sizeof(buf), "%d", vrand(b->i0));
+ if((fd = open(buf, OREAD)) == -1)
+ sysfatal("open: %r");
+ close(fd);
+ }
+ return b->reps;
+}
+
+
+static void
+run1(vlong (*f)(Bench*), Bench *b, vlong *r)
+{
+ int pid;
+
+ pid = rfork(RFPROC|RFMEM);
+ if(pid < 0)
+ sysfatal("can't fork: %r");
+ if (pid == 0)
+ *r = (*f)(b);
+}
+
+vlong
+launchrd(Bench *b)
+{
+ Bench *sub;
+ vlong sum, *res;
+ int i;
+
+ if((sub = malloc(b->nrd*sizeof(Bench))) == nil)
+ sysfatal("malloc: %r");
+ if((res = malloc(b->nrd*sizeof(vlong))) == nil)
+ sysfatal("malloc: %r");
+ for(i = 0; i < b->nrd; i++){
+ sub[i] = *b;
+ sub[i].reader = 1;
+ run1(b->fn, &sub[i], &res[i]);
+ }
+ for(i = 0; i < b->nrd; i++)
+ waitpid();
+ sum = 0;
+ for(i = 0; i < b->nrd; i++)
+ sum += res[i];
+ free(sub);
+ free(res);
+ return sum;
+}
+
+vlong
+launchwr(Bench *b)
+{
+ Bench *sub;
+ vlong sum, *res;
+ int i;
+
+ if((sub = malloc(b->nwr*sizeof(Bench))) == nil)
+ sysfatal("malloc: %r");
+ if((res = malloc(b->nwr*sizeof(vlong))) == nil)
+ sysfatal("malloc: %r");
+ for(i = 0; i < b->nwr; i++){
+ sub[i] = *b;
+ sub[i].reader = 0;
+ run1(b->fn, &sub[i], &res[i]);
+ }
+ for(i = 0; i < b->nwr; i++)
+ waitpid();
+ sum = 0;
+ for(i = 0; i < b->nwr; i++)
+ sum += res[i];
+ free(sub);
+ free(res);
+ return sum;
+}
+
+void
+partest(Bench *b)
+{
+ run1(launchrd, b, &b->resrd);
+ run1(launchwr, b, &b->reswr);
+ waitpid();
+ waitpid();
+}
+
+void
+showres(Bench *b, double dt, double res)
+{
+ char *unit[] = {"ns", "us", "ms", "s"};
+ int i;
+
+ for(i = 0; i < nelem(unit)-1; i++)
+ if(dt/1000 < 1)
+ break;
+ else
+ dt /= 1000.0;
+ print("%f%s (%f %s/%s)\n", dt, unit[i], res/dt, b->unit, unit[i]);
+}
+
+
+void
+runbench(Bench *b, int nb)
+{
+ double res;
+ vlong t0, t1;
+ int i;
+
+ for(i = 0; i < nb; i++){
+ if(b[i].reps == 0)
+ b[i].reps = 1;
+ if(b[i].nrd == 0 && b[i].nwr == 0){
+ print("%15s: ", b[i].name);
+ t0 = nsec();
+ res = b[i].fn(&b[i]);
+ t1 = nsec();
+ showres(&b[i], t1-t0, res);
+ }else{
+ print("%15s:\n", b[i].name);
+ t0 = nsec();
+ partest(&b[i]);
+ t1 = nsec();
+ print(" rd: ");
+ showres(&b[i], t1-t0, b[i].resrd);
+ print(" wr: ");
+ showres(&b[i], t1-t0, b[i].reswr);
+ }
+ }
+}
+
+static Bench marks[] = {
+ /* l => linear, a => aligned, r => random */
+ {.name="wrcached_la", .i0=128*MiB, .reps=50, .unit="MiB", .fn=wrfile_la, .s0="cached0"},
+ {.name="rwcached_la_3:1", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nrd=3, .nwr=1},
+ {.name="rdcached_lala", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_la, .s0="cached0"},
+ {.name="rdcached_lara", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_ra, .s0="cached0"},
+ {.name="rdcached_larr", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_rr, .s0="cached0"},
+
+ {.name="wrcached_ra", .i0=128*MiB, .reps=50, .unit="MiB", .fn=wrfile_ra, .s0="cached1"},
+ {.name="rdcached_rala", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_la, .s0="cached1"},
+ {.name="rdcached_rara", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_ra, .s0="cached1"},
+ {.name="rdcached_rarr", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_rr, .s0="cached1"},
+
+ {.name="wrcached_rr", .i0=128*MiB, .reps=50, .unit="MiB", .fn=wrfile_rr, .s0="cached2"},
+ {.name="rdcached_rrla", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_la, .s0="cached2"},
+ {.name="rdcached_rrra", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_ra, .s0="cached2"},
+ {.name="rdcached_rrrr", .i0=128*MiB, .reps=50, .unit="MiB", .fn=rdfile_rr, .s0="cached2"},
+
+ {.name="rwcached_la_1:3", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nrd=1, .nwr=3},
+ {.name="rwcached_la_3:3", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nrd=3, .nwr=3},
+ {.name="rwcached_la_10:1", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nrd=10, .nwr=1},
+// {.name="rwcached_la_10:5", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nrd=10, .nwr=6},
+// {.name="rwcached_la", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rwfile_la, .s0="cached0", .nrd=10, .nwr=10},
+//
+// {.name="rwcached_lara", .i0=512*MiB, .reps=10, .unit="MiB", .fn=rwfile_la, .s0="cached0", .i0=1, .i1=3},
+// {.name="rwcached_la", .i0=512*MiB, .reps=10, .unit="MiB", .fn=rwfile_la, .s0="cached0", .i0=3, .i1=3},
+// {.name="rwcached_la", .i0=512*MiB, .reps=10, .unit="MiB", .fn=rwfile_la, .s0="cached0", .i0=10, .i1=10},
+
+
+ {.name="wrlarge_la", .i0=16*GiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="large0"},
+ {.name="rdlarge_lala", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_la, .s0="large0"},
+ {.name="rdlarge_lara", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_ra, .s0="large0"},
+ {.name="rdlarge_larr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_rr, .s0="large0"},
+
+ {.name="wrlarge_ra", .i0=16*GiB, .reps=1, .unit="MiB", .fn=wrfile_ra, .s0="large1"},
+ {.name="rdlarge_lara", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_la, .s0="large1"},
+ {.name="rdlarge_rara", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_ra, .s0="large1"},
+ {.name="rdlarge_rarr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_rr, .s0="large1"},
+
+ {.name="wrlarge_rr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=wrfile_rr, .s0="large2"},
+ {.name="rdlarge_larr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_la, .s0="large2"},
+ {.name="rdlarge_rarr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_ra, .s0="large2"},
+ {.name="rdlarge_rrrr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_rr, .s0="large2"},
+
+ {.name="createflat", .i0=100*1000, .reps=1, .unit="files", .fn=createflat},
+ {.name="listfflat", .i0=100*1000, .reps=100, .unit="files", .fn=listfiles},
+ {.name="openfflat", .i0=100*1000, .reps=100*1000, .unit="files", .fn=randopen},
+
+// {.name="createheir", .i0=3, .i1=10, .reps=1, .unit="files", .fn=createhier},
+// {.name="openheir", .i0=3, .i1=10, .reps=1, .unit="files", .fn=randwalk},
+};
+
+void
+main(int argc, char **argv)
+{
+
+ ARGBEGIN{
+ }ARGEND;
+
+ if(argc != 1){
+ fprint(2, "usage: %s wdir\n", argv0);
+ exits("usage");
+ }
+ if(chdir(argv[0]) == -1)
+ sysfatal("chdir: %r");
+ runbench(marks, nelem(marks));
+ exits(nil);
+}
--- /dev/null
+++ b/fsbench.c
@@ -1,0 +1,518 @@
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+#include <thread.h>
+
+int mainstacksize = 64*1024*1024;
+typedef struct Bench Bench;
+enum {
+ KiB = 1024ULL,
+ MiB = 1024ULL*KiB,
+ GiB = 1024ULL*MiB,
+ Bufsz = 128*IOUNIT,
+};
+
+enum {
+ Bps,
+ Fps,
+};
+
+struct Bench {
+ char *name;
+ char *unit;
+ vlong (*fn)(Bench*);
+ vlong reps;
+ int nproc;
+ int id;
+ Channel *rc;
+
+ vlong i0;
+ vlong i1;
+ vlong i2;
+ char *s0;
+ char *s1;
+};
+
+#define GBIT64(p) ((u32int)(((uchar*)(p))[0]|(((uchar*)(p))[1]<<8)|\
+ (((uchar*)(p))[2]<<16)|(((uchar*)(p))[3]<<24)) |\
+ ((uvlong)(((uchar*)(p))[4]|(((uchar*)(p))[5]<<8)|\
+ (((uchar*)(p))[6]<<16)|(((uchar*)(p))[7]<<24)) << 32))
+vlong
+vrand(vlong n)
+{
+ uchar buf[8];
+ vlong slop, v;
+
+ slop = 0x7fffffffffffffffULL % n;
+ do{
+ prng(buf, 8);
+ v = GBIT64(buf);
+ }while(v <= slop);
+ return v % n;
+}
+
+vlong
+wrfile_la(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i;
+ int fd;
+
+ if((fd = create(b->s0, OWRITE, 0666)) == -1)
+ sysfatal("open: %r");
+ for(i = 0; i < b->i0; i += Bufsz)
+ if(write(fd, buf, Bufsz) != Bufsz)
+ sysfatal("write: %r");
+ close(fd);
+ return b->i0/MiB;
+}
+
+vlong
+wrfile_ra(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i, n, j, t, *off;
+ int fd;
+
+ n = b->i0/Bufsz;
+ if((fd = create(b->s0, OWRITE, 0666)) == -1)
+ sysfatal("open: %r");
+ if((off = malloc(n*sizeof(vlong))) == nil)
+ sysfatal("malloc: %r");
+ for(i = 0; i < n; i++)
+ off[i] = i*Bufsz;
+ for (i = n - 1; i > 0; i--) {
+ j = vrand(i+1);
+ t = off[i];
+ off[i] = off[j];
+ off[j] = t;
+ }
+ for(i = 0; i < n; i++)
+ if(pwrite(fd, buf, Bufsz, off[i]) != Bufsz)
+ sysfatal("write: %r");
+ close(fd);
+ free(off);
+ return b->i0/MiB;
+}
+
+vlong
+wrfile_rr(Bench *b)
+{
+ char buf[Bufsz];
+ vlong i, n, j, t, *off;
+ int fd;
+
+ n = b->i0/Bufsz;
+ if((fd = create(b->s0, OWRITE, 0666)) == -1)
+ sysfatal("open: %r");
+ if((off = malloc(n*sizeof(vlong))) == nil)
+ sysfatal("malloc: %r");
+ for(i = 0; i < n; i++)
+ off[i] = i*Bufsz;
+ for (i = n - 1; i > 0; i--) {
+ j = vrand(i+1);
+ t = off[i];
+ off[i] = off[j];
+ off[j] = t;
+ }
+ for(i = 0; i < n; i++)
+ if(pwrite(fd, buf, Bufsz, off[i] + vrand(100)) != Bufsz)
+ sysfatal("write: %r");
+ close(fd);
+ free(off);
+ return b->i0/MiB;
+}
+
+vlong
+rdfile_la(Bench *b)
+{
+ char path[128], buf[Bufsz];
+ vlong i, rep;
+ int fd;
+
+ if(b->id == -1)
+ snprint(path, sizeof(path), "%s", b->s0);
+ else if(b->i1 != 0)
+ snprint(path, sizeof(path), "%s.%lld", b->s0, b->id % b->i1);
+ else
+ snprint(path, sizeof(path), "%s.%d", b->s0, b->id);
+ if((fd = open(path, OREAD)) == -1)
+ sysfatal("open: %r");
+ for(rep = 0; rep < b->reps; rep++){
+ seek(fd, 0, 0);
+ for(i = 0; i < b->i0; i += Bufsz)
+ if(read(fd, buf, Bufsz) != Bufsz)
+ sysfatal("write: %r");
+ }
+ close(fd);
+ return b->reps*(b->i0/MiB);
+}
+vlong
+rdfile_ra(Bench *b)
+{
+ char path[128], buf[Bufsz];
+ vlong i, rep;
+ uvlong off;
+ int fd;
+
+ if(b->id == -1)
+ snprint(path, sizeof(path), "%s", b->s0);
+ else if(b->i1 != 0)
+ snprint(path, sizeof(path), "%s.%lld", b->s0, b->id % b->i1);
+ else
+ snprint(path, sizeof(path), "%s.%d", b->s0, b->id);
+ if((fd = open(path, OREAD)) == -1)
+ sysfatal("open: %r");
+ for(rep = 0; rep < b->reps; rep++){
+ seek(fd, 0, 0);
+ for(i = 0; i < b->i0; i += Bufsz){
+ off = vrand(b->i0-Bufsz) & ~((vlong)Bufsz-1);
+ if(pread(fd, buf, Bufsz, off) != Bufsz)
+ sysfatal("write: %r");
+ }
+ }
+ close(fd);
+ return b->reps*(b->i0/MiB);
+}
+
+vlong
+rwfile_lala(Bench *b)
+{
+ char buf[64];
+ Bench bb;
+
+ bb = *b;
+ if(b->id >= b->i1)
+ return rdfile_la(&bb);
+ else{
+ snprint(buf, sizeof(buf), "%s%d.w%d", b->s0, getpid(), b->id);
+ bb.s0 = buf;
+ return wrfile_la(&bb);
+ }
+}
+
+vlong
+rdfile_rr(Bench *b)
+{
+ char path[128], buf[Bufsz];
+ vlong i, rep;
+ uvlong off;
+ int fd;
+
+ if(b->id == -1)
+ snprint(path, sizeof(path), "%s", b->s0);
+ else if(b->i1 != 0)
+ snprint(path, sizeof(path), "%s.%lld", b->s0, b->id % b->i1);
+ else
+ snprint(path, sizeof(path), "%s.%d", b->s0, b->id);
+ if((fd = open(path, OREAD)) == -1)
+ sysfatal("open: %r");
+ for(rep = 0; rep < b->reps; rep++){
+ for(i = 0; i < b->i0; i += Bufsz){
+ off = vrand(b->i0-Bufsz);
+ if(pread(fd, buf, Bufsz, off) != Bufsz)
+ sysfatal("read: %r");
+ }
+ }
+ close(fd);
+ return b->reps*(b->i0/MiB);
+}
+
+vlong
+createflat(Bench *b)
+{
+ char buf[Bufsz];
+ int i, fd;
+
+ for(i = 0; i < b->i0; i++){
+ snprint(buf, sizeof(buf), "%s%d", b->s0, i);
+ if((fd = create(buf, OWRITE, 0666)) == -1)
+ sysfatal("create: %r");
+ if(b->i1 != 0)
+ write(fd, buf, b->i1);
+ close(fd);
+ }
+ return b->i0;
+}
+
+int
+createlevel(int n, int d)
+{
+ char buf[Bufsz];
+ int i, s, fd;
+
+ s = 0;
+ for(i = 0; i < n; i++){
+ snprint(buf, sizeof(buf), "%d", i);
+ if(d > 0){
+ if((fd = create(buf, OWRITE, 0777|DMDIR)) == -1)
+ sysfatal("create: %r");
+ if(chdir(buf) == -1)
+ sysfatal("chdir %s: %r", buf);
+ s += createlevel(n, d-1);
+ chdir("..");
+ }else{
+ if((fd = create(buf, OWRITE, 0666)) == -1)
+ sysfatal("create: %r");
+ s++;
+ }
+ close(fd);
+ }
+ return s;
+}
+
+vlong
+createhier(Bench *b)
+{
+ return createlevel(b->i0, b->i1);
+}
+
+vlong
+listfiles(Bench *b)
+{
+ char buf[Bufsz];
+ int i, r, fd;
+
+ for(i = 0; i < b->reps; i++){
+ if((fd = open(".", OREAD)) == -1)
+ sysfatal("open .: %r");
+ while(1){
+ if((r = read(fd, buf, sizeof(buf))) == -1)
+ sysfatal("read: %r");
+ if(r == 0)
+ break;
+ }
+ close(fd);
+ }
+ return b->reps*b->i0;
+}
+
+vlong
+randopen(Bench *b)
+{
+ char buf[Bufsz];
+ int i, fd;
+
+ for(i = 0; i < b->reps; i++){
+ snprint(buf, sizeof(buf), "%s%lld", b->s0, vrand(b->i0));
+ if((fd = open(buf, OREAD)) == -1)
+ sysfatal("open: %r");
+ if(b->i0)
+ if(read(fd, buf, sizeof(buf)) == -1)
+ sysfatal("read: %r");
+ close(fd);
+ }
+ return b->reps;
+}
+
+void
+launch(void *p)
+{
+ Bench *b;
+ vlong r;
+
+ b = p;
+ r = b->fn(b);
+ send(b->rc, &r);
+}
+
+vlong
+runpar(Bench *b)
+{
+ vlong r, sum;
+ Bench *sub;
+ int i;
+
+ sum = 0;
+ b->rc = chancreate(sizeof(vlong), b->nproc);
+ if((sub = calloc(b->nproc, sizeof(Bench))) == nil)
+ sysfatal("malloc: %r");
+ for(i = 0; i < b->nproc; i++){
+ sub[i] = *b;
+ sub[i].id = i;
+ proccreate(launch, &sub[i], mainstacksize);
+ }
+ for(i = 0; i < b->nproc; i++){
+ recv(b->rc, &r);
+ sum += r;
+ }
+ free(sub);
+ return sum;
+}
+
+void
+runbench(Bench *b, int nb)
+{
+ char *unit[] = {"ns", "us", "ms", "s"};
+ double oc, dt;
+ vlong t0, t1;
+ int i, j;
+
+ for(i = 0; i < nb; i++){
+ if(b[i].reps == 0)
+ b[i].reps = 1;
+ print("%20s:\t", b[i].name);
+ t0 = nsec();
+ if(b[i].nproc <= 1){
+ b[i].id = -1;
+ oc = b[i].fn(&b[i]);
+ }else
+ oc = runpar(&b[i]);
+ t1 = nsec();
+ dt = (t1 - t0);
+ for(j = 0; j < nelem(unit)-1; j++)
+ if(dt/100 < 1)
+ break;
+ else
+ dt /= 1000.0;
+ print("%f%s (%f %s/%s)\n", dt, unit[j], (double)oc/dt, b[i].unit, unit[j]);
+ }
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ Bench marks[] = {
+ /* l => linear, a => aligned, r => random */
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.0"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.1"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.2"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.3"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.4"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.5"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.6"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.7"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.8"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.9"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.10"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.11"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.12"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.13"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.14"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.15"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.16"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.17"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.18"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.19"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.20"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.21"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.22"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.23"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.24"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.25"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.26"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.27"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.28"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.29"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.30"},
+ {.name="wrcached_la", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="cached0.31"},
+
+ {.name="rdcached_lala", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_la, .s0="cached0"},
+ {.name="rdcached_lara", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_ra, .s0="cached0"},
+ {.name="rdcached_larr", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0"},
+
+ {.name="rdcached_lala_2p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_la, .s0="cached0", .nproc=2},
+ {.name="rdcached_lara_2p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_ra, .s0="cached0", .nproc=2},
+ {.name="rdcached_larr_2p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0", .nproc=2},
+
+ {.name="rdcached_lala_4p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_la, .s0="cached0", .nproc=4},
+ {.name="rdcached_lara_4p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_ra, .s0="cached0", .nproc=4},
+ {.name="rdcached_larr_4p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0", .nproc=4},
+
+ {.name="rdcached_lala_8p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_la, .s0="cached0", .nproc=8},
+ {.name="rdcached_lara_8p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_ra, .s0="cached0", .nproc=8},
+ {.name="rdcached_larr_8p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0", .nproc=8},
+
+ {.name="rdcached_lala_12p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_la, .s0="cached0", .nproc=12},
+ {.name="rdcached_lara_12p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_ra, .s0="cached0", .nproc=12},
+ {.name="rdcached_larr_12p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0", .nproc=12},
+
+ {.name="rdcached_lala_16p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_la, .s0="cached0", .nproc=16},
+ {.name="rdcached_lara_16p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_ra, .s0="cached0", .nproc=16},
+ {.name="rdcached_larr_16p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0", .nproc=16},
+
+ {.name="rdcached_lala_16p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_la, .s0="cached0", .nproc=16},
+ {.name="rdcached_lara_16p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_ra, .s0="cached0", .nproc=16},
+ {.name="rdcached_larr_16p", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0", .nproc=16},
+
+ {.name="rdcached_lala_16p_1f", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_la, .s0="cached0", .nproc=16, .i1=1},
+ {.name="rdcached_lara_16p_8f", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_ra, .s0="cached0", .nproc=16, .i1=8},
+ {.name="rdcached_larr_32p_16f", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0", .nproc=32, .i1=16},
+ {.name="rdcached_larr_32p_32f", .i0=128*MiB, .reps=2, .unit="MiB", .fn=rdfile_rr, .s0="cached0", .nproc=32, .i1=32},
+
+ {.name="wrcached_ra", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_ra, .s0="cached1"},
+ {.name="rdcached_rala", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rdfile_la, .s0="cached1"},
+ {.name="rdcached_rara", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rdfile_ra, .s0="cached1"},
+ {.name="rdcached_rarr", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rdfile_rr, .s0="cached1"},
+
+ {.name="wrcached_rr", .i0=128*MiB, .reps=1, .unit="MiB", .fn=wrfile_rr, .s0="cached2"},
+ {.name="rdcached_rrla", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rdfile_la, .s0="cached2"},
+ {.name="rdcached_rrra", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rdfile_ra, .s0="cached2"},
+ {.name="rdcached_rrrr", .i0=128*MiB, .reps=10, .unit="MiB", .fn=rdfile_rr, .s0="cached2"},
+
+ {.name="rwcached_la_r0_w2_w", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=2, .i1=2},
+ {.name="rwcached_la_r0_w4_w", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=4, .i1=4},
+ {.name="rwcached_la_r1_w1_w", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=2, .i1=1},
+ {.name="rwcached_la_r3_w1_w", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=4, .i1=1},
+ {.name="rwcached_la_r2_w2_w", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=4, .i1=2},
+ {.name="rwcached_la_r6_w2_w", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=8, .i1=2},
+ {.name="rwcached_la_r4_w4_w", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=8, .i1=4},
+
+ {.name="rwcached_la_r1_w1_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=2, .i1=1},
+ {.name="rwcached_la_r2_w1_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=3, .i1=1},
+ {.name="rwcached_la_r3_w1_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=4, .i1=1},
+ {.name="rwcached_la_r1_w2_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=4, .i1=2},
+ {.name="rwcached_la_r1_w2_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=3, .i1=2},
+ {.name="rwcached_la_r2_w2_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=4, .i1=2},
+ {.name="rwcached_la_r4_w2_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=4, .i1=2},
+ {.name="rwcached_la_r6_w2_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=8, .i1=2},
+ {.name="rwcached_la_r4_w4_r", .i0=64*MiB, .reps=10, .unit="MiB", .fn=rwfile_lala, .s0="cached0", .nproc=8, .i1=4},
+
+ {.name="createflat", .i0=100*1000, .reps=1, .unit="files", .fn=createflat, .s0="cz"},
+ {.name="write1flat", .i0=100*1000, .reps=1, .unit="files", .fn=createflat, .i1=1, .s0="c1"},
+ {.name="write100flat", .i0=100*1000, .reps=1, .unit="files", .fn=createflat, .i1=100, .s0="c100"},
+ {.name="write1027flat", .i0=100*1000, .reps=1, .unit="files", .fn=createflat, .i1=1027, .s0="c1027"},
+ {.name="listfflat", .i0=100*1000, .reps=10, .unit="files", .fn=listfiles},
+ {.name="openfflat", .i0=100*1000, .reps=100*1000, .unit="files", .fn=randopen, .s0="cz"},
+ {.name="read0flat", .i0=100*1000, .reps=100*1000, .unit="files", .fn=randopen, .i1=1, .s0="cz"},
+ {.name="read1flat", .i0=100*1000, .reps=100*1000, .unit="files", .fn=randopen, .i1=1, .s0="c1"},
+ {.name="read100flat", .i0=100*1000, .reps=100*1000, .unit="files", .fn=randopen, .i1=1, .s0="c100"},
+ {.name="read1027flat", .i0=100*1000, .reps=100*1000, .unit="files", .fn=randopen, .i1=1, .s0="c1027"},
+
+// {.name="rwcached_lara", .i0=512*MiB, .reps=10, .unit="MiB", .fn=rwfile_la, .s0="cached0", .i0=1, .i1=3},
+// {.name="rwcached_la", .i0=512*MiB, .reps=10, .unit="MiB", .fn=rwfile_la, .s0="cached0", .i0=3, .i1=3},
+// {.name="rwcached_la", .i0=512*MiB, .reps=10, .unit="MiB", .fn=rwfile_la, .s0="cached0", .i0=10, .i1=10},
+
+
+ {.name="wrlarge_la", .i0=16*GiB, .reps=1, .unit="MiB", .fn=wrfile_la, .s0="large0"},
+ {.name="rdlarge_lala", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_la, .s0="large0"},
+ {.name="rdlarge_lara", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_ra, .s0="large0"},
+// {.name="rdlarge_larr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_rr, .s0="large0"},
+
+ {.name="wrlarge_ra", .i0=16*GiB, .reps=1, .unit="MiB", .fn=wrfile_ra, .s0="large1"},
+ {.name="rdlarge_lara", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_la, .s0="large1"},
+ {.name="rdlarge_rara", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_ra, .s0="large1"},
+// {.name="rdlarge_rarr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_rr, .s0="large1"},
+
+// {.name="wrlarge_rr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=wrfile_rr, .s0="large2"},
+// {.name="rdlarge_larr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_la, .s0="large2"},
+// {.name="rdlarge_rarr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_ra, .s0="large2"},
+// {.name="rdlarge_rrrr", .i0=16*GiB, .reps=1, .unit="MiB", .fn=rdfile_rr, .s0="large2"},
+
+// {.name="createheir", .i0=3, .i1=10, .reps=1, .unit="files", .fn=createhier},
+// {.name="openheir", .i0=3, .i1=10, .reps=1, .unit="files", .fn=randwalk},
+ };
+
+ ARGBEGIN{
+ }ARGEND;
+
+ if(argc != 1){
+ fprint(2, "usage: %s wdir\n", argv0);
+ exits("usage");
+ }
+ if(chdir(argv[0]) == -1)
+ sysfatal("chdir: %r");
+ runbench(marks, nelem(marks));
+ exits(nil);
+}
--- /dev/null
+++ b/gobuild.rc
@@ -1,0 +1,17 @@
+#!/bin/rc
+
+if(~ $#1 0)
+ go=/tmp/go1.17.13-plan9-amd64-bootstrap.tbz
+GOROOT=/n/gefs/go
+GOROOT_BOOTSTRAP=/n/gefs/go-plan9-amd64-bootstrap
+rfork n
+m
+cd /n/gefs
+mkdir go
+mkdir tmp
+bunzip2 -c $go | tar x
+dircp go-plan9-amd64-bootstrap go
+bind -c tmp /tmp
+cd go/src
+./all.rc
+
--- /dev/null
+++ b/iobench.c
@@ -1,0 +1,33 @@
+#include <u.h>
+#include <libc.h>
+
+void
+runbench(Bench *b, int nb)
+{
+ char *unit[] = {"ns", "us", "ms", "s"};
+ double oc, dt;
+ vlong t0, t1;
+ int i, j;
+
+ for(i = 0; i < nb; i++){
+ if(b[i].reps == 0)
+ b[i].reps = 1;
+ print("%15s:\t", b[i].name);
+ t0 = nsec();
+ oc = b[i].fn(&b[i]);
+ t1 = nsec();
+ dt = (t1 - t0);
+ for(j = 0; j < nelem(unit)-1; j++)
+ if(dt/1000 < 1)
+ break;
+ else
+ dt /= 1000.0;
+ print("%f%s (%f %s/%s)\n", dt, unit[j], (double)oc/dt, b[i].unit, unit[j]);
+ sleep(10*1000);
+ }
+}
+
+void
+main(int argc, char **argv)
+{
+ Bench marks[] = {
--- /dev/null
+++ b/mkcwfs.rc
@@ -1,0 +1,28 @@
+#!/bin/rc
+/sys/src/cmd/cwfs/cwfs64x/6.cwfs64x -C -n cwfs.test -f $1 -c <<EOF
+ service cwfs.test
+ config $1
+ noauth
+ filsys main ($1)
+ ream main
+ end
+EOF
+
+{
+ echo noattach
+ echo allow
+ echo users default
+ echo cfs main
+ echo create /adm adm adm 775 d
+ echo create /adm/users adm adm 664
+ echo create /dist sys sys 775 d
+ echo create /usr sys sys 775 d
+ echo newuser $user
+ echo newuser adm +$user
+ echo newuser sys +$user
+ echo newuser upas +$user
+ echo noattach
+ sleep 2
+} >>/srv/cwfs.test.cmd
+
+mount -c /srv/cwfs.test /n/cwfs
--- /dev/null
+++ b/mkdel.c
@@ -1,0 +1,15 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(void)
+{
+ int i, fd;
+
+ for(i = 0; i < 1000*1000; i++){
+ fd = create("x", ORDWR, 0666);
+ close(fd);
+ remove("x");
+ }
+ exits(nil);
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,16 @@
+</$objtype/mkfile
+
+TESTS=\
+ basic\
+ build\
+ files\
+
+all:V: 6.freplay 6.fsbench 6.files
+
+test:VQ:
+ @{cd .. && mk 6.out}
+ for(t in $TESTS){
+ echo $t...
+ ./$t.rc >[2=1] >$t.log
+ }
+</sys/src/cmd/mktest
--- /dev/null
+++ b/mkfossil.rc
@@ -1,0 +1,16 @@
+#!/bin/rc
+
+
+fossil/flfmt $1
+fossil/conf -w $1 <<EOF
+ fsys main config
+ fsys main open -AWP
+ fsys main
+ create /active/adm adm sys d775
+ create /active/adm/users adm sys 664
+ users -w
+ srv -p fscons.test
+ srv fossil.test
+EOF
+fossil/fossil -f $1
+mount -c /srv/fossil.test /n/fossil
--- /dev/null
+++ b/mkgefs.rc
@@ -1,0 +1,8 @@
+#!/bin/rc
+
+@{cd .. && mk all}
+../6.out -r $user -f $1
+../6.out -n gefs.test -A -m 2048 -f $1
+
+mount -c /srv/gefs.test /n/gefs
+mount -c /srv/gefs.test /n/gefs.adm adm
--- /dev/null
+++ b/mkhjfs.rc
@@ -1,0 +1,17 @@
+#!/bin/rc
+
+hjfs -n hjfs.test -S -m 1024 -r -f $1
+{
+ echo echo on
+ echo allow
+ echo create /dist sys sys 775 d
+ echo create /usr sys sys 775 d
+ echo newuser $user
+ echo newuser adm +$user
+ echo newuser sys +$user
+ echo newuser upas +$user
+ echo echo off
+ sleep 2
+} >>/srv/hjfs.test.cmd
+
+mount -c /srv/hjfs.test /n/hjfs
--- /dev/null
+++ b/orclose.c
@@ -1,0 +1,18 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(int argc, char **argv)
+{
+ int fd;
+
+ ARGBEGIN{}ARGEND;
+ if((fd = create("/n/gefs/foo", ORCLOSE|OWRITE, 0644)) == -1)
+ sysfatal("open: %r");
+ if(access("/n/gefs/foo", OREAD) == -1)
+ sysfatal("access: %r");
+ close(fd);
+ if(access("/n/gefs/foo", OREAD) != -1)
+ sysfatal("access: file not removed");
+ exits(nil);
+}
--- /dev/null
+++ b/psnap.rc
@@ -1,0 +1,45 @@
+#!/bin/rc -e
+
+
+srv=/srv/gefs
+if(~ $#* 1)
+ srv=$1
+
+fn cloneto {
+ echo clone to $1
+ @{cd /n/gefs.$1 && git/clone /dist/plan9front}
+ echo clone $1 done
+}
+
+fn buildin {
+ @{
+ rfork n
+ cd /n/gefs.$1/plan9front/
+ . /sys/lib/rootstub
+ bind -c sys/include /sys/include
+ bind -c $objtype/lib /$objtype/lib
+ bind -bc $objtype/bin /bin
+ bind -bc $objtype/bin /$objtype/bin
+ cd sys/src
+ mk all >[2=1] >/tmp/ptest.$1.log
+ }
+}
+
+echo 'create snap'
+echo 'snap -m empty test1' >> $srv.cmd
+echo 'snap -m empty test2' >> $srv.cmd
+echo 'sync' >> $srv.cmd
+mount -c $srv /n/gefs.a test1
+mount -c $srv /n/gefs.b test2
+
+echo 'clone repos'
+cloneto a &
+cloneto b &
+wait
+
+echo 'build repos'
+buildin a &
+buildin b &
+wait
+
+echo 'done'
--- /dev/null
+++ b/replay.rc
@@ -1,0 +1,45 @@
+#!/bin/rc
+
+flagfmt='r:ream, s:start start'
+if(! ifs=() eval `{aux/getflags $*}){
+ aux/usage
+ exit usage
+}
+mk
+if(~ $#start 0)
+ start=0
+if(~ $#ream 1){
+ 6.out -r $user -f test.fs
+ test/6.freplay -l /tmp/fsreplay test.fs
+ 6.out -f /n/replay/data
+ mount -c /srv/gefs /n/gefs
+ @{
+ cd /n/gefs
+ git/clone gits://shithub.us/ori/git9
+ sleep 10
+ cd git9
+ mk all
+ echo sync >> /n/gefs/ctl
+ kill 6.out | rc
+ }
+ count=`{awk '{print $2}' < /n/replay/ctl}
+ echo exit > /n/replay/ctl
+}
+
+echo replaying $start .. $count IOs
+test/6.freplay -c $start -r /tmp/fsreplay test.fs
+for(i in `{seq $start 1 $count}){
+ echo run $i
+ kill 6.out | rc
+ if(! 6.out -m 128 -C -n gefs.replay -f /n/replay/data){
+ echo busted after op $i
+ exit
+ }
+ mount /srv/gefs.replay /n/gefs.replay
+ walk /n/gefs.replay | sed 20q
+ if(! echo step > /n/replay/ctl)
+ exit
+}
+kill 6.out | rc
+
+
--- /dev/null
+++ b/run.rc
@@ -1,0 +1,187 @@
+#!/bin/rc
+
+rfork e
+
+dev=$testdev
+if(~ $#testdev 0)
+ dev = testdev.fs
+switch($cputype){
+case amd64; O=6
+case arm64; O=7
+case arm; O=5
+case 386; O=8
+}
+
+fn sigexit sigint {
+ rm -f /srv/gefs.test /srv/gefs.test.cmd /srv/replay
+}
+
+fn die {
+ echo $* >[1=2]
+ exit $"*
+}
+
+fn log {
+ echo $* >[1=2]
+}
+
+fn ge_ream {
+ gefs -m 512 -r $user -f $1
+}
+
+fn ge_start {
+ gefs -m 512 -A -f $1 -n gefs.test
+ while(! test -e /srv/gefs.test)
+ sleep 0.1
+ mount -c /srv/gefs.test /n/gefs
+}
+
+fn ge_kill {
+ kill gefs | rc
+ while(test -e /srv/gefs.test)
+ sleep 0.1
+}
+
+fn ge_replay {@{
+ # prepare the test run
+ log reaming...
+ ge_ream $dev
+ log preparing replay...
+ rm -f replay.log
+ $O.freplay -l replay.log $dev
+ ge_start /mnt/replay/data
+ $*
+ echo save trace /tmp/trace >> /srv/gefs.test.cmd
+ sleep 5
+ ge_kill
+ cat /mnt/replay/ctl
+ count=`{awk '/writes/{print $2}' /mnt/replay/ctl}
+ log did $count writes.
+ echo exit > /mnt/replay/ctl
+ while(test -e /srv/replay)
+ sleep 0.1
+
+ # check blockwise consistency
+ log starting replay...
+ $O.freplay -c 1 -r replay.log $dev
+ for(i in `{seq 2 $count}){
+ gefs -c -f /mnt/replay/data >[2]/tmp/log || die 'broken'
+ log stepping $i...
+ echo step > /mnt/replay/ctl
+ }
+ echo exit > /mnt/replay/ctl
+ while(test -e /srv/replay)
+ sleep 0.1
+ exit ''
+}}
+
+fn ge_ok {@{
+ # prepare the test run
+ log reaming...
+ ge_ream $dev
+ log preparing build-and-verify...
+ $O.freplay -l replay.log $dev
+ ge_start $dev
+ $*
+ echo save trace /tmp/trace >> /srv/gefs.test.cmd
+ ge_kill
+ gefs -c -f $dev
+}}
+
+fn buildsys{@{
+ rfork ne
+ cd /n/gefs
+ . /sys/lib/rootstub
+ if(! test -e plan9front)
+ git/clone /dist/plan9front
+ bind -c $objtype/lib /$objtype/lib
+ bind -c plan9front/sys/include /sys/include
+ bind -c tmp /tmp
+ cd plan9front/sys/src
+ mk clean >> /tmp/gefsbuild.log
+ mk all >> /tmp/gefsbuild.log
+ echo save trace >> /srv/gefs.test.cmd
+ echo check >> /srv/gefs.test.cmd
+}}
+
+fn frobsnap {@{
+ rfork ne
+ sleep 1; echo snap main x >> /srv/gefs.test.cmd
+ sleep 1; dd -if /dev/zero -of /n/gefs/file0 -bs 16k -count 128
+ sleep 1; echo snap main y >> /srv/gefs.test.cmd;
+ sleep 1; dd -if /dev/zero -of /n/gefs/file1 -bs 16k -count 128
+ sleep 1; echo snap main z >> /srv/gefs.test.cmd;
+ sleep 1; rm /n/gefs/^(file0 file1);
+ sleep 1; echo snap -d y >> /srv/gefs.test.cmd;
+ sleep 1; echo check >> /srv/gefs.test.cmd
+ sleep 1; echo snap -d z >> /srv/gefs.test.cmd;
+ sleep 1; echo check >> /srv/gefs.test.cmd
+ sleep 1; echo snap -d x >> /srv/gefs.test.cmd;
+ sleep 1; echo check >> /srv/gefs.test.cmd
+}}
+
+fn buildgo {@{
+ rfork ne
+ GOROOT=/n/gefs/go
+ GOROOT_BOOTSTRAP=/n/gefs/go-plan9-amd64-bootstrap
+ go=go1.17.13-plan9-$cputype-bootstrap
+
+ cd /n/gefs
+ if(! test -e /tmp/$go.tbz){
+ echo getting https://9legacy.org/download/go/$go.tbz ...
+ hget -o /tmp/$go.tbz https://9legacy.org/download/go/$go.tbz
+ }
+ if(! test -e $GOROOT_BOOTSTRAP){
+ echo extracting /tmp/$go.tbz ...
+ bunzip2 -c /tmp/$go.tbz | tar x >[2]/dev/null
+ }
+ mkdir go
+ mkdir tmpw
+ dircp go-plan9-amd64-bootstrap go
+ bind -c tmp /tmp
+ cd go/src
+ ./all.rc
+}}
+
+fn buildgefs {@{
+ cd /n/gefs
+ if(! test -e gefs)
+ git/clone $home/src/gefs
+ cd gefs
+ mk clean > /tmp/gefsbuild.log
+ mk all > /tmp/gefsbuild.log
+ echo check >> /srv/gefs.test.cmd
+}}
+
+fn buildgefs_slowrep {
+ for(i in `{seq $1}){
+ echo @@ buildgefs $i
+ buildgefs
+ sleep 10
+ }
+}
+
+fn fillfs {
+ dd -if /dev/zero -of /n/gefs/stuff
+}
+
+fn dotest {
+ rm -f /tmp/gefs.log /tmp/gefsbuild.log
+ echo $*
+ $* || die $status
+}
+
+if(! test -e $dev)
+ dd -if /dev/zero -of $dev -bs 1kk -count 2k
+rm -f /srv/gefs.test /srv/gefs.test.cmd /srv/replay
+mk all
+@{cd test && mk all}
+
+dotest ge_replay frobsnap
+dotest ge_replay buildgefs_slowrep 50
+dotest ge_ok buildsys
+dotest ge_ok fillfs
+
+# disabled by default: go doesn't fit into a
+# small fs; make a bigger one for testing.
+# dotest ge_ok buildgo
--
⑨