#include <u.h>#include <libc.h>#include <libsec.h>/* ori disk throughput script17:54 < ori> single proc random reads with the test program => 130 megs/sec17:54 < h9ro> ah, that wasn't clear17:54 < ori> gefs => 50 megs/sec17:54 < h9ro> ok, then you're right of course :)17:55 < ori> no, gefs doesn't do parallel reads, but it clearly does something dumb.17:55 < h9ro> if your random offsets are ok and same blocksize...17:55 < ori> oh. that's actually a good thing to check.17:55 < ori> I should make sure that the offsets ARE aligned.17:55 < ori> pretty sure they are.17:55 < ori> but it'd be dumb if I'm wrong.17:55 < h9ro> try some really big alignments17:55 < h9ro> just in case17:55 < h9ro> you never know how dumb the SSD is!!!17:56 < h9ro> maybe make a test to find the internal ssd blocksizes17:56 < ori> yeah, but the test program is doing the same alignments I *think* I'm doing in gefs.17:56 < h9ro> and the ssd might have implemented readahead17:56 < ori> no worries. I'll figure it out.20:10 < ori> when you have multiple procs20:11 < ori> eg, for gefs testing one of the tests I use is '{for(i in *){cat $i&}} | tput' */enum { KiB = 1024, MiB = 1024*KiB, GiB = 1024*MiB,};int nproc = 1;int iosize = 8*1024;char *order = "seq";vlong fsize = 0;int fd;char *buf;vlong nbytes = 0;long (*iofn)(int, void*, long, vlong);voidusage(void){ fprint(2, "usage: %s [-p procs] [-s iosize] [-o order] path\n", argv0); exits("usage");}voidinc64(vlong *v, vlong dv){ vlong ov, nv; while(1){ ov = *v; nv = ov + dv; extern int cas64(u64int*, u64int, u64int); if(cas64((u64int*)v, ov, nv)) break; }}vlongseq(vlong off){ return off + iosize;}vlongskip(vlong off){ return off + 2*iosize;}vlongrandoff(vlong off){ return (fastrand()<<32)|fastrand();}voidio(vlong (*next)(vlong)){ vlong off = 0; while(1){ pwrite(fd, buf, iosize, off); inc64(&nbytes, iosize); off = next(off); if(off > fsize + iosize) off -= fsize; off -= off % iosize; }}voidshowstats(void){ double speed; int sec; sec = 0; while(1){ sleep(1000); sec++; speed = (double)nbytes/(double)sec; print("%lld/%d\n", nbytes, sec); if(speed > GiB) print("%f GiB/s\n", speed/GiB); else if(speed > MiB) print("%f MiB/s\n", speed/MiB); else if(speed > KiB) print("%f KiB/s\n", speed/KiB); }}voidmain(int argc, char **argv){ Dir *d; int i, pid; iofn = pwrite; ARGBEGIN{ case 'p': nproc = atoi(EARGF(usage())); break; case 's': iosize = atoi(EARGF(usage())); break; case 'o': order = EARGF(usage()); break; case 'r': iofn = pread; break; default: usage(); break; }ARGEND; if(argc != 1) usage(); if((fd = open(argv[0], OWRITE)) == -1) sysfatal("open %s: %r", argv[0]); if((d = dirfstat(fd)) == nil) sysfatal("stat %s: %r", argv[0]); if((buf = malloc(iosize)) == nil) sysfatal("alloc buf: %r"); fsize = d->length; for(i = 0; i < nproc; i++){ if((pid = rfork(RFPROC|RFMEM)) == -1) sysfatal("rfork: %r"); if(pid == 0){ if(strcmp(order, "seq") == 0) io(seq); else if(strcmp(order, "skip") == 0) io(skip); else if(strcmp(order, "rand") == 0) io(randoff); else sysfatal("unknown order %s\n", order); exits(nil); } } showstats(); exits(nil);}
#include <u.h>
#include <libc.h>
#include <libsec.h>
/*
ori disk throughput script
17:54 < ori> single proc random reads with the test program => 130 megs/sec
17:54 < h9ro> ah, that wasn't clear
17:54 < ori> gefs => 50 megs/sec
17:54 < h9ro> ok, then you're right of course :)
17:55 < ori> no, gefs doesn't do parallel reads, but it clearly does something dumb.
17:55 < h9ro> if your random offsets are ok and same blocksize...
17:55 < ori> oh. that's actually a good thing to check.
17:55 < ori> I should make sure that the offsets ARE aligned.
17:55 < ori> pretty sure they are.
17:55 < ori> but it'd be dumb if I'm wrong.
17:55 < h9ro> try some really big alignments
17:55 < h9ro> just in case
17:55 < h9ro> you never know how dumb the SSD is!!!
17:56 < h9ro> maybe make a test to find the internal ssd blocksizes
17:56 < ori> yeah, but the test program is doing the same alignments I *think* I'm doing in gefs.
17:56 < h9ro> and the ssd might have implemented readahead
17:56 < ori> no worries. I'll figure it out.
20:10 < ori> when you have multiple procs
20:11 < ori> eg, for gefs testing one of the tests I use is '{for(i in *){cat $i&}} | tput'
*/
enum {
KiB = 1024,
MiB = 1024*KiB,
GiB = 1024*MiB,
};
int nproc = 1;
int iosize = 8*1024;
char *order = "seq";
vlong fsize = 0;
int fd;
char *buf;
vlong nbytes = 0;
long (*iofn)(int, void*, long, vlong);
void
usage(void)
{
fprint(2, "usage: %s [-p procs] [-s iosize] [-o order] path\n", argv0);
exits("usage");
}
void
inc64(vlong *v, vlong dv)
{
vlong ov, nv;
while(1){
ov = *v;
nv = ov + dv;
extern int cas64(u64int*, u64int, u64int);
if(cas64((u64int*)v, ov, nv))
break;
}
}
vlong
seq(vlong off)
{
return off + iosize;
}
vlong
skip(vlong off)
{
return off + 2*iosize;
}
vlong
randoff(vlong off)
{
return (fastrand()<<32)|fastrand();
}
void
io(vlong (*next)(vlong))
{
vlong off = 0;
while(1){
pwrite(fd, buf, iosize, off);
inc64(&nbytes, iosize);
off = next(off);
if(off > fsize + iosize)
off -= fsize;
off -= off % iosize;
}
}
void
showstats(void)
{
double speed;
int sec;
sec = 0;
while(1){
sleep(1000);
sec++;
speed = (double)nbytes/(double)sec;
print("%lld/%d\n", nbytes, sec);
if(speed > GiB)
print("%f GiB/s\n", speed/GiB);
else if(speed > MiB)
print("%f MiB/s\n", speed/MiB);
else if(speed > KiB)
print("%f KiB/s\n", speed/KiB);
}
}
void
main(int argc, char **argv)
{
Dir *d;
int i, pid;
iofn = pwrite;
ARGBEGIN{
case 'p':
nproc = atoi(EARGF(usage()));
break;
case 's':
iosize = atoi(EARGF(usage()));
break;
case 'o':
order = EARGF(usage());
break;
case 'r':
iofn = pread;
break;
default:
usage();
break;
}ARGEND;
if(argc != 1)
usage();
if((fd = open(argv[0], OWRITE)) == -1)
sysfatal("open %s: %r", argv[0]);
if((d = dirfstat(fd)) == nil)
sysfatal("stat %s: %r", argv[0]);
if((buf = malloc(iosize)) == nil)
sysfatal("alloc buf: %r");
fsize = d->length;
for(i = 0; i < nproc; i++){
if((pid = rfork(RFPROC|RFMEM)) == -1)
sysfatal("rfork: %r");
if(pid == 0){
if(strcmp(order, "seq") == 0)
io(seq);
else if(strcmp(order, "skip") == 0)
io(skip);
else if(strcmp(order, "rand") == 0)
io(randoff);
else
sysfatal("unknown order %s\n", order);
exits(nil);
}
}
showstats();
exits(nil);
}