. test74 for mmap functionality . vm: add a mem_file memory type that specifies an mmap()ped memory range, backed by a file . add fdref, an object that keeps track of FD references within VM per process and so knows how to de-duplicate the use of FD's by various mmap()ped ranges; there can be many more than there can be FD's . turned off for now, enable with 'filemap=1' as boot option Change-Id: I640b1126cdaa522a0560301cf6732b7661555672
		
			
				
	
	
		
			251 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			251 lines
		
	
	
		
			5.7 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;
 | 
						|
 | 
						|
int fds[MAXFILES];
 | 
						|
 | 
						|
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
 | 
						|
get_fd_offset(int b, int blocksize, u64_t *file_offset, int *fd)
 | 
						|
{
 | 
						|
        u64_t offset = (u64_t) b * blocksize;
 | 
						|
        int filenumber;
 | 
						|
 | 
						|
        filenumber = offset / MB / MBPERFILE;
 | 
						|
 | 
						|
        assert(filenumber >= 0 && filenumber < MAXFILES);
 | 
						|
        assert(fds[filenumber] > 0);
 | 
						|
 | 
						|
        *fd = fds[filenumber];
 | 
						|
        *file_offset = offset - (filenumber * MBPERFILE * MB);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
makefiles(int n)
 | 
						|
{
 | 
						|
	int f;
 | 
						|
        for(f = 0; f < n; f++) {
 | 
						|
                char tempfilename[] = "cachetest.XXXXXXXX";
 | 
						|
                fds[f] = mkstemp(tempfilename);
 | 
						|
                if(fds[f] < 0) {
 | 
						|
			perror("mkstemp");
 | 
						|
			fprintf(stderr, "mkstemp %d/%d failed\n", f, n);
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
                assert(fds[f] > 0);
 | 
						|
        }
 | 
						|
}
 | 
						|
 | 
						|
void cachequiet(int quiet)
 | 
						|
{
 | 
						|
	quietflag = quiet;
 | 
						|
}
 | 
						|
 |