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