These patches add some new test cases into the test subdirectory of PVFS2:
pvfs2-test-aio.patch:
---------------------
This set of test programs allow comparison of normal io (pread/pwrite)
vs. aio vs. alt-aio (as implemented in pvfs2 with the "alt-aio" trove
method). There isn't much depth, but it at least gives a little bit of
insight into the details of the read/write path independent of how it is
used by PVFS. I've used this test program to help isolate some system
bugs and also to help figure motivate the alt-aio approach.
pvfs2-test-tcache.patch
-----------------------
This patch enhances the existing tcache test program to cover more test
cases and to print out more verbose information while the test is running.
diff -Naur pvfs2/test/io/trove/module.mk.in pvfs2-patched/test/io/trove/module.mk.in
--- pvfs2/test/io/trove/module.mk.in 2006-06-16 17:01:17.000000000 -0400
+++ pvfs2-patched/test/io/trove/module.mk.in 2007-05-02 15:15:45.000000000 -0400
@@ -7,6 +7,8 @@
$(DIR)/trove-mkfs.c \
$(DIR)/trove-rm.c \
$(DIR)/trove-rmdir.c \
+ $(DIR)/test-aio.c \
+ $(DIR)/test-non-aio.c \
$(DIR)/test-listio.c \
$(DIR)/test-listio2.c \
$(DIR)/test-listio3.c \
diff -Naur pvfs2/test/io/trove/test-aio.c pvfs2-patched/test/io/trove/test-aio.c
--- pvfs2/test/io/trove/test-aio.c 1969-12-31 19:00:00.000000000 -0500
+++ pvfs2-patched/test/io/trove/test-aio.c 2007-05-02 15:14:45.000000000 -0400
@@ -0,0 +1,552 @@
+/*
+ * Copyright © Acxiom Corporation, 2006
+ *
+ * See COPYING in top-level directory.
+ */
+
+#define _XOPEN_SOURCE 500
+
+#include <pthread.h>
+#include <aio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#include "quicklist.h"
+#include "pint-util.h"
+#include "pvfs2-internal.h"
+
+struct options
+{
+ int total_ops;
+ int concurrent_ops;
+ long long size;
+ char* filename;
+ char* in_filename;
+ int alt_aio;
+ int rand_off;
+ int mix_reads;
+ int delete;
+};
+
+struct aio_entry
+{
+ struct aiocb cb;
+ struct aiocb* cb_p;
+ struct sigevent sig;
+ PINT_time_marker start;
+ PINT_time_marker end;
+ struct qlist_head list_link;
+};
+
+
+QLIST_HEAD(aio_queue);
+static int aio_queue_count = 0;
+pthread_mutex_t aio_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int aio_done_count = 0;
+pthread_mutex_t aio_done_count_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int parse_args(int argc, char **argv, struct options* opts);
+static void usage(void);
+static void aio_callback(sigval_t sig);
+
+static float time_sum = 0;
+static float time_max = 0;
+static pthread_mutex_t time_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+PINT_time_marker total_start;
+PINT_time_marker total_end;
+
+#define IO_SIZE (256*1024)
+
+#define WORKER_THREADS 16
+
+struct alt_aio_item
+{
+ struct aiocb *cb_p;
+ struct sigevent *sig;
+ struct qlist_head list_link;
+};
+QLIST_HEAD(alt_aio_queue);
+pthread_mutex_t alt_aio_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t alt_aio_queue_cond = PTHREAD_COND_INITIALIZER;
+
+void* thread_fn_read(void*);
+void* thread_fn_write(void*);
+int alt_lio_listio(int mode, struct aiocb *list[],
+ int nent, struct sigevent *sig);
+
+
+static struct options opts;
+
+int main(int argc, char **argv)
+{
+ int ret;
+ struct aio_entry* aio_array;
+ int i = 0;
+ int my_fd = -1;
+ int my_in_fd = -1;
+ char* my_buffer = NULL;
+ long long cur_offset = 0;
+ int should_exit = 0;
+ double wtime, utime, stime;
+ int region;
+ int num_regions;
+
+ ret = parse_args(argc, argv, &opts);
+ if (ret < 0)
+ {
+ fprintf(stderr, "Error: argument parsing failed.\n");
+ usage();
+ return -1;
+ }
+
+ printf("file size: %lld\n", opts.size);
+ printf("total ops: %d\n", opts.total_ops);
+ printf("concurrent ops: %d\n", opts.concurrent_ops);
+ printf("filename: %s\n", opts.filename);
+ if(opts.alt_aio)
+ {
+ printf("aio: ALTERNATE.\n");
+#if 0
+ for(i=0; i<WORKER_THREADS; i++)
+ {
+ ret = pthread_create(&tid, NULL, thread_fn, NULL);
+ assert(ret == 0);
+ }
+#endif
+ }
+ else
+ {
+ printf("aio: NORMAL.\n");
+ }
+
+ pthread_mutex_lock(&aio_queue_mutex);
+ aio_queue_count = opts.total_ops;
+ pthread_mutex_unlock(&aio_queue_mutex);
+
+ if(opts.concurrent_ops > opts.total_ops)
+ {
+ fprintf(stderr, "Error: concurrent ops > total ops.\n");
+ return(-1);
+ }
+
+ /* open file */
+ my_fd = open(opts.filename, (O_RDWR|O_CREAT), (S_IRUSR|S_IWUSR));
+ if(my_fd < 0)
+ {
+ perror("open");
+ return(-1);
+ }
+
+ /* open file */
+ /* do we have a seperate file for reads or not? */
+ if(opts.in_filename)
+ {
+ my_in_fd = open(opts.in_filename, (O_RDWR), (S_IRUSR|S_IWUSR));
+ if(my_in_fd < 0)
+ {
+ perror("open");
+ return(-1);
+ }
+ }
+ else
+ {
+ my_in_fd = my_fd;
+ }
+
+ /* allocate buffer to write */
+ my_buffer = malloc(IO_SIZE);
+
+ /* allocate structures ahead of time to run each op */
+ aio_array = (struct aio_entry*)malloc(opts.total_ops*sizeof(struct
+ aio_entry));
+ assert(aio_array);
+ memset(aio_array, 0, (opts.total_ops*sizeof(struct aio_entry)));
+
+ srand((unsigned int)time(NULL));
+ num_regions = opts.size / RAND_MAX;
+
+ for(i = 0; i<opts.total_ops; i++)
+ {
+ /* fill in description */
+ if(opts.rand_off)
+ {
+ /* this extra logic is go overcome the fact that rand won't
+ * produce large enough integers for large files
+ */
+ if(num_regions)
+ {
+ region = rand() % num_regions;
+ }
+ else
+ {
+ region = 0;
+ }
+ aio_array[i].cb.aio_offset =
+ (off_t)((off_t)(rand()) % (off_t)opts.size);
+ aio_array[i].cb.aio_offset +=
+ (((off_t)(region)) * ((off_t)(RAND_MAX)));
+ /* make sure we don't go beyond eof */
+ aio_array[i].cb.aio_offset =
+ (aio_array[i].cb.aio_offset % ((off_t)(opts.size-IO_SIZE)));
+ }
+ else
+ {
+ aio_array[i].cb.aio_offset = 0;
+ aio_array[i].cb.aio_offset += cur_offset;
+ cur_offset += IO_SIZE;
+ if(cur_offset > (opts.size-IO_SIZE))
+ {
+ cur_offset = 0;
+ }
+ }
+ /* they will all write the same buffer of garbage */
+ aio_array[i].cb.aio_buf = my_buffer;
+ aio_array[i].cb.aio_nbytes = IO_SIZE;
+ aio_array[i].cb.aio_reqprio = 0;
+ if(opts.mix_reads)
+ {
+ /* 0 and 1 are reads and writes respectively */
+ aio_array[i].cb.aio_lio_opcode = rand() % 2;
+ }
+ else
+ {
+ aio_array[i].cb.aio_lio_opcode = LIO_WRITE;
+ }
+ if(aio_array[i].cb.aio_lio_opcode == LIO_WRITE)
+ {
+ aio_array[i].cb.aio_fildes = my_fd;
+ }
+ else
+ {
+ aio_array[i].cb.aio_fildes = my_in_fd;
+ }
+
+ /* need to fill in sigevent */
+ aio_array[i].sig.sigev_notify = SIGEV_THREAD;
+ aio_array[i].sig.sigev_notify_attributes = NULL;
+ aio_array[i].sig.sigev_notify_function = aio_callback;
+ aio_array[i].sig.sigev_value.sival_ptr = (void *)(&aio_array[i]);
+
+ aio_array[i].cb_p = &aio_array[i].cb;
+
+ pthread_mutex_lock(&aio_queue_mutex);
+ qlist_add_tail(&aio_array[i].list_link, &aio_queue);
+ pthread_mutex_unlock(&aio_queue_mutex);
+ }
+
+ PINT_time_mark(&total_start);
+ pthread_mutex_lock(&aio_queue_mutex);
+ for(i=0; i<opts.concurrent_ops; i++)
+ {
+ qlist_del(&aio_array[i].list_link);
+ aio_queue_count--;
+
+ PINT_time_mark(&aio_array[i].start);
+ if(opts.alt_aio)
+ {
+ ret = alt_lio_listio(LIO_NOWAIT, &aio_array[i].cb_p, 1,
+ &aio_array[i].sig);
+ }
+ else
+ {
+ ret = lio_listio(LIO_NOWAIT, &aio_array[i].cb_p, 1,
+ &aio_array[i].sig);
+ }
+ assert(ret == 0);
+ }
+ pthread_mutex_unlock(&aio_queue_mutex);
+
+ do
+ {
+ sleep(1);
+ pthread_mutex_lock(&aio_done_count_mutex);
+ if(aio_done_count == opts.total_ops)
+ {
+ should_exit = 1;
+ }
+ pthread_mutex_unlock(&aio_done_count_mutex);
+ }while(!should_exit);
+
+ free(aio_array);
+
+ if(my_fd != my_in_fd)
+ {
+ close(my_in_fd);
+ }
+
+ close(my_fd);
+
+ if(opts.delete)
+ {
+ ret = unlink(opts.filename);
+ if(ret < 0)
+ {
+ perror("unlink");
+ return(-1);
+ }
+ }
+
+ PINT_time_diff(total_start, total_end, &wtime, &utime, &stime);
+ printf("TEST COMPLETE.\n");
+ printf("Maximum service time: %f seconds\n", time_max);
+ printf("Average service time: %f seconds\n", (time_sum/opts.total_ops));
+ printf("Total time: %f seconds\n", wtime);
+
+ return(0);
+}
+
+static int parse_args(int argc, char **argv, struct options* opts)
+{
+ int c;
+ int ret;
+ long long g2;
+
+ memset(opts, 0, sizeof(struct options));
+ opts->total_ops = 100;
+ opts->concurrent_ops = 16;
+ opts->size = 1024*1024*1024;
+
+ while ((c = getopt(argc, argv, "t:c:s:hf:ardRi:")) != EOF) {
+ switch (c) {
+ case 't': /* total operations */
+ ret = sscanf(optarg, "%d", &opts->total_ops);
+ if(ret != 1)
+ {
+ return(-1);
+ }
+ break;
+ case 'c': /* concurrent operations */
+ ret = sscanf(optarg, "%d", &opts->concurrent_ops);
+ if(ret != 1)
+ {
+ return(-1);
+ }
+ break;
+ case 's': /* size of file */
+ ret = sscanf(optarg, "%lld",
+ &opts->size);
+ if(ret != 1)
+ {
+ return(-1);
+ }
+ break;
+ case 'f':
+ opts->filename = (char*)malloc(strlen(optarg)+1);
+ assert(opts->filename);
+ strcpy(opts->filename, optarg);
+ break;
+ case 'h': /* help */
+ usage();
+ return(0);
+ break;
+ case 'a':
+ opts->alt_aio = 1;
+ break;
+ case 'r':
+ opts->rand_off = 1;
+ break;
+ case 'd':
+ opts->delete = 1;
+ break;
+ case 'R':
+ opts->mix_reads = 1;
+ break;
+ case 'i':
+ opts->in_filename = (char*)malloc(strlen(optarg)+1);
+ assert(opts->in_filename);
+ strcpy(opts->in_filename, optarg);
+ break;
+ case '?':
+ default:
+ return -1;
+ }
+ }
+ if(!opts->filename)
+ {
+ fprintf(stderr, "Error: must specify filename with -f.\n");
+ return(-1);
+ }
+ g2 = 1024*1024*1024;
+ g2 *= 2;
+ if((opts->rand_off) && (opts->size > g2) && (opts->size % g2))
+ {
+ fprintf(stderr, "Error: if size greater than 2G, then the size must\n");
+ fprintf(stderr, " be a multiple of 2G to preserve randomness.\n");
+ return(-1);
+ }
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("USAGE: test-aio [options]\n");
+ printf(" -t: total number of operations\n");
+ printf(" -c: number of operations to process concurrently\n");
+ printf(" -s: overall size of file\n");
+ printf(" -h: display usage information\n");
+ printf(" -f: file name\n");
+ printf(" -a: enable alternat aio implementation\n");
+ printf(" -r: enable random offset selection\n");
+ printf(" -R: include a mixture of read operations.\n");
+ printf(" -d: delete file upon completion.\n");
+ printf(" -i: specify a different file for input (read operations).\n");
+}
+
+static void aio_callback(sigval_t sig)
+{
+ struct aio_entry* tmp_ent = (struct aio_entry*)sig.sival_ptr;
+ int ret;
+ struct aio_entry* next_ent;
+ double wtime, utime, stime;
+
+ pthread_mutex_lock(&aio_queue_mutex);
+
+ /* check error code */
+ ret = aio_error(tmp_ent->cb_p);
+ assert(ret == 0);
+
+ PINT_time_mark(&tmp_ent->end);
+ PINT_time_diff(tmp_ent->start, tmp_ent->end, &wtime, &utime, &stime);
+
+ /* submit another one if available */
+ if(aio_queue_count > 0)
+ {
+ /* get next item off of the queue */
+ next_ent = qlist_entry(aio_queue.next, struct aio_entry, list_link);
+ qlist_del(&next_ent->list_link);
+ aio_queue_count--;
+
+ PINT_time_mark(&next_ent->start);
+ if(opts.alt_aio)
+ {
+ ret = alt_lio_listio(LIO_NOWAIT, &next_ent->cb_p, 1,
+ &next_ent->sig);
+ }
+ else
+ {
+ ret = lio_listio(LIO_NOWAIT, &next_ent->cb_p, 1,
+ &next_ent->sig);
+ }
+ assert(ret == 0);
+ }
+
+ pthread_mutex_unlock(&aio_queue_mutex);
+
+ pthread_mutex_lock(&time_mutex);
+ time_sum += wtime;
+ if(wtime > time_max)
+ {
+ time_max = wtime;
+ }
+ pthread_mutex_unlock(&time_mutex);
+
+ pthread_mutex_lock(&aio_done_count_mutex);
+ aio_done_count++;
+ printf("callback count: %d, elapsed time: %f seconds\n",
+ aio_done_count, wtime);
+ if(aio_done_count == opts.total_ops)
+ {
+ PINT_time_mark(&total_end);
+ }
+ pthread_mutex_unlock(&aio_done_count_mutex);
+
+ return;
+}
+
+void* thread_fn_write(void* foo)
+{
+ struct alt_aio_item* tmp_item = (struct alt_aio_item*)foo;
+ int ret = 0;
+
+ ret = pwrite(tmp_item->cb_p->aio_fildes,
+ (const void*)tmp_item->cb_p->aio_buf,
+ tmp_item->cb_p->aio_nbytes,
+ tmp_item->cb_p->aio_offset);
+ assert(ret == tmp_item->cb_p->aio_nbytes);
+
+ /* run callback fn */
+ tmp_item->sig->sigev_notify_function(
+ tmp_item->sig->sigev_value);
+
+ free(tmp_item);
+
+ return(NULL);
+}
+
+void* thread_fn_read(void* foo)
+{
+ struct alt_aio_item* tmp_item = (struct alt_aio_item*)foo;
+ int ret = 0;
+
+ ret = pread(tmp_item->cb_p->aio_fildes,
+ (void*)tmp_item->cb_p->aio_buf,
+ tmp_item->cb_p->aio_nbytes,
+ tmp_item->cb_p->aio_offset);
+ assert(ret == tmp_item->cb_p->aio_nbytes);
+
+ /* run callback fn */
+ tmp_item->sig->sigev_notify_function(
+ tmp_item->sig->sigev_value);
+
+ free(tmp_item);
+
+ return(NULL);
+}
+
+
+int alt_lio_listio(int mode, struct aiocb *list[],
+ int nent, struct sigevent *sig)
+{
+ struct alt_aio_item* tmp_item;
+ int ret;
+ pthread_t tid;
+
+ assert(mode == LIO_NOWAIT);
+ assert(nent == 1);
+
+ tmp_item = (struct alt_aio_item*)malloc(sizeof(struct alt_aio_item));
+ tmp_item->cb_p = list[0];
+ tmp_item->sig = sig;
+
+ if(tmp_item->cb_p->aio_lio_opcode == LIO_READ)
+ {
+ ret = pthread_create(&tid, NULL, thread_fn_read, tmp_item);
+ }
+ else if(tmp_item->cb_p->aio_lio_opcode == LIO_WRITE)
+ {
+ ret = pthread_create(&tid, NULL, thread_fn_write, tmp_item);
+ }
+ else
+ {
+ assert(0);
+ }
+ if(ret != 0)
+ {
+ perror("pthread_create");
+ }
+ assert(ret == 0);
+ ret = pthread_detach(tid);
+ assert(ret == 0);
+
+ return(0);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff -Naur pvfs2/test/io/trove/test-non-aio.c pvfs2-patched/test/io/trove/test-non-aio.c
--- pvfs2/test/io/trove/test-non-aio.c 1969-12-31 19:00:00.000000000 -0500
+++ pvfs2-patched/test/io/trove/test-non-aio.c 2007-05-02 15:14:48.000000000 -0400
@@ -0,0 +1,203 @@
+/*
+ * Copyright © Acxiom Corporation, 2006
+ *
+ * See COPYING in top-level directory.
+ */
+
+#define _XOPEN_SOURCE 500
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "quicklist.h"
+#include "pint-util.h"
+
+struct options
+{
+ int total_ops;
+ long long size;
+ char* filename;
+ int sync;
+};
+
+static int parse_args(int argc, char **argv, struct options* opts);
+static void usage(void);
+
+static float time_sum = 0;
+static float time_max = 0;
+
+#define IO_SIZE (256*1024)
+
+int main(int argc, char **argv)
+{
+ int ret;
+ struct options opts;
+ int i = 0;
+ int my_fd = -1;
+ char* my_buffer = NULL;
+ long long cur_offset = 0;
+ PINT_time_marker start;
+ PINT_time_marker end;
+ PINT_time_marker total_start;
+ PINT_time_marker total_end;
+ double wtime, utime, stime;
+ double total_wtime, total_utime, total_stime;
+
+ ret = parse_args(argc, argv, &opts);
+ if (ret < 0)
+ {
+ fprintf(stderr, "Error: argument parsing failed.\n");
+ usage();
+ return -1;
+ }
+
+ printf("file size: %lld\n", opts.size);
+ printf("total ops: %d\n", opts.total_ops);
+ printf("filename: %s\n", opts.filename);
+
+ /* open file */
+ if(opts.sync)
+ {
+ my_fd = open(opts.filename, (O_RDWR|O_CREAT|O_TRUNC|O_SYNC), (S_IRUSR|S_IWUSR));
+ }
+ else
+ {
+ my_fd = open(opts.filename, (O_RDWR|O_CREAT|O_TRUNC), (S_IRUSR|S_IWUSR));
+ }
+ if(my_fd < 0)
+ {
+ perror("open");
+ return(-1);
+ }
+
+ /* allocate buffer to write */
+ my_buffer = malloc(IO_SIZE);
+
+ PINT_time_mark(&total_start);
+ for(i = 0; i<opts.total_ops; i++)
+ {
+
+ PINT_time_mark(&start);
+
+ ret = pwrite(my_fd, my_buffer, IO_SIZE, cur_offset);
+ if(ret < 0)
+ {
+ perror("write");
+ return(-1);
+ }
+ PINT_time_mark(&end);
+
+ PINT_time_diff(start, end, &wtime, &utime, &stime);
+
+ time_sum += wtime;
+ if(wtime > time_max)
+ {
+ time_max = wtime;
+ }
+
+ printf("write count: %d, elapsed time: %f seconds\n", i,
+ wtime);
+ cur_offset += IO_SIZE;
+ if(cur_offset > opts.size)
+ {
+ cur_offset = 0;
+ }
+ }
+ PINT_time_mark(&total_end);
+
+ close(my_fd);
+ ret = unlink(opts.filename);
+ if(ret < 0)
+ {
+ perror("unlink");
+ return(-1);
+ }
+
+ PINT_time_diff(total_start, total_end, &total_wtime, &total_utime,
+ &total_stime);
+
+ printf("TEST COMPLETE.\n");
+ printf("Maximum service time: %f seconds\n", time_max);
+ printf("Average service time: %f seconds\n", (time_sum/opts.total_ops));
+ printf("Total time: %f seconds\n", total_wtime);
+
+ return(0);
+}
+
+static int parse_args(int argc, char **argv, struct options* opts)
+{
+ int c;
+ int ret;
+
+ memset(opts, 0, sizeof(struct options));
+ opts->total_ops = 100;
+ opts->size = 1024*1024*1024;
+
+ while ((c = getopt(argc, argv, "t:s:hf:y")) != EOF) {
+ switch (c) {
+ case 't': /* total operations */
+ ret = sscanf(optarg, "%d", &opts->total_ops);
+ if(ret != 1)
+ {
+ return(-1);
+ }
+ break;
+ case 's': /* size of file */
+ ret = sscanf(optarg, "%lld",
+ &opts->size);
+ if(ret != 1)
+ {
+ return(-1);
+ }
+ break;
+ case 'f':
+ opts->filename = (char*)malloc(strlen(optarg)+1);
+ assert(opts->filename);
+ strcpy(opts->filename, optarg);
+ break;
+ case 'h': /* help */
+ usage();
+ return(0);
+ break;
+ case 'y': /* help */
+ opts->sync = 1;
+ break;
+ case '?':
+ default:
+ return -1;
+ }
+ }
+ if(!opts->filename)
+ {
+ fprintf(stderr, "Error: must specify filename with -f.\n");
+ return(-1);
+ }
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("USAGE: test-aio [options]\n");
+ printf(" -t: total number of operations\n");
+ printf(" -s: overall size of file\n");
+ printf(" -h: display usage information\n");
+ printf(" -y: open file in O_SYNC mode\n");
+ printf(" -f: file name\n");
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff -Naur pvfs2/test/common/misc/test-tcache.c pvfs2-patched/test/common/misc/test-tcache.c
--- pvfs2/test/common/misc/test-tcache.c 2006-06-13 11:56:52.000000000 -0400
+++ pvfs2-patched/test/common/misc/test-tcache.c 2007-05-02 15:38:16.000000000 -0400
@@ -15,6 +15,15 @@
static int foo_compare_key_entry(void* key, struct qhash_head* link);
static int foo_hash_key(void* key, int table_size);
static int foo_free_payload(void* payload);
+static void check_param(char *parameter_name, int param, int expected_value);
+
+#define TEST_TIMEOUT_MSEC 4000
+#define TEST_NUM_ENTRIES 30
+#define TEST_HARD_LIMIT 10
+#define TEST_SOFT_LIMIT 5
+#define TEST_ENABLE 1
+#define TEST_RECLAIM_PERCENTAGE 50
+
/* test payload */
struct foo_payload
@@ -32,9 +41,8 @@
int ret = 0;
int status = 0;
unsigned int param = 0;
- int removed = 0;
- int reclaimed = 0;
-
+ int tmp_count = 0;
+
if(argc != 1)
{
usage(argc, argv);
@@ -42,7 +50,7 @@
}
/* initialize */
- printf("Initializing cache...\n");
+ printf("Initializing cache... ");
test_tcache = PINT_tcache_initialize(foo_compare_key_entry,
foo_hash_key,
foo_free_payload,
@@ -54,73 +62,50 @@
}
printf("Done.\n");
- /* read current parameters */
- printf("Reading parameters...\n");
- ret = PINT_tcache_get_info(test_tcache, TCACHE_TIMEOUT_MSECS, ¶m);
- assert(ret == 0);
- printf("timeout_msecs: %d\n", param);
- ret = PINT_tcache_get_info(test_tcache, TCACHE_NUM_ENTRIES, ¶m);
- assert(ret == 0);
- printf("num_entries: %d\n", param);
- ret = PINT_tcache_get_info(test_tcache, TCACHE_HARD_LIMIT, ¶m);
- assert(ret == 0);
- printf("hard_limit: %d\n", param);
- ret = PINT_tcache_get_info(test_tcache, TCACHE_SOFT_LIMIT, ¶m);
- assert(ret == 0);
- printf("soft_limit: %d\n", param);
- ret = PINT_tcache_get_info(test_tcache, TCACHE_ENABLE, ¶m);
- assert(ret == 0);
- printf("enable: %d\n", param);
- ret = PINT_tcache_get_info(test_tcache, TCACHE_RECLAIM_PERCENTAGE, ¶m);
- assert(ret == 0);
- printf("reclaim_percentage: %d\n", param);
- printf("Done.\n");
-
/* set parameters */
- printf("Setting parameters...\n");
- param = 4000;
+ printf("Setting all TCACHE parameters... ");
+ param = TEST_TIMEOUT_MSEC;
ret = PINT_tcache_set_info(test_tcache, TCACHE_TIMEOUT_MSECS, param);
assert(ret == 0);
- param = 30;
+ param = TEST_NUM_ENTRIES;
ret = PINT_tcache_set_info(test_tcache, TCACHE_NUM_ENTRIES, param);
- assert(ret < 0);
- param = 10;
+ assert(ret == -PVFS_EINVAL);
+ param = TEST_HARD_LIMIT;
ret = PINT_tcache_set_info(test_tcache, TCACHE_HARD_LIMIT, param);
assert(ret == 0);
- param = 5;
+ param = TEST_SOFT_LIMIT;
ret = PINT_tcache_set_info(test_tcache, TCACHE_SOFT_LIMIT, param);
assert(ret == 0);
- param = 1;
+ param = TEST_ENABLE;
ret = PINT_tcache_set_info(test_tcache, TCACHE_ENABLE, param);
assert(ret == 0);
- param = 50;
+ param = TEST_RECLAIM_PERCENTAGE;
ret = PINT_tcache_set_info(test_tcache, TCACHE_RECLAIM_PERCENTAGE, param);
assert(ret == 0);
printf("Done.\n");
/* read current parameters */
- printf("Reading parameters...\n");
+ printf("Reading all TCACHE parameters... ");
ret = PINT_tcache_get_info(test_tcache, TCACHE_TIMEOUT_MSECS, ¶m);
assert(ret == 0);
- printf("timeout_msecs: %d\n", param);
+ check_param("TCACHE_TIMEOUT_MSECS", param, TEST_TIMEOUT_MSEC);
ret = PINT_tcache_get_info(test_tcache, TCACHE_NUM_ENTRIES, ¶m);
assert(ret == 0);
- printf("num_entries: %d\n", param);
+ check_param("TCACHE_NUM_ENTRIES", param, 0);
ret = PINT_tcache_get_info(test_tcache, TCACHE_HARD_LIMIT, ¶m);
assert(ret == 0);
- printf("hard_limit: %d\n", param);
+ check_param("TCACHE_HARD_LIMIT", param, TEST_HARD_LIMIT);
ret = PINT_tcache_get_info(test_tcache, TCACHE_SOFT_LIMIT, ¶m);
assert(ret == 0);
- printf("soft_limit: %d\n", param);
+ check_param("TCACHE_SOFT_LIMIT", param, TEST_SOFT_LIMIT);
ret = PINT_tcache_get_info(test_tcache, TCACHE_ENABLE, ¶m);
assert(ret == 0);
- printf("enable: %d\n", param);
+ check_param("TCACHE_ENABLE", param, TEST_ENABLE);
ret = PINT_tcache_get_info(test_tcache, TCACHE_RECLAIM_PERCENTAGE, ¶m);
assert(ret == 0);
- printf("reclaim_percentage: %d\n", param);
+ check_param("TCACHE_RECLAIM_PERCENTAGE", param, TEST_RECLAIM_PERCENTAGE);
printf("Done.\n");
-
/* insert some entries */
for(i=0; i< 3; i++)
{
@@ -130,12 +115,12 @@
tmp_payload->key = i;
tmp_payload->value = i;
- printf("Inserting %d...\n", i);
- ret = PINT_tcache_insert_entry(test_tcache, &i,
- tmp_payload, &removed);
+ printf("Inserting [%d]... ", i);
+ ret = PINT_tcache_insert_entry(test_tcache, &i, tmp_payload,
+ &tmp_count);
if(ret < 0)
{
- PVFS_perror("PINT_tcache_insert", ret);
+ PVFS_perror("\nPINT_tcache_insert", ret);
return(-1);
}
printf("Done.\n");
@@ -145,58 +130,58 @@
/* lookup all three */
for(i=0; i<3; i++)
{
- printf("Looking up entry %d\n", i);
+ printf("Looking up valid entry [%d]... ", i);
ret = PINT_tcache_lookup(test_tcache, &i, &test_entry, &status);
if(ret < 0)
{
- PVFS_perror("PINT_tcache_lookup", ret);
+ PVFS_perror("\nPINT_tcache_lookup", ret);
return(-1);
}
if(status != 0)
{
- PVFS_perror("PINT_tcache_lookup status", status);
+ PVFS_perror("\nPINT_tcache_lookup status", status);
return(-1);
}
- printf("Done.\n");
tmp_payload = test_entry->payload;
- printf("Value: %f\n", tmp_payload->value);
+ check_param("tcache value", tmp_payload->value, i);
+ printf("Done.\n");
}
/* sleep until at least first expires */
sleep(2);
i=0;
- printf("Looking up expired entry %d\n", i);
+ printf("Looking up expired entry [%d]... ", i);
ret = PINT_tcache_lookup(test_tcache, &i, &test_entry, &status);
if(ret < 0)
{
- PVFS_perror("PINT_tcache_lookup", ret);
+ PVFS_perror("\nPINT_tcache_lookup", ret);
return(-1);
}
- if(status != -PVFS_ETIME)
+ if(status != -PVFS_ETIME) /* The status should be EXPIRED */
{
- PVFS_perror("PINT_tcache_lookup status", status);
+ PVFS_perror("\nPINT_tcache_lookup status", status);
return(-1);
}
- printf("Done.\n");
tmp_payload = test_entry->payload;
- printf("Value: %f\n", tmp_payload->value);
+ check_param("tcache value", tmp_payload->value, i);
+ printf("Done.\n");
i=2;
- printf("Looking up valid entry %d\n", i);
+ printf("Looking up valid entry [%d]... ", i);
ret = PINT_tcache_lookup(test_tcache, &i, &test_entry, &status);
if(ret < 0)
{
- PVFS_perror("PINT_tcache_lookup", ret);
+ PVFS_perror("\nPINT_tcache_lookup", ret);
return(-1);
}
if(status != 0)
{
- PVFS_perror("PINT_tcache_lookup status", status);
+ PVFS_perror("\nPINT_tcache_lookup status", status);
return(-1);
}
- printf("Done.\n");
tmp_payload = test_entry->payload;
- printf("Value: %f\n", tmp_payload->value);
+ check_param("tcache value", tmp_payload->value, i);
+ printf("Done.\n");
/* try destroying an entry */
printf("Destroying an entry...\n");
@@ -209,26 +194,29 @@
printf("Done.\n");
i=2;
- printf("Looking up destroyed entry %d\n", i);
+ printf("Looking up destroyed entry [%d]... ", i);
ret = PINT_tcache_lookup(test_tcache, &i, &test_entry, &status);
- if(ret == 0)
+ if(ret != -PVFS_ENOENT)
{
- PVFS_perror("PINT_tcache_lookup", ret);
+ PVFS_perror("\nPINT_tcache_lookup", ret);
return(-1);
}
printf("Done.\n");
i=200;
- printf("Looking up entry that never existed %d\n", i);
+ printf("Looking up entry that never existed [%d]... ", i);
ret = PINT_tcache_lookup(test_tcache, &i, &test_entry, &status);
- if(ret == 0)
+ if(ret != -PVFS_ENOENT)
{
- PVFS_perror("PINT_tcache_lookup", ret);
+ PVFS_perror("\nPINT_tcache_lookup", ret);
return(-1);
}
printf("Done.\n");
+ /* All entries will be expired after sleep*/
+ printf("Sleeping 5 seconds to expire all entries... ");
sleep(5);
+ printf("Done.\n");
/* insert a new entry */
i=3;
@@ -237,9 +225,9 @@
assert(tmp_payload);
tmp_payload->key = i;
tmp_payload->value = i;
- printf("Inserting %d...\n", i);
- ret = PINT_tcache_insert_entry(test_tcache, &i,
- tmp_payload, &removed);
+ printf("Inserting [%d]... ", i);
+ ret = PINT_tcache_insert_entry(test_tcache, &i, tmp_payload,
+ &tmp_count);
if(ret < 0)
{
PVFS_perror("PINT_tcache_insert", ret);
@@ -247,34 +235,61 @@
}
printf("Done.\n");
- /* reclaim */
- ret = PINT_tcache_reclaim(test_tcache, &reclaimed);
+ /* reclaim. There should be 3 entries... Soft limit is 5, reclaim percentage
+ * is 50. We should reclaim (soft limit) * (reclaim percentage), so we should
+ * reclaim 2 entries, which leaves us with 1 entry
+ */
+ printf("Issuing a reclaim...");
+ ret = PINT_tcache_reclaim(test_tcache, &tmp_count);
if(ret < 0)
{
PVFS_perror("PINT_tcache_reclaim", ret);
return(-1);
}
+ ret = PINT_tcache_get_info(test_tcache, TCACHE_NUM_ENTRIES, ¶m);
+ assert(ret == 0);
+ check_param("TCACHE_NUM_ENTRIES", param, 1);
+ printf("Done.\n");
+ /* Check that reclaim removed the expected entries and that only one entry
+ * exists
+ */
+ printf("Looking up valid entry [%d]... ", i);
+ ret = PINT_tcache_lookup(test_tcache, &i, &test_entry, &status);
+ if(ret < 0)
+ {
+ PVFS_perror("\nPINT_tcache_lookup", ret);
+ return(-1);
+ }
+ if(status != 0)
+ {
+ PVFS_perror("\nPINT_tcache_lookup status", status);
+ return(-1);
+ }
+ tmp_payload = test_entry->payload;
+ check_param("tcache value", tmp_payload->value, i);
+ printf("Done.\n");
+
/* finalize */
- printf("Finalizing cache...\n");
+ printf("Finalizing cache... ");
PINT_tcache_finalize(test_tcache);
printf("Done.\n");
/* initialize */
- printf("Initializing cache...\n");
+ printf("Initializing cache... ");
test_tcache = PINT_tcache_initialize(foo_compare_key_entry,
foo_hash_key,
foo_free_payload,
-1);
if(!test_tcache)
{
- fprintf(stderr, "PINT_tcache_initialize failure.\n");
+ fprintf(stderr, "\nPINT_tcache_initialize failure.\n");
return(-1);
}
printf("Done.\n");
/* disable */
- printf("Disabling...\n");
+ printf("Disabling TCACHE...");
param = 0;
ret = PINT_tcache_set_info(test_tcache, TCACHE_ENABLE, param);
assert(ret == 0);
@@ -289,49 +304,59 @@
tmp_payload->key = i;
tmp_payload->value = i;
- printf("Inserting %d...\n", i);
- ret = PINT_tcache_insert_entry(test_tcache, &i,
- tmp_payload, &removed);
+ printf("Inserting [%d]... ", i);
+ ret = PINT_tcache_insert_entry(test_tcache, &i, tmp_payload,
+ &tmp_count);
if(ret < 0)
{
- PVFS_perror("PINT_tcache_insert", ret);
+ PVFS_perror("\nPINT_tcache_insert", ret);
return(-1);
}
printf("Done.\n");
- sleep(1);
}
+ /* Try and lookup each entry, make sure it doesn't exist */
+ for(i=0; i<3; i++)
+ {
+ printf("Looking up invalid entry [%d]... ", i);
+ ret = PINT_tcache_lookup(test_tcache, &i, &test_entry, &status);
+ if(ret != -PVFS_ENOENT)
+ {
+ PVFS_perror("\nPINT_tcache_lookup", ret);
+ return(-1);
+ }
+ printf("Done.\n");
+ }
+
/* enable */
- printf("Enabling...\n");
+ printf("Enable TCACHE... ");
param = 1;
ret = PINT_tcache_set_info(test_tcache, TCACHE_ENABLE, param);
assert(ret == 0);
printf("Done.\n");
/* set parameters */
- printf("Setting parameters...\n");
- param = 4000;
+ printf("Setting all TCACHE parameters... ");
+ param = TEST_TIMEOUT_MSEC;
ret = PINT_tcache_set_info(test_tcache, TCACHE_TIMEOUT_MSECS, param);
assert(ret == 0);
- param = 30;
+ param = TEST_NUM_ENTRIES;
ret = PINT_tcache_set_info(test_tcache, TCACHE_NUM_ENTRIES, param);
- assert(ret < 0);
- param = 10;
+ assert(ret == -PVFS_EINVAL);
+ param = TEST_HARD_LIMIT;
ret = PINT_tcache_set_info(test_tcache, TCACHE_HARD_LIMIT, param);
assert(ret == 0);
- param = 5;
+ param = TEST_SOFT_LIMIT;
ret = PINT_tcache_set_info(test_tcache, TCACHE_SOFT_LIMIT, param);
assert(ret == 0);
- param = 1;
+ param = TEST_ENABLE;
ret = PINT_tcache_set_info(test_tcache, TCACHE_ENABLE, param);
assert(ret == 0);
- param = 50;
+ param = TEST_RECLAIM_PERCENTAGE;
ret = PINT_tcache_set_info(test_tcache, TCACHE_RECLAIM_PERCENTAGE, param);
assert(ret == 0);
printf("Done.\n");
-
-
/* insert some entries */
for(i=0; i< 5; i++)
{
@@ -341,23 +366,28 @@
tmp_payload->key = i;
tmp_payload->value = i;
- printf("Inserting %d...\n", i);
- ret = PINT_tcache_insert_entry(test_tcache, &i,
- tmp_payload, &removed);
+ printf("Inserting [%d]... ", i);
+ ret = PINT_tcache_insert_entry(test_tcache, &i, tmp_payload,
+ &tmp_count);
if(ret < 0)
{
- PVFS_perror("PINT_tcache_insert", ret);
+ PVFS_perror("\nPINT_tcache_insert", ret);
return(-1);
}
printf("Done.\n");
}
+ /* All entries should be expired after sleep */
+ printf("Sleeping 5 seconds to expire all entries... ");
sleep(5);
+ printf("Done.\n");
/* check num_entries */
+ printf("Checking for 5 entries...");
ret = PINT_tcache_get_info(test_tcache, TCACHE_NUM_ENTRIES, ¶m);
assert(ret == 0);
- printf("num_entries: %d\n", param);
+ check_param("TCACHE_NUM_ENTRIES", param, 5);
+ printf("Done.\n");
/* insert some entries */
for(i=5; i< 6; i++)
@@ -368,21 +398,26 @@
tmp_payload->key = i;
tmp_payload->value = i;
- printf("Inserting %d...\n", i);
- ret = PINT_tcache_insert_entry(test_tcache, &i,
- tmp_payload, &removed);
+ printf("Inserting [%d]... ", i);
+ /* Soft limit is 5, insert of 6th entry should cause a reclaim. 5
+ * expired entries exist. Reclaim of 2 entries should occur
+ */
+ ret = PINT_tcache_insert_entry(test_tcache, &i, tmp_payload,
+ &tmp_count);
if(ret < 0)
{
- PVFS_perror("PINT_tcache_insert", ret);
+ PVFS_perror("\nPINT_tcache_insert", ret);
return(-1);
}
printf("Done.\n");
}
- /* check num_entries */
+ /* check num_entries. Reclaim should have purged 2 entries */
+ printf("Checking RECLAIM occurred during last insert. Should contain 4 entries... ");
ret = PINT_tcache_get_info(test_tcache, TCACHE_NUM_ENTRIES, ¶m);
assert(ret == 0);
- printf("num_entries: %d\n", param);
+ check_param("TCACHE_NUM_ENTRIES", param, 4);
+ printf("Done.\n");
/* insert some entries */
for(i=6; i< 20; i++)
@@ -393,12 +428,16 @@
tmp_payload->key = i;
tmp_payload->value = i;
- printf("Inserting %d...\n", i);
- ret = PINT_tcache_insert_entry(test_tcache, &i,
- tmp_payload, &removed);
+ printf("Inserting [%d]... ", i);
+ /* Inserting should cause reclaims to happen. 3 entries (3-5) are
+ * expired and should be purged. HARD_LIMIT is 10, so only the last
+ * 10 entries should exist
+ */
+ ret = PINT_tcache_insert_entry(test_tcache, &i, tmp_payload,
+ &tmp_count);
if(ret < 0)
{
- PVFS_perror("PINT_tcache_insert", ret);
+ PVFS_perror("\nPINT_tcache_insert", ret);
return(-1);
}
printf("Done.\n");
@@ -407,7 +446,21 @@
/* check num_entries */
ret = PINT_tcache_get_info(test_tcache, TCACHE_NUM_ENTRIES, ¶m);
assert(ret == 0);
- printf("num_entries: %d\n", param);
+ check_param("TCACHE_NUM_ENTRIES", param, TEST_HARD_LIMIT);
+
+ /* Check to make sure the first 10 entries do NOT exist */
+ /* Try and lookup each entry, make sure it doesn't exist */
+ for(i=0; i<10; i++)
+ {
+ printf("Looking up invalid entry [%d]... ", i);
+ ret = PINT_tcache_lookup(test_tcache, &i, &test_entry, &status);
+ if(ret != -PVFS_ENOENT)
+ {
+ PVFS_perror("\nPINT_tcache_lookup", ret);
+ return(-1);
+ }
+ printf("Done.\n");
+ }
return(0);
}
@@ -452,6 +505,19 @@
return(0);
}
+static void check_param(char *parameter_name, int param, int expected_value)
+{
+ if(param != expected_value)
+ {
+ fprintf(stderr, "\n%s does not match expected result\n"
+ "\t%s = %d\n"
+ "\texpected value = %d\n",
+ parameter_name,
+ parameter_name,
+ param,
+ expected_value);
+ }
+}
/*
* Local variables:
* c-indent-level: 4
_______________________________________________
Pvfs2-developers mailing list
[email protected]
http://www.beowulf-underground.org/mailman/listinfo/pvfs2-developers