|  | #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; | 
|  | } | 
|  |  |