shithub: getest

ref: f22e05c866913e608b0630d40d33634aebcaf188
dir: /fsbench-par.c/

View raw version
#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);
}