minix/test/testcache.c
Ben Gras 32a4e0d84d many new tests
. test70: regression test for m_out vfs race condition

The following tests use testcache.c to generate test i/o
patterns, generate random write data and verify the reads.

	. test71: blackbox full-stack test of FS operation, testing
	  using the regular VFS interface crazy i/o patterns
	  with various working set sizes, triggering only
	  primary cache, also secondary cache, and finally
	  disk i/o and verifying contents all the time
	. test72: unit test of libminixfs, implementing
	  functions it needs from -lsys and -lblockdriver
	  and the client in order to simulate a working
	  cache client and backend environment.
	. test73: blackbox test of secondary vm cache in isolation

Change-Id: I1287e9753182b8719e634917ad158e3c1e079ceb
2013-04-19 16:21:48 +00:00

218 lines
5 KiB
C

/* A general i/o consistency test library. It performs i/o
* using functions provided by the client (readblock, dowriteblock)
* with a working set size specified by the client. It checks that
* blocks that were written have the same contents when later read,
* using different access patterns. The assumption is the various
* cache layers so exercised are forced into many different states
* (reordering, eviction, etc), hopefully triggering bugs if present.
*
* Entry point: dotest()
*/
#include <sys/types.h>
#include <sys/ioc_memory.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "testcache.h"
#include "common.h"
extern int quietflag;
static void
genblock(int b, char *blockdata, int blocksize, u32_t seed)
{
u32_t *p = (u32_t *) blockdata,
*plimit = (u32_t *) (blockdata + blocksize),
i = 0;
srandom(seed ^ b);
for(p = (u32_t *) blockdata; p < plimit; p++) {
i++;
*p = random();
}
}
static int
checkblock(int b, int blocksize, u32_t seed)
{
static char data[MAXBLOCKSIZE], expected_data[MAXBLOCKSIZE];
int r;
genblock(b, expected_data, blocksize, seed);
r = readblock(b, blocksize, seed, data);
if(r == OK_BLOCK_GONE) { return 0; }
if(r != blocksize) {
fprintf(stderr, "readblock failed\n");
return 1;
}
if(memcmp(expected_data, data, blocksize)) {
fprintf(stderr, "comparison of %d failed\n", b);
return 1;
}
return 0;
}
static int
writeblock(int b, int blocksize, u32_t seed)
{
static char data[MAXBLOCKSIZE];
genblock(b, data, blocksize, seed);
if(dowriteblock(b, blocksize, seed, data) != blocksize) {
fprintf(stderr, "writeblock of %d failed\n", b);
return 0;
}
return blocksize;
}
static int *
makepermutation(int nblocks, int *permutation)
{
int b;
assert(nblocks > 0 && nblocks <= MAXBLOCKS);
for(b = 0; b < nblocks; b++) permutation[b] = b;
for(b = 0; b < nblocks-1; b++) {
int s, other = b + random() % (nblocks - b - 1);
assert(other >= b && other < nblocks);
s = permutation[other];
permutation[other] = permutation[b];
permutation[b] = s;
}
return permutation;
}
static int
checkblocks(int nblocks, int blocksize, u32_t seed)
{
int b;
int nrandom = nblocks * 3;
static int perm1[MAXBLOCKS];
if(!quietflag) { fprintf(stderr, "\nverifying "); fflush(stderr); }
makepermutation(nblocks, perm1);
assert(nblocks > 0 && nblocks <= MAXBLOCKS);
assert(blocksize > 0 && blocksize <= MAXBLOCKSIZE);
for(b = 0; b < nblocks; b++) {
if(checkblock(b, blocksize, seed)) { return 1; }
}
for(b = 0; b < nrandom; b++) {
if(checkblock(random() % nblocks, blocksize, seed)) { return 1; }
}
for(b = 0; b < nblocks; b++) {
if(checkblock(b, blocksize, seed)) { return 1; }
}
for(b = 0; b < nblocks; b++) {
if(checkblock(perm1[b], blocksize, seed)) { return 1; }
}
if(!quietflag) { fprintf(stderr, "done\n"); }
return 0;
}
int
dotest(int blocksize, int nblocks, int iterations)
{
int b, i;
int nrandom = nblocks * iterations;
static int perm1[MAXBLOCKS], perm2[MAXBLOCKS];
static int newblock[MAXBLOCKS];
u32_t seed = random(), newseed;
int mb;
assert(nblocks > 0 && nblocks <= MAXBLOCKS);
mb = (int) ((u64_t) blocksize * nblocks / 1024 / 1024);
if(!quietflag) { fprintf(stderr, "test: %d * %d = %dMB\n", blocksize, nblocks, mb); }
for(b = 0; b < nblocks; b++) {
if(writeblock(b, blocksize, seed) < blocksize) { return 1; }
if(checkblock(b, blocksize, seed)) { return 1; }
printprogress("writing sequential", b, nblocks);
}
if(checkblocks(nblocks, blocksize, seed)) { return 1; }
makepermutation(nblocks, perm1);
for(b = 0; b < nblocks; b++) {
if(writeblock(perm1[b], blocksize, seed) < blocksize) { return 1; }
if(checkblock(perm1[b], blocksize, seed)) { return 1; }
printprogress("writing permutation", b, nblocks);
}
if(checkblocks(nblocks, blocksize, seed)) { return 1; }
for(i = 0; i < iterations; i++) {
makepermutation(nblocks, perm1);
makepermutation(nblocks, perm2);
memset(newblock, 0, sizeof(newblock));
newseed = random();
if(!quietflag) { fprintf(stderr, "iteration %d/%d\n", i, iterations); }
for(b = 0; b < nblocks; b++) {
int wr = perm1[b], check = perm2[b];
if(writeblock(wr, blocksize, newseed) < blocksize) { return 1; }
newblock[wr] = 1;
if(checkblock(check, blocksize, newblock[check] ? newseed : seed)) { return 1; }
printprogress("interleaved permutation read, write", b, nblocks);
}
seed = newseed;
if(checkblocks(nblocks, blocksize, seed)) { return 1; }
}
newseed = random();
memset(newblock, 0, sizeof(newblock));
for(b = 0; b < nrandom; b++) {
int wr = random() % nblocks, check = random() % nblocks;
if(writeblock(wr, blocksize, newseed) < blocksize) { return 1; }
newblock[wr] = 1;
if(checkblock(check, blocksize,
newblock[check] ? newseed : seed)) { return 1; }
printprogress("1 random verify, 1 random write", b, nrandom);
}
seed = newseed;
if(!quietflag) { fprintf(stderr, "\n"); }
testend();
return 0;
}
void cachequiet(int quiet)
{
quietflag = quiet;
}