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 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 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 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 * 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 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 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 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 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 246 void cachequiet(int quiet) 247 { 248 quietflag = quiet; 249 } 250 251