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