xref: /minix3/minix/tests/testcache.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* A general i/o consistency test library. It performs i/o
2*433d6423SLionel Sambuc  * using functions provided by the client (readblock, dowriteblock)
3*433d6423SLionel Sambuc  * with a working set size specified by the client. It checks that
4*433d6423SLionel Sambuc  * blocks that were written have the same contents when later read,
5*433d6423SLionel Sambuc  * using different access patterns. The assumption is the various
6*433d6423SLionel Sambuc  * cache layers so exercised are forced into many different states
7*433d6423SLionel Sambuc  * (reordering, eviction, etc), hopefully triggering bugs if present.
8*433d6423SLionel Sambuc  *
9*433d6423SLionel Sambuc  * Entry point: dotest()
10*433d6423SLionel Sambuc  */
11*433d6423SLionel Sambuc 
12*433d6423SLionel Sambuc #include <sys/types.h>
13*433d6423SLionel Sambuc #include <sys/ioc_memory.h>
14*433d6423SLionel Sambuc #include <stdio.h>
15*433d6423SLionel Sambuc #include <assert.h>
16*433d6423SLionel Sambuc #include <string.h>
17*433d6423SLionel Sambuc #include <stdlib.h>
18*433d6423SLionel Sambuc #include <unistd.h>
19*433d6423SLionel Sambuc #include <fcntl.h>
20*433d6423SLionel Sambuc 
21*433d6423SLionel Sambuc #include "testcache.h"
22*433d6423SLionel Sambuc #include "common.h"
23*433d6423SLionel Sambuc 
24*433d6423SLionel Sambuc extern int quietflag;
25*433d6423SLionel Sambuc 
26*433d6423SLionel Sambuc int fds[MAXFILES];
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc static void
genblock(int b,char * blockdata,int blocksize,u32_t seed)29*433d6423SLionel Sambuc genblock(int b, char *blockdata, int blocksize, u32_t seed)
30*433d6423SLionel Sambuc {
31*433d6423SLionel Sambuc 	u32_t *p = (u32_t *) blockdata,
32*433d6423SLionel Sambuc 		*plimit = (u32_t *) (blockdata + blocksize),
33*433d6423SLionel Sambuc 		i = 0;
34*433d6423SLionel Sambuc 
35*433d6423SLionel Sambuc 	srandom(seed ^ b);
36*433d6423SLionel Sambuc 
37*433d6423SLionel Sambuc 	for(p = (u32_t *) blockdata; p < plimit; p++) {
38*433d6423SLionel Sambuc 		i++;
39*433d6423SLionel Sambuc 		*p = random();
40*433d6423SLionel Sambuc 	}
41*433d6423SLionel Sambuc }
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc static int
checkblock(int b,int blocksize,u32_t seed)44*433d6423SLionel Sambuc checkblock(int b, int blocksize, u32_t seed)
45*433d6423SLionel Sambuc {
46*433d6423SLionel Sambuc 	static char data[MAXBLOCKSIZE], expected_data[MAXBLOCKSIZE];
47*433d6423SLionel Sambuc 	int r;
48*433d6423SLionel Sambuc 
49*433d6423SLionel Sambuc 	genblock(b, expected_data, blocksize, seed);
50*433d6423SLionel Sambuc 
51*433d6423SLionel Sambuc 	r = readblock(b, blocksize, seed, data);
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc 	if(r == OK_BLOCK_GONE) { return 0; }
54*433d6423SLionel Sambuc 
55*433d6423SLionel Sambuc 	if(r != blocksize) {
56*433d6423SLionel Sambuc 		fprintf(stderr, "readblock failed\n");
57*433d6423SLionel Sambuc 		return 1;
58*433d6423SLionel Sambuc 	}
59*433d6423SLionel Sambuc 
60*433d6423SLionel Sambuc 	if(memcmp(expected_data, data, blocksize)) {
61*433d6423SLionel Sambuc 		fprintf(stderr, "comparison of %d failed\n", b);
62*433d6423SLionel Sambuc 		return 1;
63*433d6423SLionel Sambuc 	}
64*433d6423SLionel Sambuc 
65*433d6423SLionel Sambuc 	return 0;
66*433d6423SLionel Sambuc }
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc static int
writeblock(int b,int blocksize,u32_t seed)69*433d6423SLionel Sambuc writeblock(int b, int blocksize, u32_t seed)
70*433d6423SLionel Sambuc {
71*433d6423SLionel Sambuc 	static char data[MAXBLOCKSIZE];
72*433d6423SLionel Sambuc 
73*433d6423SLionel Sambuc 	genblock(b, data, blocksize, seed);
74*433d6423SLionel Sambuc 
75*433d6423SLionel Sambuc 	if(dowriteblock(b, blocksize, seed, data) != blocksize) {
76*433d6423SLionel Sambuc 		fprintf(stderr, "writeblock of %d failed\n", b);
77*433d6423SLionel Sambuc 		return 0;
78*433d6423SLionel Sambuc 	}
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc 	return blocksize;
81*433d6423SLionel Sambuc }
82*433d6423SLionel Sambuc 
83*433d6423SLionel Sambuc static int *
makepermutation(int nblocks,int * permutation)84*433d6423SLionel Sambuc makepermutation(int nblocks, int *permutation)
85*433d6423SLionel Sambuc {
86*433d6423SLionel Sambuc 	int b;
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc 	assert(nblocks > 0 && nblocks <= MAXBLOCKS);
89*433d6423SLionel Sambuc 
90*433d6423SLionel Sambuc 	for(b = 0; b < nblocks; b++) permutation[b] = b;
91*433d6423SLionel Sambuc 
92*433d6423SLionel Sambuc 	for(b = 0; b < nblocks-1; b++) {
93*433d6423SLionel Sambuc 		int s, other = b + random() % (nblocks - b - 1);
94*433d6423SLionel Sambuc 		assert(other >= b && other < nblocks);
95*433d6423SLionel Sambuc 		s = permutation[other];
96*433d6423SLionel Sambuc 		permutation[other] = permutation[b];
97*433d6423SLionel Sambuc 		permutation[b] = s;
98*433d6423SLionel Sambuc 	}
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc 	return permutation;
101*433d6423SLionel Sambuc }
102*433d6423SLionel Sambuc 
103*433d6423SLionel Sambuc static int
checkblocks(int nblocks,int blocksize,u32_t seed)104*433d6423SLionel Sambuc checkblocks(int nblocks, int blocksize, u32_t seed)
105*433d6423SLionel Sambuc {
106*433d6423SLionel Sambuc 	int b;
107*433d6423SLionel Sambuc 	int nrandom = nblocks * 3;
108*433d6423SLionel Sambuc 	static int perm1[MAXBLOCKS];
109*433d6423SLionel Sambuc 
110*433d6423SLionel Sambuc 	if(!quietflag) { fprintf(stderr, "\nverifying "); fflush(stderr); }
111*433d6423SLionel Sambuc 
112*433d6423SLionel Sambuc 	makepermutation(nblocks, perm1);
113*433d6423SLionel Sambuc 
114*433d6423SLionel Sambuc 	assert(nblocks > 0 && nblocks <= MAXBLOCKS);
115*433d6423SLionel Sambuc 	assert(blocksize > 0 && blocksize <= MAXBLOCKSIZE);
116*433d6423SLionel Sambuc 
117*433d6423SLionel Sambuc 	for(b = 0; b < nblocks; b++) {
118*433d6423SLionel Sambuc 		if(checkblock(b, blocksize, seed)) { return 1; }
119*433d6423SLionel Sambuc 	}
120*433d6423SLionel Sambuc 
121*433d6423SLionel Sambuc 	for(b = 0; b < nrandom; b++) {
122*433d6423SLionel Sambuc 		if(checkblock(random() % nblocks, blocksize, seed)) { return 1; }
123*433d6423SLionel Sambuc 	}
124*433d6423SLionel Sambuc 
125*433d6423SLionel Sambuc 	for(b = 0; b < nblocks; b++) {
126*433d6423SLionel Sambuc 		if(checkblock(b, blocksize, seed)) { return 1; }
127*433d6423SLionel Sambuc 	}
128*433d6423SLionel Sambuc 
129*433d6423SLionel Sambuc 	for(b = 0; b < nblocks; b++) {
130*433d6423SLionel Sambuc 		if(checkblock(perm1[b], blocksize, seed)) { return 1; }
131*433d6423SLionel Sambuc 	}
132*433d6423SLionel Sambuc 
133*433d6423SLionel Sambuc 	if(!quietflag) { fprintf(stderr, "done\n"); }
134*433d6423SLionel Sambuc 
135*433d6423SLionel Sambuc 	return 0;
136*433d6423SLionel Sambuc }
137*433d6423SLionel Sambuc 
138*433d6423SLionel Sambuc int
dotest(int blocksize,int nblocks,int iterations)139*433d6423SLionel Sambuc dotest(int blocksize, int nblocks, int iterations)
140*433d6423SLionel Sambuc {
141*433d6423SLionel Sambuc 	int b, i;
142*433d6423SLionel Sambuc 	int nrandom = nblocks * iterations;
143*433d6423SLionel Sambuc 	static int perm1[MAXBLOCKS], perm2[MAXBLOCKS];
144*433d6423SLionel Sambuc 	static int newblock[MAXBLOCKS];
145*433d6423SLionel Sambuc 	u32_t seed = random(), newseed;
146*433d6423SLionel Sambuc 	int mb;
147*433d6423SLionel Sambuc 
148*433d6423SLionel Sambuc 	assert(nblocks > 0 && nblocks <= MAXBLOCKS);
149*433d6423SLionel Sambuc 
150*433d6423SLionel Sambuc 	mb = (int) ((u64_t) blocksize * nblocks / 1024 / 1024);
151*433d6423SLionel Sambuc 
152*433d6423SLionel Sambuc 	if(!quietflag) { fprintf(stderr, "test: %d * %d = %dMB\n", blocksize, nblocks, mb); }
153*433d6423SLionel Sambuc 
154*433d6423SLionel Sambuc 	for(b = 0; b < nblocks; b++) {
155*433d6423SLionel Sambuc 		if(writeblock(b, blocksize, seed) < blocksize) { return 1; }
156*433d6423SLionel Sambuc 		if(checkblock(b, blocksize, seed)) { return 1; }
157*433d6423SLionel Sambuc 		printprogress("writing sequential", b, nblocks);
158*433d6423SLionel Sambuc 	}
159*433d6423SLionel Sambuc 
160*433d6423SLionel Sambuc 	if(checkblocks(nblocks, blocksize, seed)) { return 1; }
161*433d6423SLionel Sambuc 
162*433d6423SLionel Sambuc 	makepermutation(nblocks, perm1);
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc 	for(b = 0; b < nblocks; b++) {
165*433d6423SLionel Sambuc 		if(writeblock(perm1[b], blocksize, seed) < blocksize) { return 1; }
166*433d6423SLionel Sambuc 		if(checkblock(perm1[b], blocksize, seed)) { return 1; }
167*433d6423SLionel Sambuc 		printprogress("writing permutation", b, nblocks);
168*433d6423SLionel Sambuc 	}
169*433d6423SLionel Sambuc 
170*433d6423SLionel Sambuc 	if(checkblocks(nblocks, blocksize, seed)) { return 1; }
171*433d6423SLionel Sambuc 
172*433d6423SLionel Sambuc 	for(i = 0; i < iterations; i++) {
173*433d6423SLionel Sambuc 		makepermutation(nblocks, perm1);
174*433d6423SLionel Sambuc 		makepermutation(nblocks, perm2);
175*433d6423SLionel Sambuc 		memset(newblock, 0, sizeof(newblock));
176*433d6423SLionel Sambuc 
177*433d6423SLionel Sambuc 		newseed = random();
178*433d6423SLionel Sambuc 
179*433d6423SLionel Sambuc 		if(!quietflag) { fprintf(stderr, "iteration %d/%d\n", i, iterations); }
180*433d6423SLionel Sambuc 
181*433d6423SLionel Sambuc 		for(b = 0; b < nblocks; b++) {
182*433d6423SLionel Sambuc 			int wr = perm1[b], check = perm2[b];
183*433d6423SLionel Sambuc 			if(writeblock(wr, blocksize, newseed) < blocksize) { return 1; }
184*433d6423SLionel Sambuc 			newblock[wr] = 1;
185*433d6423SLionel Sambuc 			if(checkblock(check, blocksize, newblock[check] ? newseed : seed)) { return 1; }
186*433d6423SLionel Sambuc 			printprogress("interleaved permutation read, write", b, nblocks);
187*433d6423SLionel Sambuc 		}
188*433d6423SLionel Sambuc 
189*433d6423SLionel Sambuc 		seed = newseed;
190*433d6423SLionel Sambuc 
191*433d6423SLionel Sambuc 		if(checkblocks(nblocks, blocksize, seed)) { return 1; }
192*433d6423SLionel Sambuc 	}
193*433d6423SLionel Sambuc 
194*433d6423SLionel Sambuc 	newseed = random();
195*433d6423SLionel Sambuc 
196*433d6423SLionel Sambuc 	memset(newblock, 0, sizeof(newblock));
197*433d6423SLionel Sambuc 
198*433d6423SLionel Sambuc 	for(b = 0; b < nrandom; b++) {
199*433d6423SLionel Sambuc 		int wr = random() % nblocks, check = random() % nblocks;
200*433d6423SLionel Sambuc 		if(writeblock(wr, blocksize, newseed) < blocksize) { return 1; }
201*433d6423SLionel Sambuc 		newblock[wr] = 1;
202*433d6423SLionel Sambuc 		if(checkblock(check, blocksize,
203*433d6423SLionel Sambuc 			newblock[check] ? newseed : seed)) { return 1; }
204*433d6423SLionel Sambuc 		printprogress("1 random verify, 1 random write", b, nrandom);
205*433d6423SLionel Sambuc 	}
206*433d6423SLionel Sambuc 
207*433d6423SLionel Sambuc 	seed = newseed;
208*433d6423SLionel Sambuc 
209*433d6423SLionel Sambuc 	if(!quietflag) { fprintf(stderr, "\n"); }
210*433d6423SLionel Sambuc 	testend();
211*433d6423SLionel Sambuc 
212*433d6423SLionel Sambuc 	return 0;
213*433d6423SLionel Sambuc }
214*433d6423SLionel Sambuc 
215*433d6423SLionel Sambuc void
get_fd_offset(int b,int blocksize,u64_t * file_offset,int * fd)216*433d6423SLionel Sambuc get_fd_offset(int b, int blocksize, u64_t *file_offset, int *fd)
217*433d6423SLionel Sambuc {
218*433d6423SLionel Sambuc         u64_t offset = (u64_t) b * blocksize;
219*433d6423SLionel Sambuc         int filenumber;
220*433d6423SLionel Sambuc 
221*433d6423SLionel Sambuc         filenumber = offset / MB / MBPERFILE;
222*433d6423SLionel Sambuc 
223*433d6423SLionel Sambuc         assert(filenumber >= 0 && filenumber < MAXFILES);
224*433d6423SLionel Sambuc         assert(fds[filenumber] > 0);
225*433d6423SLionel Sambuc 
226*433d6423SLionel Sambuc         *fd = fds[filenumber];
227*433d6423SLionel Sambuc         *file_offset = offset - (filenumber * MBPERFILE * MB);
228*433d6423SLionel Sambuc }
229*433d6423SLionel Sambuc 
230*433d6423SLionel Sambuc void
makefiles(int n)231*433d6423SLionel Sambuc makefiles(int n)
232*433d6423SLionel Sambuc {
233*433d6423SLionel Sambuc 	int f;
234*433d6423SLionel Sambuc         for(f = 0; f < n; f++) {
235*433d6423SLionel Sambuc                 char tempfilename[] = "cachetest.XXXXXXXX";
236*433d6423SLionel Sambuc                 fds[f] = mkstemp(tempfilename);
237*433d6423SLionel Sambuc                 if(fds[f] < 0) {
238*433d6423SLionel Sambuc 			perror("mkstemp");
239*433d6423SLionel Sambuc 			fprintf(stderr, "mkstemp %d/%d failed\n", f, n);
240*433d6423SLionel Sambuc 			exit(1);
241*433d6423SLionel Sambuc 		}
242*433d6423SLionel Sambuc                 assert(fds[f] > 0);
243*433d6423SLionel Sambuc         }
244*433d6423SLionel Sambuc }
245*433d6423SLionel Sambuc 
cachequiet(int quiet)246*433d6423SLionel Sambuc void cachequiet(int quiet)
247*433d6423SLionel Sambuc {
248*433d6423SLionel Sambuc 	quietflag = quiet;
249*433d6423SLionel Sambuc }
250*433d6423SLionel Sambuc 
251