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