randtest.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <venti.h>
  4. #include <libsec.h>
  5. #include <thread.h>
  6. enum { STACK = 32768 };
  7. void xxxsrand(long);
  8. long xxxlrand(void);
  9. Channel *cw;
  10. Channel *cr;
  11. char *host;
  12. int blocksize, seed, randpct;
  13. int doread, dowrite, packets, permute;
  14. vlong totalbytes, cur;
  15. VtConn *z;
  16. int multi;
  17. int maxpackets;
  18. int sequence;
  19. int doublecheck = 1;
  20. uint *order;
  21. void
  22. usage(void)
  23. {
  24. fprint(2, "usage: randtest [-q] [-h host] [-s seed] [-b blocksize] [-p randpct] [-n totalbytes] [-M maxblocks] [-P] [-r] [-w]\n");
  25. threadexitsall("usage");
  26. }
  27. void
  28. wr(char *buf, char *buf2)
  29. {
  30. uchar score[VtScoreSize], score2[VtScoreSize];
  31. DigestState ds;
  32. USED(buf2);
  33. memset(&ds, 0, sizeof ds);
  34. if(doublecheck)
  35. sha1((uchar*)buf, blocksize, score, &ds);
  36. if(vtwrite(z, score2, VtDataType, (uchar*)buf, blocksize) < 0)
  37. sysfatal("vtwrite %V at %,lld: %r", score, cur);
  38. if(doublecheck && memcmp(score, score2, VtScoreSize) != 0)
  39. sysfatal("score mismatch! %V %V", score, score2);
  40. }
  41. void
  42. wrthread(void *v)
  43. {
  44. char *p;
  45. USED(v);
  46. while((p = recvp(cw)) != nil){
  47. wr(p, nil);
  48. free(p);
  49. }
  50. }
  51. void
  52. rd(char *buf, char *buf2)
  53. {
  54. uchar score[VtScoreSize];
  55. DigestState ds;
  56. memset(&ds, 0, sizeof ds);
  57. sha1((uchar*)buf, blocksize, score, &ds);
  58. if(vtread(z, score, VtDataType, (uchar*)buf2, blocksize) < 0)
  59. sysfatal("vtread %V at %,lld: %r", score, cur);
  60. if(memcmp(buf, buf2, blocksize) != 0)
  61. sysfatal("bad data read! %V", score);
  62. }
  63. void
  64. rdthread(void *v)
  65. {
  66. char *p, *buf2;
  67. buf2 = vtmalloc(blocksize);
  68. USED(v);
  69. while((p = recvp(cr)) != nil){
  70. rd(p, buf2);
  71. free(p);
  72. }
  73. }
  74. char *template;
  75. void
  76. run(void (*fn)(char*, char*), Channel *c)
  77. {
  78. int i, t, j, packets;
  79. char *buf2, *buf;
  80. buf2 = vtmalloc(blocksize);
  81. buf = vtmalloc(blocksize);
  82. cur = 0;
  83. packets = totalbytes/blocksize;
  84. if(maxpackets == 0)
  85. maxpackets = packets;
  86. order = vtmalloc(packets*sizeof order[0]);
  87. for(i=0; i<packets; i++)
  88. order[i] = i;
  89. if(permute){
  90. for(i=1; i<packets; i++){
  91. j = nrand(i+1);
  92. t = order[i];
  93. order[i] = order[j];
  94. order[j] = t;
  95. }
  96. }
  97. for(i=0; i<packets && i<maxpackets; i++){
  98. memmove(buf, template, blocksize);
  99. *(uint*)buf = order[i];
  100. if(c){
  101. sendp(c, buf);
  102. buf = vtmalloc(blocksize);
  103. }else
  104. (*fn)(buf, buf2);
  105. cur += blocksize;
  106. }
  107. free(order);
  108. }
  109. #define TWID64 ((u64int)~(u64int)0)
  110. u64int
  111. unittoull(char *s)
  112. {
  113. char *es;
  114. u64int n;
  115. if(s == nil)
  116. return TWID64;
  117. n = strtoul(s, &es, 0);
  118. if(*es == 'k' || *es == 'K'){
  119. n *= 1024;
  120. es++;
  121. }else if(*es == 'm' || *es == 'M'){
  122. n *= 1024*1024;
  123. es++;
  124. }else if(*es == 'g' || *es == 'G'){
  125. n *= 1024*1024*1024;
  126. es++;
  127. }else if(*es == 't' || *es == 'T'){
  128. n *= 1024*1024;
  129. n *= 1024*1024;
  130. }
  131. if(*es != '\0')
  132. return TWID64;
  133. return n;
  134. }
  135. void
  136. threadmain(int argc, char *argv[])
  137. {
  138. int i, max;
  139. vlong t0;
  140. double t;
  141. blocksize = 8192;
  142. seed = 0;
  143. randpct = 50;
  144. host = nil;
  145. doread = 0;
  146. dowrite = 0;
  147. totalbytes = 1*1024*1024*1024;
  148. fmtinstall('V', vtscorefmt);
  149. fmtinstall('F', vtfcallfmt);
  150. ARGBEGIN{
  151. case 'b':
  152. blocksize = unittoull(EARGF(usage()));
  153. break;
  154. case 'h':
  155. host = EARGF(usage());
  156. break;
  157. case 'M':
  158. maxpackets = unittoull(EARGF(usage()));
  159. break;
  160. case 'm':
  161. multi = atoi(EARGF(usage()));
  162. break;
  163. case 'n':
  164. totalbytes = unittoull(EARGF(usage()));
  165. break;
  166. case 'p':
  167. randpct = atoi(EARGF(usage()));
  168. break;
  169. case 'P':
  170. permute = 1;
  171. break;
  172. case 'S':
  173. doublecheck = 0;
  174. ventidoublechecksha1 = 0;
  175. break;
  176. case 's':
  177. seed = atoi(EARGF(usage()));
  178. break;
  179. case 'r':
  180. doread = 1;
  181. break;
  182. case 'w':
  183. dowrite = 1;
  184. break;
  185. case 'V':
  186. chattyventi++;
  187. break;
  188. default:
  189. usage();
  190. }ARGEND
  191. if(doread==0 && dowrite==0){
  192. doread = 1;
  193. dowrite = 1;
  194. }
  195. z = vtdial(host);
  196. if(z == nil)
  197. sysfatal("could not connect to server: %r");
  198. if(vtconnect(z) < 0)
  199. sysfatal("vtconnect: %r");
  200. if(multi){
  201. cr = chancreate(sizeof(void*), 0);
  202. cw = chancreate(sizeof(void*), 0);
  203. for(i=0; i<multi; i++){
  204. proccreate(wrthread, nil, STACK);
  205. proccreate(rdthread, nil, STACK);
  206. }
  207. }
  208. template = vtmalloc(blocksize);
  209. xxxsrand(seed);
  210. max = (256*randpct)/100;
  211. if(max == 0)
  212. max = 1;
  213. for(i=0; i<blocksize; i++)
  214. template[i] = xxxlrand()%max;
  215. if(dowrite){
  216. t0 = nsec();
  217. run(wr, cw);
  218. for(i=0; i<multi; i++)
  219. sendp(cw, nil);
  220. t = (nsec() - t0)/1.e9;
  221. print("write: %lld bytes / %.3f seconds = %.6f MB/s\n",
  222. totalbytes, t, (double)totalbytes/1e6/t);
  223. }
  224. if(doread){
  225. t0 = nsec();
  226. run(rd, cr);
  227. for(i=0; i<multi; i++)
  228. sendp(cr, nil);
  229. t = (nsec() - t0)/1.e9;
  230. print("read: %lld bytes / %.3f seconds = %.6f MB/s\n",
  231. totalbytes, t, (double)totalbytes/1e6/t);
  232. }
  233. threadexitsall(nil);
  234. }
  235. /*
  236. * algorithm by
  237. * D. P. Mitchell & J. A. Reeds
  238. */
  239. #define LEN 607
  240. #define TAP 273
  241. #define MASK 0x7fffffffL
  242. #define A 48271
  243. #define M 2147483647
  244. #define Q 44488
  245. #define R 3399
  246. #define NORM (1.0/(1.0+MASK))
  247. static ulong rng_vec[LEN];
  248. static ulong* rng_tap = rng_vec;
  249. static ulong* rng_feed = 0;
  250. static void
  251. isrand(long seed)
  252. {
  253. long lo, hi, x;
  254. int i;
  255. rng_tap = rng_vec;
  256. rng_feed = rng_vec+LEN-TAP;
  257. seed = seed%M;
  258. if(seed < 0)
  259. seed += M;
  260. if(seed == 0)
  261. seed = 89482311;
  262. x = seed;
  263. /*
  264. * Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1)
  265. */
  266. for(i = -20; i < LEN; i++) {
  267. hi = x / Q;
  268. lo = x % Q;
  269. x = A*lo - R*hi;
  270. if(x < 0)
  271. x += M;
  272. if(i >= 0)
  273. rng_vec[i] = x;
  274. }
  275. }
  276. void
  277. xxxsrand(long seed)
  278. {
  279. isrand(seed);
  280. }
  281. long
  282. xxxlrand(void)
  283. {
  284. ulong x;
  285. rng_tap--;
  286. if(rng_tap < rng_vec) {
  287. if(rng_feed == 0) {
  288. isrand(1);
  289. rng_tap--;
  290. }
  291. rng_tap += LEN;
  292. }
  293. rng_feed--;
  294. if(rng_feed < rng_vec)
  295. rng_feed += LEN;
  296. x = (*rng_feed + *rng_tap) & MASK;
  297. *rng_feed = x;
  298. return x;
  299. }