test71, test72: fs/cache behaviour testing
. test71: blackbox 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. Change-Id: I1287e9753182b8719e634917ad158e3c1e079ceb
This commit is contained in:
parent
9afa452b59
commit
3a08ad741d
|
|
@ -45,6 +45,7 @@ struct buf *lmfs_get_block(dev_t dev, block_t block,int only_search);
|
||||||
void lmfs_invalidate(dev_t device);
|
void lmfs_invalidate(dev_t device);
|
||||||
void lmfs_put_block(struct buf *bp, int block_type);
|
void lmfs_put_block(struct buf *bp, int block_type);
|
||||||
void lmfs_rw_scattered(dev_t, struct buf **, int, int);
|
void lmfs_rw_scattered(dev_t, struct buf **, int, int);
|
||||||
|
void lmfs_setquiet(int q);
|
||||||
|
|
||||||
/* calls that libminixfs does into fs */
|
/* calls that libminixfs does into fs */
|
||||||
void fs_blockstats(u32_t *blocks, u32_t *free, u32_t *used);
|
void fs_blockstats(u32_t *blocks, u32_t *free, u32_t *used);
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,11 @@ static int fs_block_size = 1024; /* raw i/o block size */
|
||||||
|
|
||||||
static int rdwt_err;
|
static int rdwt_err;
|
||||||
|
|
||||||
|
static int quiet = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
lmfs_setquiet(int q) { quiet = q; }
|
||||||
|
|
||||||
u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u32_t bfree,
|
u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u32_t bfree,
|
||||||
int blocksize, dev_t majordev)
|
int blocksize, dev_t majordev)
|
||||||
{
|
{
|
||||||
|
|
@ -66,7 +71,7 @@ u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u32_t bfree,
|
||||||
*/
|
*/
|
||||||
if((vm_info_stats(&vsi) != OK)) {
|
if((vm_info_stats(&vsi) != OK)) {
|
||||||
bufs = 1024;
|
bufs = 1024;
|
||||||
printf("fslib: heuristic info fail: default to %d bufs\n", bufs);
|
if(!quiet) printf("fslib: heuristic info fail: default to %d bufs\n", bufs);
|
||||||
return bufs;
|
return bufs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,17 @@ LDFLAGS.mod= -shared # make shared object
|
||||||
# Some have an extra file
|
# Some have an extra file
|
||||||
OBJS.test57= test57loop.o
|
OBJS.test57= test57loop.o
|
||||||
|
|
||||||
|
# Cache testing programs
|
||||||
|
OBJS.test71+= testcache.o
|
||||||
|
OBJS.test72+= testcache.o
|
||||||
|
LDADD.test72+= -lminixfs
|
||||||
|
|
||||||
# Tests to compile, For every architecture
|
# Tests to compile, For every architecture
|
||||||
MINIX_TESTS= \
|
MINIX_TESTS= \
|
||||||
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||||
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
|
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
|
||||||
61 64 65 66 67 68 69 70
|
61 64 65 66 67 68 69 70 71 72
|
||||||
|
|
||||||
.if ${MACHINE_ARCH} == "i386"
|
.if ${MACHINE_ARCH} == "i386"
|
||||||
MINIX_TESTS+= \
|
MINIX_TESTS+= \
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
int common_test_nr = -1, errct = 0, subtest;
|
int common_test_nr = -1, errct = 0, subtest;
|
||||||
|
|
||||||
|
int quietflag = 1;
|
||||||
|
|
||||||
/* provide a default max_error symbol as Max_error with a value
|
/* provide a default max_error symbol as Max_error with a value
|
||||||
* of 5. The test program can override it wit its own max_error
|
* of 5. The test program can override it wit its own max_error
|
||||||
* symbol if it wants that this code will then use instead.
|
* symbol if it wants that this code will then use instead.
|
||||||
|
|
@ -130,3 +132,37 @@ void quit()
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printprogress(char *msg, int i, int max)
|
||||||
|
{
|
||||||
|
int use_i = i + 1;
|
||||||
|
static time_t start_time, prev_time;
|
||||||
|
static int prev_i;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if(quietflag) return;
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
if(prev_i >= i) start_time = now;
|
||||||
|
|
||||||
|
if(now > start_time && prev_time < now) {
|
||||||
|
double i_per_sec = i / (now - start_time);
|
||||||
|
int remain_secs;
|
||||||
|
|
||||||
|
remain_secs = (int)((max-i) / i_per_sec);
|
||||||
|
|
||||||
|
fprintf(stderr, "%-35s %7d/%7d %3d%% ETA %3ds\r", msg,
|
||||||
|
use_i, (max), use_i*100/(max), remain_secs);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(use_i >= max) {
|
||||||
|
fprintf(stderr, "%-35s done \n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_i = i;
|
||||||
|
prev_time = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
114
test/test71.c
Normal file
114
test/test71.c
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
|
||||||
|
#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 "common.h"
|
||||||
|
#include "testcache.h"
|
||||||
|
|
||||||
|
/* we want to flexibly split this test over multiple files
|
||||||
|
* - for big working sets we might run over the 2GB MFS file limit
|
||||||
|
* - we might want to test the FS being able to handle lots of
|
||||||
|
* files / unusual metadata situations
|
||||||
|
*/
|
||||||
|
#define MBPERFILE 100
|
||||||
|
#define MB (1024*1024)
|
||||||
|
#define MAXFILES ((u64_t) MAXBLOCKS * MAXBLOCKSIZE / MB / MBPERFILE + 1)
|
||||||
|
|
||||||
|
static int fds[MAXFILES];
|
||||||
|
|
||||||
|
static 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
dowriteblock(int b, int blocksize, u32_t seed, char *data)
|
||||||
|
{
|
||||||
|
u64_t offset;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
get_fd_offset(b, blocksize, &offset, &fd);
|
||||||
|
|
||||||
|
if(pwrite(fd, data, blocksize, offset) < blocksize) {
|
||||||
|
perror("pwrite");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
readblock(int b, int blocksize, u32_t seed, char *data)
|
||||||
|
{
|
||||||
|
u64_t offset;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
get_fd_offset(b, blocksize, &offset, &fd);
|
||||||
|
|
||||||
|
if(pread(fd, data, blocksize, offset) < blocksize) {
|
||||||
|
perror("pread");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testend(void) { }
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int f, big = !!getenv("BIGTEST");
|
||||||
|
|
||||||
|
start(71);
|
||||||
|
|
||||||
|
cachequiet(!big);
|
||||||
|
|
||||||
|
for(f = 0; f < MAXFILES; f++) {
|
||||||
|
char tempfilename[] = "cachetest.XXXXXXXX";
|
||||||
|
fds[f] = mkstemp(tempfilename);
|
||||||
|
if(fds[f] < 0) { perror("mkstemp"); e(20); return 1; }
|
||||||
|
/* if(unlink(tempfilename) < 0) { perror("unlink"); e(21); return 1; } */
|
||||||
|
assert(fds[f] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ITER 3
|
||||||
|
|
||||||
|
if(dotest(PAGE_SIZE, 1500000, ITER)) e(7);
|
||||||
|
|
||||||
|
if(dotest(PAGE_SIZE, 500, ITER)) e(1);
|
||||||
|
if(dotest(PAGE_SIZE*2, 1000, ITER)) e(2);
|
||||||
|
if(dotest(PAGE_SIZE*3, 1000, ITER)) e(3);
|
||||||
|
if(dotest(PAGE_SIZE, 1500, ITER)) e(4);
|
||||||
|
if(dotest(PAGE_SIZE, 15000, ITER)) e(5);
|
||||||
|
if(big) {
|
||||||
|
if(dotest(PAGE_SIZE, 50000, ITER)) e(6);
|
||||||
|
if(dotest(PAGE_SIZE, 500000, ITER)) e(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(f = 0; f < MAXFILES; f++) {
|
||||||
|
assert(fds[f] > 0);
|
||||||
|
close(fds[f]);
|
||||||
|
}
|
||||||
|
|
||||||
|
quit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
303
test/test72.c
Normal file
303
test/test72.c
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
/* libminixfs test */
|
||||||
|
|
||||||
|
#include <minix/libminixfs.h>
|
||||||
|
#include <minix/sysutil.h>
|
||||||
|
#include <minix/syslib.h>
|
||||||
|
#include <minix/vm.h>
|
||||||
|
#include <minix/bdev.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/ioc_memory.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
int max_error = 0;
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "testcache.h"
|
||||||
|
|
||||||
|
#define MYMAJOR 40 /* doesn't really matter, shouldn't be NO_DEV though */
|
||||||
|
|
||||||
|
#define MYDEV makedev(MYMAJOR, 1)
|
||||||
|
|
||||||
|
static int curblocksize = -1;
|
||||||
|
|
||||||
|
static char *writtenblocks[MAXBLOCKS];
|
||||||
|
|
||||||
|
/* Some functions used by testcache.c */
|
||||||
|
|
||||||
|
int
|
||||||
|
dowriteblock(int b, int blocksize, u32_t seed, char *data)
|
||||||
|
{
|
||||||
|
struct buf *bp;
|
||||||
|
|
||||||
|
assert(blocksize == curblocksize);
|
||||||
|
|
||||||
|
if(!(bp = lmfs_get_block(MYDEV, b, NORMAL))) {
|
||||||
|
e(30);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(bp->data, data, blocksize);
|
||||||
|
|
||||||
|
lmfs_markdirty(bp);
|
||||||
|
|
||||||
|
lmfs_put_block(bp, FULL_DATA_BLOCK);
|
||||||
|
|
||||||
|
return blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
readblock(int b, int blocksize, u32_t seed, char *data)
|
||||||
|
{
|
||||||
|
struct buf *bp;
|
||||||
|
|
||||||
|
assert(blocksize == curblocksize);
|
||||||
|
|
||||||
|
if(!(bp = lmfs_get_block(MYDEV, b, NORMAL))) {
|
||||||
|
e(30);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data, bp->data, blocksize);
|
||||||
|
|
||||||
|
lmfs_put_block(bp, FULL_DATA_BLOCK);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testend(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < MAXBLOCKS; i++) {
|
||||||
|
if(writtenblocks[i]) {
|
||||||
|
free(writtenblocks[i]);
|
||||||
|
writtenblocks[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fake some libminixfs client functions */
|
||||||
|
|
||||||
|
int
|
||||||
|
fs_sync(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fs_blockstats(u32_t *total, u32_t *free, u32_t *used)
|
||||||
|
{
|
||||||
|
*total = *free = *used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void allocate(int b)
|
||||||
|
{
|
||||||
|
assert(curblocksize > 0);
|
||||||
|
assert(!writtenblocks[b]);
|
||||||
|
if(!(writtenblocks[b] = calloc(1, curblocksize))) {
|
||||||
|
fprintf(stderr, "out of memory allocating block %d\n", b);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fake some libblockdriver functions */
|
||||||
|
ssize_t
|
||||||
|
bdev_gather(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags)
|
||||||
|
{
|
||||||
|
int i, block;
|
||||||
|
ssize_t tot = 0;
|
||||||
|
assert(dev == MYDEV);
|
||||||
|
assert(curblocksize > 0);
|
||||||
|
assert(!(pos % curblocksize));
|
||||||
|
block = pos / curblocksize;
|
||||||
|
for(i = 0; i < count; i++) {
|
||||||
|
int subblocks;
|
||||||
|
char *data = (char *) vec[i].iov_addr;
|
||||||
|
assert(vec[i].iov_size > 0);
|
||||||
|
assert(!(vec[i].iov_size % curblocksize));
|
||||||
|
subblocks = vec[i].iov_size / curblocksize;
|
||||||
|
while(subblocks > 0) {
|
||||||
|
assert(block > 0);
|
||||||
|
assert(block < MAXBLOCKS);
|
||||||
|
if(!writtenblocks[block]) {
|
||||||
|
allocate(block);
|
||||||
|
}
|
||||||
|
memcpy(data, writtenblocks[block], curblocksize);
|
||||||
|
block++;
|
||||||
|
subblocks--;
|
||||||
|
data += curblocksize;
|
||||||
|
tot += curblocksize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
bdev_scatter(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags)
|
||||||
|
{
|
||||||
|
int i, block;
|
||||||
|
ssize_t tot = 0;
|
||||||
|
assert(dev == MYDEV);
|
||||||
|
assert(curblocksize > 0);
|
||||||
|
assert(!(pos % curblocksize));
|
||||||
|
block = pos / curblocksize;
|
||||||
|
for(i = 0; i < count; i++) {
|
||||||
|
int subblocks;
|
||||||
|
char *data = (char *) vec[i].iov_addr;
|
||||||
|
assert(vec[i].iov_size > 0);
|
||||||
|
assert(!(vec[i].iov_size % curblocksize));
|
||||||
|
subblocks = vec[i].iov_size / curblocksize;
|
||||||
|
while(subblocks > 0) {
|
||||||
|
assert(block >= 0);
|
||||||
|
assert(block < MAXBLOCKS);
|
||||||
|
if(!writtenblocks[block]) {
|
||||||
|
allocate(block);
|
||||||
|
}
|
||||||
|
memcpy(writtenblocks[block], data, curblocksize);
|
||||||
|
block++;
|
||||||
|
subblocks--;
|
||||||
|
data += curblocksize;
|
||||||
|
tot += curblocksize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
bdev_read(dev_t dev, u64_t pos, char *data, size_t count, int flags)
|
||||||
|
{
|
||||||
|
int block;
|
||||||
|
ssize_t tot = 0;
|
||||||
|
int subblocks;
|
||||||
|
|
||||||
|
assert(dev == MYDEV);
|
||||||
|
assert(curblocksize > 0);
|
||||||
|
assert(!(pos % curblocksize));
|
||||||
|
assert(count > 0);
|
||||||
|
assert(!(count % curblocksize));
|
||||||
|
|
||||||
|
block = pos / curblocksize;
|
||||||
|
subblocks = count / curblocksize;
|
||||||
|
while(subblocks > 0) {
|
||||||
|
assert(block >= 0);
|
||||||
|
assert(block < MAXBLOCKS);
|
||||||
|
if(!writtenblocks[block]) {
|
||||||
|
allocate(block);
|
||||||
|
}
|
||||||
|
memcpy(data, writtenblocks[block], curblocksize);
|
||||||
|
block++;
|
||||||
|
subblocks--;
|
||||||
|
data += curblocksize;
|
||||||
|
tot += curblocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fake some libsys functions */
|
||||||
|
|
||||||
|
__dead void
|
||||||
|
panic(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
vfprintf(stderr, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_forgetblock(u64_t id)
|
||||||
|
{
|
||||||
|
return ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_yield_block_get_block(u64_t yieldid, u64_t getid, void *mem,
|
||||||
|
vir_bytes len)
|
||||||
|
{
|
||||||
|
return ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_forgetblocks(void)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vm_info_stats(struct vm_stats_info *vsi)
|
||||||
|
{
|
||||||
|
return ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
util_stacktrace(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fake stacktrace\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void *alloc_contig(size_t len, int flags, phys_bytes *phys)
|
||||||
|
{
|
||||||
|
return malloc(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_contig(void *addr, size_t len)
|
||||||
|
{
|
||||||
|
free(addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t sqrt_approx(u32_t v)
|
||||||
|
{
|
||||||
|
return (u32_t) sqrt(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int wss, cs, n = 0, p;
|
||||||
|
|
||||||
|
#define ITER 3
|
||||||
|
#define BLOCKS 200
|
||||||
|
|
||||||
|
start(72);
|
||||||
|
|
||||||
|
lmfs_setquiet(1);
|
||||||
|
|
||||||
|
/* Can the cache handle differently sized blocks? */
|
||||||
|
|
||||||
|
for(p = 1; p <= 3; p++) {
|
||||||
|
curblocksize = PAGE_SIZE*p;
|
||||||
|
lmfs_set_blocksize(curblocksize, MYMAJOR);
|
||||||
|
lmfs_buf_pool(BLOCKS);
|
||||||
|
if(dotest(curblocksize, BLOCKS, ITER)) e(n);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can the cache handle various combinations of the working set
|
||||||
|
* being larger and smaller than the cache?
|
||||||
|
*/
|
||||||
|
for(wss = 2; wss <= 3; wss++) {
|
||||||
|
int wsblocks = 10*wss*wss*wss*wss*wss;
|
||||||
|
for(cs = wsblocks/4; cs <= wsblocks*3; cs *= 1.5) {
|
||||||
|
curblocksize = PAGE_SIZE;
|
||||||
|
lmfs_set_blocksize(curblocksize, MYMAJOR);
|
||||||
|
lmfs_buf_pool(cs);
|
||||||
|
if(dotest(curblocksize, wsblocks, ITER)) e(n);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
203
test/testcache.c
Normal file
203
test/testcache.c
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
|
||||||
|
#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];
|
||||||
|
|
||||||
|
genblock(b, expected_data, blocksize, seed);
|
||||||
|
|
||||||
|
if(readblock(b, blocksize, seed, data)) {
|
||||||
|
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 * 5;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
12
test/testcache.h
Normal file
12
test/testcache.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define MAXBLOCKS 1500000
|
||||||
|
|
||||||
|
#define MAXBLOCKSIZE (4*PAGE_SIZE)
|
||||||
|
|
||||||
|
int dowriteblock(int b, int blocksize, u32_t seed, char *block);
|
||||||
|
int readblock(int b, int blocksize, u32_t seed, char *block);
|
||||||
|
void testend(void);
|
||||||
|
int dotest(int blocksize, int nblocks, int iterations);
|
||||||
|
void cachequiet(int quiet);
|
||||||
Loading…
Reference in New Issue
Block a user