#include #include enum { Ios = 1000, /* number of ios / test */ Nanoi = 1000000000, /* 1/nano */ Microi = 1000000, }; enum { Read = 1<<0, Write = 1<<1, }; static int otab[4] = { [Read] OREAD, [Write] OWRITE, [Read|Write] ORDWR, }; static char *rwtab[4] = { [Read] "read", [Write] "write", [Read|Write] "rdwr", }; void rio(int fd, uvlong byte0, uvlong bytes, uint ss, int rw) { char *buf; int i; uvlong maxlba, lba, t, x; long (*io)(int, void*, long, vlong); maxlba = (bytes - byte0) / ss; if(rw == Read) io = pread; else if(rw == Write) io = pwrite; else{ io = nil; /* compiler noise */ sysfatal("not prepared to mix read/write yet"); } buf = malloc(ss); if(buf == nil) sysfatal("malloc"); srand(nsec()); t = -nsec(); for(i = 0; i < Ios; i++){ lba = frand()*maxlba; /* awful. no vlnrand() */ io(fd, buf, ss, byte0 + lba*ss); } t += nsec(); free(buf); print("%s %lld.%03lld\n", rwtab[rw], t/Nanoi, (t%Nanoi)/Microi); x = (uvlong)Ios*(uvlong)Nanoi*100; x /= t; print("%lld.%02lld iops\n", x/100, (x%100)); } void usage(void) { fprint(2, "usage: randomio [-rw] [-o offset] [-s sectorsz] [file ...]\n"); exits("usage"); } void main(int argc, char **argv) { int i, byte0, fd, rw, ss; uvlong bytes; Dir *d; rw = 0; ss = 512; byte0 = 0; ARGBEGIN{ case 'r': rw |= Read; break; case 'w': rw |= Write; break; case 'o': byte0 = atoi(EARGF(usage())); break; case 's': ss = atoi(EARGF(usage())); break; default: usage(); }ARGEND; if(rw == 0) rw = Read; for(i = 0; i < argc; i++){ d = dirstat(argv[i]); if(d == nil) sysfatal("dirstat: %r"); bytes = d->length; free(d); fd = open(argv[i], otab[rw]); if(fd == -1) sysfatal("open: %r"); if(rw & Read) rio(fd, byte0, bytes, ss, Read); if(rw & Write) rio(fd, byte0, bytes, ss, Write); close(fd); } exits(""); }