ref: f22e05c866913e608b0630d40d33634aebcaf188
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); }