ref: 4cff2af5a4ff459f67aaa9cadf56913171891f95
dir: /fsbench-par.c/
#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);
}