blob: 7d94eef2c898c27e48844fe900700302dbf32cfb [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <venti.h>
#include <libsec.h>
#include <thread.h>
enum { STACK = 32768 };
void xxxsrand(long);
long xxxlrand(void);
Channel *cw;
Channel *cr;
char *host;
int blocksize, seed, randpct;
int doread, dowrite, packets, permute;
vlong totalbytes, cur;
VtConn *z;
int multi;
int maxpackets;
int sequence;
int doublecheck = 1;
uint *order;
void
usage(void)
{
fprint(2, "usage: randtest [-q] [-h host] [-s seed] [-b blocksize] [-p randpct] [-n totalbytes] [-M maxblocks] [-P] [-r] [-w]\n");
threadexitsall("usage");
}
void
wr(char *buf, char *buf2)
{
uchar score[VtScoreSize], score2[VtScoreSize];
DigestState ds;
USED(buf2);
memset(&ds, 0, sizeof ds);
if(doublecheck)
sha1((uchar*)buf, blocksize, score, &ds);
if(vtwrite(z, score2, VtDataType, (uchar*)buf, blocksize) < 0)
sysfatal("vtwrite %V at %,lld: %r", score, cur);
if(doublecheck && memcmp(score, score2, VtScoreSize) != 0)
sysfatal("score mismatch! %V %V", score, score2);
}
void
wrthread(void *v)
{
char *p;
USED(v);
while((p = recvp(cw)) != nil){
wr(p, nil);
free(p);
}
}
void
rd(char *buf, char *buf2)
{
uchar score[VtScoreSize];
DigestState ds;
memset(&ds, 0, sizeof ds);
sha1((uchar*)buf, blocksize, score, &ds);
if(vtread(z, score, VtDataType, (uchar*)buf2, blocksize) < 0)
sysfatal("vtread %V at %,lld: %r", score, cur);
if(memcmp(buf, buf2, blocksize) != 0)
sysfatal("bad data read! %V", score);
}
void
rdthread(void *v)
{
char *p, *buf2;
buf2 = vtmalloc(blocksize);
USED(v);
while((p = recvp(cr)) != nil){
rd(p, buf2);
free(p);
}
}
char *template;
void
run(void (*fn)(char*, char*), Channel *c)
{
int i, t, j, packets;
char *buf2, *buf;
buf2 = vtmalloc(blocksize);
buf = vtmalloc(blocksize);
cur = 0;
packets = totalbytes/blocksize;
if(maxpackets > 0 && maxpackets < packets)
packets = maxpackets;
totalbytes = (vlong)packets * blocksize;
order = vtmalloc(packets*sizeof order[0]);
for(i=0; i<packets; i++)
order[i] = i;
if(permute){
for(i=1; i<packets; i++){
j = nrand(i+1);
t = order[i];
order[i] = order[j];
order[j] = t;
}
}
for(i=0; i<packets; i++){
memmove(buf, template, blocksize);
*(uint*)buf = order[i];
if(c){
sendp(c, buf);
buf = vtmalloc(blocksize);
}else
(*fn)(buf, buf2);
cur += blocksize;
}
free(order);
}
#define TWID64 ((u64int)~(u64int)0)
u64int
unittoull(char *s)
{
char *es;
u64int n;
if(s == nil)
return TWID64;
n = strtoul(s, &es, 0);
if(*es == 'k' || *es == 'K'){
n *= 1024;
es++;
}else if(*es == 'm' || *es == 'M'){
n *= 1024*1024;
es++;
}else if(*es == 'g' || *es == 'G'){
n *= 1024*1024*1024;
es++;
}else if(*es == 't' || *es == 'T'){
n *= 1024*1024;
n *= 1024*1024;
}
if(*es != '\0')
return TWID64;
return n;
}
void
threadmain(int argc, char *argv[])
{
int i, max;
vlong t0;
double t;
blocksize = 8192;
seed = 0;
randpct = 50;
host = nil;
doread = 0;
dowrite = 0;
totalbytes = 1*1024*1024*1024;
fmtinstall('V', vtscorefmt);
fmtinstall('F', vtfcallfmt);
ARGBEGIN{
case 'b':
blocksize = unittoull(EARGF(usage()));
break;
case 'h':
host = EARGF(usage());
break;
case 'M':
maxpackets = unittoull(EARGF(usage()));
break;
case 'm':
multi = atoi(EARGF(usage()));
break;
case 'n':
totalbytes = unittoull(EARGF(usage()));
break;
case 'p':
randpct = atoi(EARGF(usage()));
break;
case 'P':
permute = 1;
break;
case 'S':
doublecheck = 0;
ventidoublechecksha1 = 0;
break;
case 's':
seed = atoi(EARGF(usage()));
break;
case 'r':
doread = 1;
break;
case 'w':
dowrite = 1;
break;
case 'V':
chattyventi++;
break;
default:
usage();
}ARGEND
if(doread==0 && dowrite==0){
doread = 1;
dowrite = 1;
}
z = vtdial(host);
if(z == nil)
sysfatal("could not connect to server: %r");
if(vtconnect(z) < 0)
sysfatal("vtconnect: %r");
if(multi){
cr = chancreate(sizeof(void*), 0);
cw = chancreate(sizeof(void*), 0);
for(i=0; i<multi; i++){
proccreate(wrthread, nil, STACK);
proccreate(rdthread, nil, STACK);
}
}
template = vtmalloc(blocksize);
xxxsrand(seed);
max = (256*randpct)/100;
if(max == 0)
max = 1;
for(i=0; i<blocksize; i++)
template[i] = xxxlrand()%max;
if(dowrite){
t0 = nsec();
run(wr, cw);
for(i=0; i<multi; i++)
sendp(cw, nil);
t = (nsec() - t0)/1.e9;
print("write: %lld bytes / %.3f seconds = %.6f MB/s\n",
totalbytes, t, (double)totalbytes/1e6/t);
}
if(doread){
t0 = nsec();
run(rd, cr);
for(i=0; i<multi; i++)
sendp(cr, nil);
t = (nsec() - t0)/1.e9;
print("read: %lld bytes / %.3f seconds = %.6f MB/s\n",
totalbytes, t, (double)totalbytes/1e6/t);
}
threadexitsall(nil);
}
/*
* algorithm by
* D. P. Mitchell & J. A. Reeds
*/
#define LEN 607
#define TAP 273
#define MASK 0x7fffffffL
#define A 48271
#define M 2147483647
#define Q 44488
#define R 3399
#define NORM (1.0/(1.0+MASK))
static ulong rng_vec[LEN];
static ulong* rng_tap = rng_vec;
static ulong* rng_feed = 0;
static void
isrand(long seed)
{
long lo, hi, x;
int i;
rng_tap = rng_vec;
rng_feed = rng_vec+LEN-TAP;
seed = seed%M;
if(seed < 0)
seed += M;
if(seed == 0)
seed = 89482311;
x = seed;
/*
* Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1)
*/
for(i = -20; i < LEN; i++) {
hi = x / Q;
lo = x % Q;
x = A*lo - R*hi;
if(x < 0)
x += M;
if(i >= 0)
rng_vec[i] = x;
}
}
void
xxxsrand(long seed)
{
isrand(seed);
}
long
xxxlrand(void)
{
ulong x;
rng_tap--;
if(rng_tap < rng_vec) {
if(rng_feed == 0) {
isrand(1);
rng_tap--;
}
rng_tap += LEN;
}
rng_feed--;
if(rng_feed < rng_vec)
rng_feed += LEN;
x = (*rng_feed + *rng_tap) & MASK;
*rng_feed = x;
return x;
}