diff options
Diffstat (limited to 'test_micro/source')
-rw-r--r-- | test_micro/source/LIST | 101 | ||||
-rw-r--r-- | test_micro/source/b_curalloc.c | 69 | ||||
-rw-r--r-- | test_micro/source/b_curwalk.c | 208 | ||||
-rw-r--r-- | test_micro/source/b_del.c | 166 | ||||
-rw-r--r-- | test_micro/source/b_get.c | 162 | ||||
-rw-r--r-- | test_micro/source/b_inmem.c | 426 | ||||
-rw-r--r-- | test_micro/source/b_latch.c | 199 | ||||
-rw-r--r-- | test_micro/source/b_load.c | 164 | ||||
-rw-r--r-- | test_micro/source/b_open.c | 144 | ||||
-rw-r--r-- | test_micro/source/b_put.c | 225 | ||||
-rw-r--r-- | test_micro/source/b_recover.c | 141 | ||||
-rw-r--r-- | test_micro/source/b_txn.c | 93 | ||||
-rw-r--r-- | test_micro/source/b_txn_write.c | 172 | ||||
-rw-r--r-- | test_micro/source/b_uname.c | 147 | ||||
-rw-r--r-- | test_micro/source/b_util.c | 157 | ||||
-rw-r--r-- | test_micro/source/b_workload.c | 631 | ||||
-rw-r--r-- | test_micro/source/b_workload.h | 153 | ||||
-rw-r--r-- | test_micro/source/bench.h | 217 | ||||
-rw-r--r-- | test_micro/source/test_micro.c | 223 |
19 files changed, 3798 insertions, 0 deletions
diff --git a/test_micro/source/LIST b/test_micro/source/LIST new file mode 100644 index 0000000..8c02b4a --- /dev/null +++ b/test_micro/source/LIST @@ -0,0 +1,101 @@ +Test list: + +b_curalloc + Cursor allocation + + usage: b_curalloc [-c count] + + -c Cursor count + +b_curwalk + Walk a cursor through N records + + usage: b_curwalk [-pSs] [-C cachesz] + [-c cnt] [-d dupcnt] [-P pagesz] [-t type] [-w walkcnt] + -C Cache size + -c Record count + -d Duplicate record count + -P Page size + -p Walk backward instead of forward + -S Skip duplicates + -s Sort duplicates + -t Database type (B | H | Q | R) + +b_del + Delete records + + usage: b_del [-w] [-C cachesz] [-c count] [-t type] + + -C Cache size + -c Record count + -t Database type (B | H | Q | R) + -w Delete through cursor + +b_get + Read records + + usage: b_get [-C cachesz] [-c count] [-t type] + + -C Cache size + -c Record count + -t Database type (B | H | Q | R) + +b_load + Insert records + + usage: b_load [-d] [-C cachesz] [-c count] [-t type] + + -C Cache size + -c Record count + -d Use duplicate records + -t Database type (B | H | Q | R) + +b_open + Database open/close + + usage: b_open [-df] [-c count] [-t type] + + -d Open/close a subdatabase + -f Open/close a physical file + -c Open/close count + -t Database type (B | H | Q | R) + +b_put + Overwrite record + + usage: b_put [-C cachesz] + [-c count] [-d bytes] [-s secondaries] [-t type] + + -C Cache size + -c Record count + -d Data size + -s Number of secondaries + -t Database type (B | H | Q | R) + +b_recover + Run recovery + + usage: b_recover [-C cachesz] [-c count] + + -C Cache size + -c Transactions to recover + +b_txn + Abort or commit a transaction containing no operations + + usage: b_txn [-a] [-c count] + + -a Abort rather than commit + -c Transaction count + +b_txn_write + Write/commit transaction + + usage: b_txn_write [-arw] [-c count] + + -a nosync + -c Transaction count + -r Configure replication stub callback + -w write-nosync + +b_workload diff --git a/test_micro/source/b_curalloc.c b/test_micro/source/b_curalloc.c new file mode 100644 index 0000000..410d720 --- /dev/null +++ b/test_micro/source/b_curalloc.c @@ -0,0 +1,69 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); + +int +b_curalloc(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *dbp; + DBC *curp; + int ch, i, count; + + count = 100000; + while ((ch = getopt(argc, argv, "c:")) != EOF) + switch (ch) { + case 'c': + count = atoi(optarg); + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* Create the database. */ + DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); + dbp->set_errfile(dbp, stderr); + +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT(dbp->open( + dbp, NULL, TESTFILE, NULL, DB_BTREE, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT( + dbp->open(dbp, TESTFILE, NULL, DB_BTREE, DB_CREATE, 0666) == 0); +#endif + + /* Allocate a cursor count times. */ + TIMER_START; + for (i = 0; i < count; ++i) { + DB_BENCH_ASSERT(dbp->cursor(dbp, NULL, &curp, 0) == 0); + DB_BENCH_ASSERT(curp->c_close(curp) == 0); + } + TIMER_STOP; + + printf("# %d cursor allocations\n", count); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, "usage: b_curalloc [-c count]\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_curwalk.c b/test_micro/source/b_curwalk.c new file mode 100644 index 0000000..8e935f2 --- /dev/null +++ b/test_micro/source/b_curwalk.c @@ -0,0 +1,208 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); + +int +b_curwalk(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *dbp; + DBTYPE type; + DBC *dbc; + DBT key, data; + db_recno_t recno; + u_int32_t cachesize, pagesize, walkflags; + int ch, i, count, dupcount, j; + int prev, ret, skipdupwalk, sorted, walkcount; + char *ts, dbuf[32], kbuf[32]; + + type = DB_BTREE; + cachesize = 10 * MEGABYTE; + pagesize = 16 * 1024; + count = 100000; + dupcount = prev = skipdupwalk = sorted = 0; + walkcount = 1000; + ts = "Btree"; + while ((ch = getopt(argc, argv, "C:c:d:P:pSst:w:")) != EOF) + switch (ch) { + case 'C': + cachesize = (u_int32_t)atoi(optarg); + break; + case 'c': + count = atoi(optarg); + break; + case 'd': + dupcount = atoi(optarg); + break; + case 'P': + pagesize = (u_int32_t)atoi(optarg); + break; + case 'p': + prev = 1; + break; + case 'S': + skipdupwalk = 1; + break; + case 's': + sorted = 1; + break; + case 't': + switch (optarg[0]) { + case 'B': case 'b': + ts = "Btree"; + type = DB_BTREE; + break; + case 'H': case 'h': + if (b_util_have_hash()) + return (0); + ts = "Hash"; + type = DB_HASH; + break; + case 'Q': case 'q': + if (b_util_have_queue()) + return (0); + ts = "Queue"; + type = DB_QUEUE; + break; + case 'R': case 'r': + ts = "Recno"; + type = DB_RECNO; + break; + default: + return (usage()); + } + break; + case 'w': + walkcount = atoi(optarg); + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* + * Queue and Recno don't support duplicates. + */ + if (dupcount != 0 && (type == DB_QUEUE || type == DB_RECNO)) { + fprintf(stderr, + "b_curwalk: Queue and Recno don't support duplicates\n"); + return (usage()); + } + +#if DB_VERSION_MAJOR < 3 || DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0 +#define DB_PREV_NODUP 0 + /* + * DB_PREV_NODUP wasn't available until after 3.0.55. + * + * For some reason, testing sorted duplicates doesn't work either. + * I don't really care about 3.0.55 any more, just ignore it. + */ + return (0); +#endif + /* Create the database. */ + DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); + DB_BENCH_ASSERT(dbp->set_cachesize(dbp, 0, cachesize, 0) == 0); + DB_BENCH_ASSERT(dbp->set_pagesize(dbp, pagesize) == 0); + dbp->set_errfile(dbp, stderr); + + /* Set record length for Queue. */ + if (type == DB_QUEUE) + DB_BENCH_ASSERT(dbp->set_re_len(dbp, 20) == 0); + + /* Set duplicates flag. */ + if (dupcount != 0) + DB_BENCH_ASSERT( + dbp->set_flags(dbp, sorted ? DB_DUPSORT : DB_DUP) == 0); + +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT(dbp->open( + dbp, NULL, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbp->open( + dbp, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#endif + + /* Initialize the data. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* Insert count in-order key/data pairs. */ + data.data = dbuf; + data.size = 20; + if (type == DB_BTREE || type == DB_HASH) { + key.size = 10; + key.data = kbuf; + for (i = 0; i < count; ++i) { + (void)snprintf(kbuf, sizeof(kbuf), "%010d", i); + for (j = 0; j <= dupcount; ++j) { + (void)snprintf(dbuf, sizeof(dbuf), "%020d", j); + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + } + } else { + key.data = &recno; + key.size = sizeof(recno); + for (i = 0, recno = 1; i < count; ++i, ++recno) + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + + walkflags = prev ? + (skipdupwalk ? DB_PREV_NODUP : DB_PREV) : + (skipdupwalk ? DB_NEXT_NODUP : DB_NEXT); + + /* Walk the cursor through the tree N times. */ + TIMER_START; + for (i = 0; i < walkcount; ++i) { + DB_BENCH_ASSERT(dbp->cursor(dbp, NULL, &dbc, 0) == 0); + while ((ret = dbc->c_get(dbc, &key, &data, walkflags)) == 0) + ; + DB_BENCH_ASSERT(ret == DB_NOTFOUND); + DB_BENCH_ASSERT(dbc->c_close(dbc) == 0); + } + TIMER_STOP; + + printf("# %d %s %s cursor of %d 10/20 byte key/data items", + walkcount, ts, prev ? + (skipdupwalk ? "DB_PREV_NODUP" : "DB_PREV") : + (skipdupwalk ? "DB_NEXT_NODUP" : "DB_NEXT"), + count); + if (dupcount != 0) + printf(" with %d dups", dupcount); + printf("\n"); + + /* + * An "operation" is traversal of a single key/data pair -- not a + * return of the key/data pair, since some versions of this test + * skip duplicate key/data pairs. + * + * Use a "double" so we don't overflow. + */ + TIMER_DISPLAY((double)count * walkcount); + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + + return (EXIT_SUCCESS); +} + +static int +usage() +{ + (void)fprintf(stderr, "%s\n\t%s\n", + "usage: b_curwalk [-pSs] [-C cachesz]", + "[-c cnt] [-d dupcnt] [-P pagesz] [-t type] [-w walkcnt]"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_del.c b/test_micro/source/b_del.c new file mode 100644 index 0000000..6385267 --- /dev/null +++ b/test_micro/source/b_del.c @@ -0,0 +1,166 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); + +int +b_del(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *dbp; + DBC *dbc; + DBT key, data; + DBTYPE type; + db_recno_t recno; + u_int32_t cachesize; + int ch, i, count, ret, use_cursor; + char *ts, buf[32]; + + type = DB_BTREE; + cachesize = MEGABYTE; + count = 100000; + use_cursor = 0; + ts = "Btree"; + while ((ch = getopt(argc, argv, "C:c:t:w")) != EOF) + switch (ch) { + case 'C': + cachesize = (u_int32_t)atoi(optarg); + break; + case 'c': + count = atoi(optarg); + break; + case 't': + switch (optarg[0]) { + case 'B': case 'b': + ts = "Btree"; + type = DB_BTREE; + break; + case 'H': case 'h': + if (b_util_have_hash()) + return (0); + ts = "Hash"; + type = DB_HASH; + break; + case 'Q': case 'q': + if (b_util_have_queue()) + return (0); + ts = "Queue"; + type = DB_QUEUE; + break; + case 'R': case 'r': + ts = "Recno"; + type = DB_RECNO; + break; + default: + return (usage()); + } + break; + case 'w': + use_cursor = 1; + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* Create the database. */ + DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); + DB_BENCH_ASSERT(dbp->set_cachesize(dbp, 0, cachesize, 0) == 0); + dbp->set_errfile(dbp, stderr); + + /* Set record length for Queue. */ + if (type == DB_QUEUE) + DB_BENCH_ASSERT(dbp->set_re_len(dbp, 20) == 0); + +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT( + dbp->open(dbp, NULL, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT( + dbp->open(dbp, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#endif + + /* Initialize the data. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + data.data = "01234567890123456789"; + data.size = 20; + + /* Store a key/data pair. */ + switch (type) { + case DB_BTREE: + case DB_HASH: + key.data = buf; + key.size = 10; + break; + case DB_QUEUE: + case DB_RECNO: + key.data = &recno; + key.size = sizeof(recno); + break; + case DB_UNKNOWN: + b_util_abort(); + break; + } + + /* Insert count in-order key/data pairs. */ + if (type == DB_BTREE || type == DB_HASH) + for (i = 0; i < count; ++i) { + (void)snprintf(buf, sizeof(buf), "%010d", i); + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + else + for (i = 0, recno = 1; i < count; ++i, ++recno) + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + + /* Delete the records. */ + TIMER_START; + if (use_cursor) { + DB_BENCH_ASSERT(dbp->cursor(dbp, NULL, &dbc, 0) == 0); + while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) + DB_BENCH_ASSERT(dbc->c_del(dbc, 0) == 0); + DB_BENCH_ASSERT (ret == DB_NOTFOUND); + } else + if (type == DB_BTREE || type == DB_HASH) + for (i = 0; i < count; ++i) { + (void)snprintf(buf, sizeof(buf), "%010d", i); + DB_BENCH_ASSERT( + dbp->del(dbp, NULL, &key, 0) == 0); + } + else + for (i = 0, recno = 1; i < count; ++i, ++recno) + DB_BENCH_ASSERT( + dbp->del(dbp, NULL, &key, 0) == 0); + + TIMER_STOP; + + printf( + "# %d %s database in-order delete of 10/20 byte key/data pairs using %s\n", + count, ts, use_cursor ? "a cursor" : "the key"); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, + "usage: b_del [-w] [-C cachesz] [-c count] [-t type]\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_get.c b/test_micro/source/b_get.c new file mode 100644 index 0000000..b63f02a --- /dev/null +++ b/test_micro/source/b_get.c @@ -0,0 +1,162 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); + +u_int32_t part_callback(dbp, dbt) + DB *dbp; + DBT *dbt; +{ + extern u_int32_t __ham_func2(DB *, const void *, u_int32_t); + return (__ham_func2(dbp, dbt->data, dbt->size)); +} + +int +b_get(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *dbp; + DBTYPE type; + DBT key, data; + db_recno_t recno; + u_int32_t cachesize; + int ch, i, count; + char *ts; + + type = DB_BTREE; + cachesize = MEGABYTE; + count = 100000; + ts = "Btree"; + while ((ch = getopt(argc, argv, "C:c:t:")) != EOF) + switch (ch) { + case 'C': + cachesize = (u_int32_t)atoi(optarg); + break; + case 'c': + count = atoi(optarg); + break; + case 't': + switch (optarg[0]) { + case 'B': case 'b': + ts = "Btree"; + type = DB_BTREE; + break; + case 'H': case 'h': + if (b_util_have_hash()) + return (0); + ts = "Hash"; + type = DB_HASH; + break; + case 'Q': case 'q': + if (b_util_have_queue()) + return (0); + ts = "Queue"; + type = DB_QUEUE; + break; + case 'R': case 'r': + ts = "Recno"; + type = DB_RECNO; + break; + default: + return (usage()); + } + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* Create the database. */ + DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); + DB_BENCH_ASSERT(dbp->set_cachesize(dbp, 0, cachesize, 0) == 0); + dbp->set_errfile(dbp, stderr); + + /* Set record length for Queue. */ + if (type == DB_QUEUE) + DB_BENCH_ASSERT(dbp->set_re_len(dbp, 10) == 0); +#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 7 && DB_VERSION_PATCH == 30 + if (type == DB_BTREE) { + DBT keys[3]; + + memset(keys, 0, sizeof(keys)); + keys[0].data = "a"; + keys[0].size = 1; + keys[1].data = "b"; + keys[1].size = 1; + keys[2].data = "c"; + keys[2].size = 1; + + DB_BENCH_ASSERT( + dbp->set_partition_keys(dbp, 4, keys, NULL) == 0); + } + + if (type == DB_HASH) { + DB_BENCH_ASSERT( + dbp->set_partition_callback(dbp, 4, part_callback) == 0); + } +#endif + +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT( + dbp->open(dbp, NULL, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT( + dbp->open(dbp, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#endif + + /* Store a key/data pair. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + switch (type) { + case DB_BTREE: + case DB_HASH: + key.data = "aaaaa"; + key.size = 5; + break; + case DB_QUEUE: + case DB_RECNO: + recno = 1; + key.data = &recno; + key.size = sizeof(recno); + break; + case DB_UNKNOWN: + b_util_abort(); + break; + } + data.data = "bbbbb"; + data.size = 5; + + DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); + + /* Retrieve the key/data pair count times. */ + TIMER_START; + for (i = 0; i < count; ++i) + DB_BENCH_ASSERT(dbp->get(dbp, NULL, &key, &data, 0) == 0); + TIMER_STOP; + + printf("# %d %s database get of cached key/data item\n", count, ts); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, + "usage: b_get [-C cachesz] [-c count] [-t type]\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_inmem.c b/test_micro/source/b_inmem.c new file mode 100644 index 0000000..ee0ddda --- /dev/null +++ b/test_micro/source/b_inmem.c @@ -0,0 +1,426 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "bench.h" + +#if DB_VERSION_MAJOR > 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0 +/* + * The in-memory tests don't run on early releases of Berkeley DB. + */ +#undef MEGABYTE +#define MEGABYTE (1024 * 1024) + +u_int32_t bulkbufsize = 4 * MEGABYTE; +u_int32_t cachesize = 32 * MEGABYTE; +u_int32_t datasize = 32; +u_int32_t keysize = 8; +u_int32_t logbufsize = 8 * MEGABYTE; +u_int32_t numitems; +u_int32_t pagesize = 32 * 1024; + +FILE *fp; + +static void op_ds __P((u_int, int)); +static void op_ds_bulk __P((u_int, u_int *)); +static void op_tds __P((u_int, int, u_int32_t, u_int32_t)); +static int usage __P((void)); + +static void +op_ds(u_int ops, int update) +{ + DB_ENV *dbenv; + char *letters = "abcdefghijklmnopqrstuvwxuz"; + DB *dbp; + DBT key, data; + char *keybuf, *databuf; + DB_MPOOL_STAT *gsp; + + DB_BENCH_ASSERT((keybuf = malloc(keysize)) != NULL); + DB_BENCH_ASSERT((databuf = malloc(datasize)) != NULL); + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = keybuf; + key.size = keysize; + memset(keybuf, 'a', keysize); + + data.data = databuf; + data.size = datasize; + memset(databuf, 'b', datasize); + + DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); + dbenv = dbp->dbenv; + dbp->set_errfile(dbp, stderr); + + DB_BENCH_ASSERT(dbp->set_pagesize(dbp, pagesize) == 0); + DB_BENCH_ASSERT(dbp->open( + dbp, NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0666) == 0); + + (void)dbenv->memp_stat(dbenv, &gsp, NULL, DB_STAT_CLEAR); + + if (update) { + TIMER_START; + for (; ops > 0; --ops) { + keybuf[(ops % keysize)] = letters[(ops % 26)]; + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + TIMER_STOP; + } else { + DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); + TIMER_START; + for (; ops > 0; --ops) + DB_BENCH_ASSERT( + dbp->get(dbp, NULL, &key, &data, 0) == 0); + TIMER_STOP; + } + + if (dbenv->memp_stat(dbenv, &gsp, NULL, 0) == 0) + DB_BENCH_ASSERT(gsp->st_cache_miss == 0); + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); +} + +static void +op_ds_bulk(u_int ops, u_int *totalp) +{ + DB_ENV *dbenv; + DB *dbp; + DBC *dbc; + DBT key, data; + u_int32_t len, klen; + u_int i, total; + char *keybuf, *databuf; + void *pointer, *dp, *kp; + DB_MPOOL_STAT *gsp; + + DB_BENCH_ASSERT((keybuf = malloc(keysize)) != NULL); + DB_BENCH_ASSERT((databuf = malloc(bulkbufsize)) != NULL); + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = keybuf; + key.size = keysize; + + data.data = databuf; + data.size = datasize; + memset(databuf, 'b', datasize); + + DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); + dbenv = dbp->dbenv; + dbp->set_errfile(dbp, stderr); + + DB_BENCH_ASSERT(dbp->set_pagesize(dbp, pagesize) == 0); + DB_BENCH_ASSERT(dbp->set_cachesize(dbp, 0, cachesize, 1) == 0); + DB_BENCH_ASSERT( + dbp->open(dbp, NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0666) == 0); + + for (i = 1; i <= numitems; ++i) { + (void)snprintf(keybuf, keysize, "%7d", i); + DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + +#if 0 + fp = fopen("before", "w"); + dbp->set_msgfile(dbp, fp); + DB_BENCH_ASSERT (dbp->stat_print(dbp, DB_STAT_ALL) == 0); +#endif + + DB_BENCH_ASSERT(dbp->cursor(dbp, NULL, &dbc, 0) == 0); + + data.ulen = bulkbufsize; + data.flags = DB_DBT_USERMEM; + + (void)dbenv->memp_stat(dbenv, &gsp, NULL, DB_STAT_CLEAR); + + TIMER_START; + for (total = 0; ops > 0; --ops) { + DB_BENCH_ASSERT(dbc->c_get( + dbc, &key, &data, DB_FIRST | DB_MULTIPLE_KEY) == 0); + DB_MULTIPLE_INIT(pointer, &data); + while (pointer != NULL) { + DB_MULTIPLE_KEY_NEXT(pointer, &data, kp, klen, dp, len); + if (kp != NULL) + ++total; + } + } + TIMER_STOP; + *totalp = total; + + if (dbenv->memp_stat(dbenv, &gsp, NULL, 0) == 0) + DB_BENCH_ASSERT(gsp->st_cache_miss == 0); + +#if 0 + fp = fopen("before", "w"); + dbp->set_msgfile(dbp, fp); + DB_BENCH_ASSERT (dbp->stat_print(dbp, DB_STAT_ALL) == 0); +#endif + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + + COMPQUIET(dp, NULL); + COMPQUIET(klen, 0); + COMPQUIET(len, 0); +} + +static void +op_tds(u_int ops, int update, u_int32_t env_flags, u_int32_t log_flags) +{ + DB *dbp; + DBT key, data; + DB_ENV *dbenv; + DB_MPOOL_STAT *gsp; + DB_TXN *txn; + char *keybuf, *databuf; + + DB_BENCH_ASSERT((keybuf = malloc(keysize)) != NULL); + DB_BENCH_ASSERT((databuf = malloc(datasize)) != NULL); + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = keybuf; + key.size = keysize; + memset(keybuf, 'a', keysize); + + data.data = databuf; + data.size = datasize; + memset(databuf, 'b', datasize); + + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + + dbenv->set_errfile(dbenv, stderr); + + /* General environment configuration. */ +#ifdef DB_AUTO_COMMIT + DB_BENCH_ASSERT(dbenv->set_flags(dbenv, DB_AUTO_COMMIT, 1) == 0); +#endif + if (env_flags != 0) + DB_BENCH_ASSERT(dbenv->set_flags(dbenv, env_flags, 1) == 0); + + /* Logging configuration. */ + if (log_flags != 0) +#if DB_VERSION_MINOR >= 7 + DB_BENCH_ASSERT( + dbenv->log_set_config(dbenv, log_flags, 1) == 0); +#else + DB_BENCH_ASSERT(dbenv->set_flags(dbenv, log_flags, 1) == 0); +#endif +#ifdef DB_LOG_INMEMORY + if (!(log_flags & DB_LOG_INMEMORY)) +#endif +#ifdef DB_LOG_IN_MEMORY + if (!(log_flags & DB_LOG_IN_MEMORY)) +#endif + DB_BENCH_ASSERT(dbenv->set_lg_max(dbenv, logbufsize * 10) == 0); + DB_BENCH_ASSERT(dbenv->set_lg_bsize(dbenv, logbufsize) == 0); + + DB_BENCH_ASSERT(dbenv->open(dbenv, "TESTDIR", + DB_CREATE | DB_PRIVATE | DB_INIT_LOCK | + DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN, 0666) == 0); + + DB_BENCH_ASSERT(db_create(&dbp, dbenv, 0) == 0); + DB_BENCH_ASSERT(dbp->set_pagesize(dbp, pagesize) == 0); + DB_BENCH_ASSERT(dbp->open( + dbp, NULL, TESTFILE, NULL, DB_BTREE, DB_CREATE, 0666) == 0); + + if (update) { + (void)dbenv->memp_stat(dbenv, &gsp, NULL, DB_STAT_CLEAR); + + TIMER_START; + for (; ops > 0; --ops) + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + TIMER_STOP; + + if (dbenv->memp_stat(dbenv, &gsp, NULL, 0) == 0) + DB_BENCH_ASSERT(gsp->st_page_out == 0); + } else { + DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); + (void)dbenv->memp_stat(dbenv, &gsp, NULL, DB_STAT_CLEAR); + + TIMER_START; + for (; ops > 0; --ops) { + DB_BENCH_ASSERT( + dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0); + DB_BENCH_ASSERT( + dbp->get(dbp, NULL, &key, &data, 0) == 0); + DB_BENCH_ASSERT(txn->commit(txn, 0) == 0); + } + TIMER_STOP; + + if (dbenv->memp_stat(dbenv, &gsp, NULL, 0) == 0) + DB_BENCH_ASSERT(gsp->st_cache_miss == 0); + } + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); +} + +#define DEFAULT_OPS 1000000 + +int +b_inmem(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + u_int ops, total; + int ch; + + if ((progname = strrchr(argv[0], '/')) == NULL) + progname = argv[0]; + else + ++progname; + + ops = 0; + while ((ch = getopt(argc, argv, "b:C:d:k:l:o:P:")) != EOF) + switch (ch) { + case 'b': + bulkbufsize = (u_int32_t)atoi(optarg); + break; + case 'C': + cachesize = (u_int32_t)atoi(optarg); + break; + case 'd': + datasize = (u_int)atoi(optarg); + break; + case 'k': + keysize = (u_int)atoi(optarg); + break; + case 'l': + logbufsize = (u_int32_t)atoi(optarg); + break; + case 'o': + ops = (u_int)atoi(optarg); + break; + case 'P': + pagesize = (u_int32_t)atoi(optarg); + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + + if (argc != 1) + return (usage()); + + numitems = (cachesize / (keysize + datasize - 1)) / 2; + + if (strcasecmp(argv[0], "read") == 0) { + if (ops == 0) + ops = DEFAULT_OPS; + op_ds(ops, 0); + printf( + "# %u in-memory Btree database reads of %u/%u byte key/data pairs\n", + ops, keysize, datasize); + } else if (strcasecmp(argv[0], "bulk") == 0) { + if (keysize < 8) { + fprintf(stderr, + "%s: bulk read requires a key size >= 10\n", progname); + return (EXIT_FAILURE); + } + /* + * The ops value is the number of bulk operations, not key get + * operations. Reduce the value so the test doesn't take so + * long, and use the returned number of retrievals as the ops + * value for timing purposes. + */ + if (ops == 0) + ops = 100000; + op_ds_bulk(ops, &total); + ops = total; + printf( + "# %u bulk in-memory Btree database reads of %u/%u byte key/data pairs\n", + ops, keysize, datasize); + } else if (strcasecmp(argv[0], "write") == 0) { + if (ops == 0) + ops = DEFAULT_OPS; + op_ds(ops, 1); + printf( + "# %u in-memory Btree database writes of %u/%u byte key/data pairs\n", + ops, keysize, datasize); + } else if (strcasecmp(argv[0], "txn-read") == 0) { + if (ops == 0) + ops = DEFAULT_OPS; + op_tds(ops, 0, 0, 0); + printf( + "# %u transactional in-memory Btree database reads of %u/%u %s", + ops, keysize, datasize, "byte key/data pairs\n"); + } else if (strcasecmp(argv[0], "txn-write") == 0) { + if (ops == 0) + ops = DEFAULT_OPS; +#if defined(DB_LOG_INMEMORY) || defined(DB_LOG_IN_MEMORY) +#if defined(DB_LOG_INMEMORY) + op_tds(ops, 1, 0, DB_LOG_INMEMORY); +#else + op_tds(ops, 1, 0, DB_LOG_IN_MEMORY); +#endif + printf( + "# %u transactional in-memory logging Btree database writes of %u/%u%s", + ops, keysize, datasize, " byte key/data pairs\n"); +#else + return (EXIT_SUCCESS); +#endif + } else if (strcasecmp(argv[0], "txn-nosync") == 0) { + if (ops == 0) + ops = DEFAULT_OPS; + op_tds(ops, 1, DB_TXN_NOSYNC, 0); + printf( + "# %u transactional nosync logging Btree database writes of %u/%u %s", + ops, keysize, datasize, "byte key/data pairs\n"); + } else if (strcasecmp(argv[0], "txn-write-nosync") == 0) { + if (ops == 0) + ops = DEFAULT_OPS; +#ifdef DB_TXN_WRITE_NOSYNC + op_tds(ops, 1, DB_TXN_WRITE_NOSYNC, 0); + printf( + "# %u transactional OS-write/nosync logging Btree database writes of %u/%u%s", + ops, keysize, datasize, " byte key/data pairs\n"); +#else + return (EXIT_SUCCESS); +#endif + } else if (strcasecmp(argv[0], "txn-sync") == 0) { + /* + * Flushing to disk takes a long time, reduce the number of + * default ops. + */ + if (ops == 0) + ops = 100000; + op_tds(ops, 1, 0, 0); + printf( + "# %u transactional logging Btree database writes of %u/%u %s", + ops, keysize, datasize, "byte key/data pairs\n"); + } else { + fprintf(stderr, "%s: unknown keyword %s\n", progname, argv[0]); + return (EXIT_FAILURE); + } + + TIMER_DISPLAY(ops); + return (EXIT_SUCCESS); +} + +static int +usage() +{ + fprintf(stderr, "usage: %s %s%s%s%s", + progname, "[-b bulkbufsz] [-C cachesz]\n\t", + "[-d datasize] [-k keysize] [-l logbufsz] [-o ops] [-P pagesz]\n\t", + "[read | bulk | write | txn-read |\n\t", + "txn-write | txn-nosync | txn-write-nosync | txn-sync]\n"); + return (EXIT_FAILURE); +} +#else +int +b_inmem(int argc, char *argv[]) +{ + COMPQUIET(argc, 0); + COMPQUIET(argv, NULL); + return (0); +} +#endif diff --git a/test_micro/source/b_latch.c b/test_micro/source/b_latch.c new file mode 100644 index 0000000..83ae181 --- /dev/null +++ b/test_micro/source/b_latch.c @@ -0,0 +1,199 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "bench.h" + +#ifdef _POSIX_THREADS +typedef struct { + pthread_t id; + DB_ENV *dbenv; + int iterations; + db_mutex_t mutex; + int contentions; +} threadinfo_t; + +static void *latch_threadmain __P((void *)); +#endif + +static int time_latches __P((DB_ENV *, db_mutex_t, int)); + +#define LATCH_THREADS_MAX 100 + +/* Return the environment needed for __mutex_lock(), depending on release. + */ +#if DB_VERSION_MAJOR <4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 7 +#define ENV_ARG(dbenv) (dbenv) +#else +#define ENV_ARG(dbenv) ((dbenv)->env) +#endif + +/* + * In the mulithreaded latch test each thread locks and updates this variable. + * It detects contention when the value of this counter changes during the + * mutex lock call. + */ +static int CurrentCounter = 0; +static int latch_usage __P((void)); + +static int +latch_usage() +{ + (void)fprintf(stderr, "usage: b_latch [-c number of %s", + "lock+unlock pairs] [-n number of threads]\n"); + return (EXIT_FAILURE); +} + +/* + * time_latches -- + * Repeat acquire and release of an exclusive latch, counting the + * number of times that 'someone else' got it just as we tried to. + */ +static int time_latches(dbenv, mutex, iterations) + DB_ENV *dbenv; + db_mutex_t mutex; + int iterations; +{ + int contended, i, previous; + + contended = 0; + for (i = 0; i < iterations; ++i) { + previous = CurrentCounter; + DB_BENCH_ASSERT(__mutex_lock(ENV_ARG(dbenv), mutex) == 0); + if (previous != CurrentCounter) + contended++; + CurrentCounter++; + DB_BENCH_ASSERT(__mutex_unlock(ENV_ARG(dbenv), mutex) == 0); + } + return (contended); +} + +#ifdef _POSIX_THREADS +/* + * latch_threadmain -- + * Entry point for multithreaded latching test. + * + * Currently only supported for POSIX threads. + */ +static void * +latch_threadmain(arg) + void *arg; +{ + threadinfo_t *info = arg; + + info->contentions = time_latches(info->dbenv, + info->mutex, info->iterations); + + return ((void *) 0); +} +#endif + +/* + * b_latch -- + * Measure the speed of latching and mutex operations. + * + * + */ +int +b_latch(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DB_ENV *dbenv; + int ch, count, nthreads; +#ifdef _POSIX_THREADS + threadinfo_t threads[LATCH_THREADS_MAX]; + int i, ret; + void *status; +#endif + db_mutex_t mutex; + int contended; + + contended = 0; + count = 1000000; + nthreads = 0; /* Default to running the test without extra threads */ + while ((ch = getopt(argc, argv, "c:n:")) != EOF) + switch (ch) { + case 'c': + count = atoi(optarg); + break; + case 'n': + nthreads = atoi(optarg); + break; + case '?': + default: + return (latch_usage()); + } + argc -= optind; + argv += optind; + if (argc != 0 || count < 1 || nthreads < 0 || + nthreads > LATCH_THREADS_MAX) + return (latch_usage()); +#ifndef _POSIX_THREADS + if (nthreads > 1) { + (void)fprintf(stderr, + "Sorry, support for -n %d: threads not yet available\n", + nthreads); + exit(EXIT_FAILURE); + } +#endif + + /* Create the environment. */ + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + dbenv->set_errfile(dbenv, stderr); +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 1 + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, + NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE, 0666) == 0); +#endif + DB_BENCH_ASSERT(dbenv->mutex_alloc(dbenv, DB_MUTEX_SELF_BLOCK, + &mutex) == 0); +#ifdef _POSIX_THREADS + for (i = 0; i < nthreads; i++) { + threads[i].dbenv = dbenv; + threads[i].mutex = mutex; + threads[i].iterations = + nthreads <= 1 ? count : count / nthreads; + } +#endif + + /* Start and acquire and release a mutex count times. If there's + * posix support and a non-zero number of threads start them. + */ + TIMER_START; +#ifdef _POSIX_THREADS + if (nthreads > 0) { + for (i = 0; i < nthreads; i++) + DB_BENCH_ASSERT(pthread_create(&threads[i].id, + NULL, latch_threadmain, &threads[i]) == 0); + for (i = 0; i < nthreads; i++) { + ret = pthread_join(threads[i].id, &status); + DB_BENCH_ASSERT(ret == 0); + contended += threads[i].contentions; + } + + } else +#endif + contended = time_latches(dbenv, mutex, count); + TIMER_STOP; + + printf("# %d mutex lock-unlock pairs of %d thread%s\n", count, + nthreads, nthreads == 1 ? "" : "s"); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbenv->mutex_free(dbenv, mutex) == 0); + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); + COMPQUIET(contended, 0); + + return (0); +} diff --git a/test_micro/source/b_load.c b/test_micro/source/b_load.c new file mode 100644 index 0000000..9cbb968 --- /dev/null +++ b/test_micro/source/b_load.c @@ -0,0 +1,164 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); + +int +b_load(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *dbp; + DBTYPE type; + DBT key, data; + db_recno_t recno; + u_int32_t cachesize; + int ch, i, count, duplicate; + char *ts, buf[32]; + + type = DB_BTREE; + cachesize = MEGABYTE; + count = 100000; + duplicate = 0; + ts = "Btree"; + while ((ch = getopt(argc, argv, "C:c:dt:")) != EOF) + switch (ch) { + case 'C': + cachesize = (u_int32_t)atoi(optarg); + break; + case 'c': + count = atoi(optarg); + break; + case 'd': + duplicate = 1; + break; + case 't': + switch (optarg[0]) { + case 'B': case 'b': + ts = "Btree"; + type = DB_BTREE; + break; + case 'H': case 'h': + if (b_util_have_hash()) + return (0); + ts = "Hash"; + type = DB_HASH; + break; + case 'Q': case 'q': + if (b_util_have_queue()) + return (0); + ts = "Queue"; + type = DB_QUEUE; + break; + case 'R': case 'r': + ts = "Recno"; + type = DB_RECNO; + break; + default: + return (usage()); + } + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* Usage. */ + if (duplicate && (type == DB_QUEUE || type == DB_RECNO)) { + fprintf(stderr, + "b_load: Queue an Recno don't support duplicates\n"); + return (usage()); + } + +#if DB_VERSION_MAJOR < 3 || DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 1 + /* + * DB versions prior to 3.1.17 didn't have off-page duplicates, so + * this test can run forever. + */ + if (duplicate) + return (0); +#endif + + /* Create the database. */ + DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); + DB_BENCH_ASSERT(dbp->set_cachesize(dbp, 0, cachesize, 0) == 0); + if (duplicate) + DB_BENCH_ASSERT(dbp->set_flags(dbp, DB_DUP) == 0); + dbp->set_errfile(dbp, stderr); + + /* Set record length for Queue. */ + if (type == DB_QUEUE) + DB_BENCH_ASSERT(dbp->set_re_len(dbp, 20) == 0); + +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT( + dbp->open(dbp, NULL, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT( + dbp->open(dbp, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#endif + + /* Initialize the data. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* Insert count in-order key/data pairs. */ + TIMER_START; + if (duplicate) { + key.size = 10; + key.data = "01234567890123456789"; + data.data = buf; + data.size = 20; + for (i = 0; i < count; ++i) { + (void)snprintf(buf, sizeof(buf), "%020d", i); + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + } else { + data.data = buf; + data.size = 20; + if (type == DB_BTREE || type == DB_HASH) { + key.size = 10; + key.data = buf; + for (i = 0; i < count; ++i) { + (void)snprintf(buf, sizeof(buf), "%010d", i); + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + } else { + key.data = &recno; + key.size = sizeof(recno); + for (i = 0, recno = 1; i < count; ++i, ++recno) + DB_BENCH_ASSERT( + dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + } + + TIMER_STOP; + + printf("# %d %s database in-order put of 10/20 byte key/data %sitems\n", + count, ts, duplicate ? "duplicate " : ""); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, + "usage: b_load [-d] [-C cachesz] [-c count] [-t type]\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_open.c b/test_micro/source/b_open.c new file mode 100644 index 0000000..1c47e43 --- /dev/null +++ b/test_micro/source/b_open.c @@ -0,0 +1,144 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); + +int +b_open(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB_ENV *dbenv; + DB *dbp; + DBTYPE type; + int ch, i, count; + char *fname, *dbname, *ts; + + type = DB_BTREE; + count = 1000; + fname = dbname = NULL; + ts = "Btree"; + while ((ch = getopt(argc, argv, "c:dft:")) != EOF) + switch (ch) { + case 'c': + count = atoi(optarg); + break; + case 'd': + dbname = "dbname"; + break; + case 'f': + fname = "filename"; + break; + case 't': + switch (optarg[0]) { + case 'B': case 'b': + ts = "Btree"; + type = DB_BTREE; + break; + case 'H': case 'h': + if (b_util_have_hash()) + return (0); + ts = "Hash"; + type = DB_HASH; + break; + case 'Q': case 'q': + if (b_util_have_queue()) + return (0); + ts = "Queue"; + type = DB_QUEUE; + break; + case 'R': case 'r': + ts = "Recno"; + type = DB_RECNO; + break; + default: + return (usage()); + } + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + +#if DB_VERSION_MAJOR < 4 + /* + * Don't run in-memory database tests on versions less than 3, it + * takes forever and eats memory. + */ + if (fname == NULL && dbname == NULL) + return (0); +#endif +#if DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 4 + /* + * Named in-memory databases weren't available until 4.4. + */ + if (fname == NULL && dbname != NULL) + return (0); +#endif + + /* Create the environment. */ + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + dbenv->set_errfile(dbenv, stderr); +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0 + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, + NULL, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, + DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0666) == 0); +#endif + + /* Create the database. */ + DB_BENCH_ASSERT(db_create(&dbp, dbenv, 0) == 0); + +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT(dbp->open( + dbp, NULL, fname, dbname, type, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbp->open( + dbp, fname, dbname, type, DB_CREATE, 0666) == 0); +#endif + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + + /* Open the database count times. */ + TIMER_START; + for (i = 0; i < count; ++i) { + DB_BENCH_ASSERT(db_create(&dbp, dbenv, 0) == 0); +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT(dbp->open( + dbp, NULL, fname, dbname, type, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbp->open( + dbp, fname, dbname, type, DB_CREATE, 0666) == 0); +#endif + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + } + TIMER_STOP; + + printf("# %d %s %sdatabase open/close pairs\n", + count, ts, + fname == NULL ? + (dbname == NULL ? "in-memory " : "named in-memory ") : + (dbname == NULL ? "" : "sub-")); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, "usage: b_open [-df] [-c count] [-t type]\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_put.c b/test_micro/source/b_put.c new file mode 100644 index 0000000..c9b2d61 --- /dev/null +++ b/test_micro/source/b_put.c @@ -0,0 +1,225 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); +static int b_put_secondary(DB *, const DBT *, const DBT *, DBT *); + +int +b_put(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB_ENV *dbenv; + DB *dbp, **second; + DBTYPE type; + DBT key, data; + db_recno_t recno; + u_int32_t cachesize, dsize; + int ch, i, count, secondaries; + char *ts, buf[64]; + + second = NULL; + type = DB_BTREE; + cachesize = MEGABYTE; + dsize = 20; + count = 100000; + secondaries = 0; + ts = "Btree"; + while ((ch = getopt(argc, argv, "C:c:d:s:t:")) != EOF) + switch (ch) { + case 'C': + cachesize = (u_int32_t)atoi(optarg); + break; + case 'c': + count = atoi(optarg); + break; + case 'd': + dsize = (u_int32_t)atoi(optarg); + break; + case 's': + secondaries = atoi(optarg); + break; + case 't': + switch (optarg[0]) { + case 'B': case 'b': + ts = "Btree"; + type = DB_BTREE; + break; + case 'H': case 'h': + if (b_util_have_hash()) + return (0); + ts = "Hash"; + type = DB_HASH; + break; + case 'Q': case 'q': + if (b_util_have_queue()) + return (0); + ts = "Queue"; + type = DB_QUEUE; + break; + case 'R': case 'r': + ts = "Recno"; + type = DB_RECNO; + break; + default: + return (usage()); + } + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + +#if DB_VERSION_MAJOR < 3 || DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 3 + /* + * Secondaries were added after DB 3.2.9. + */ + if (secondaries) + return (0); +#endif + + /* Create the environment. */ + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + dbenv->set_errfile(dbenv, stderr); + DB_BENCH_ASSERT(dbenv->set_cachesize(dbenv, 0, cachesize, 0) == 0); +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 1 + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, + NULL, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, + DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0666) == 0); +#endif + + /* + * Create the database. + * Optionally set the record length for Queue. + */ + DB_BENCH_ASSERT(db_create(&dbp, dbenv, 0) == 0); + if (type == DB_QUEUE) + DB_BENCH_ASSERT(dbp->set_re_len(dbp, dsize) == 0); +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT( + dbp->open(dbp, NULL, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT( + dbp->open(dbp, TESTFILE, NULL, type, DB_CREATE, 0666) == 0); +#endif + + /* Optionally create the secondaries. */ + if (secondaries != 0) { + DB_BENCH_ASSERT((second = + calloc(sizeof(DB *), (size_t)secondaries)) != NULL); + for (i = 0; i < secondaries; ++i) { + DB_BENCH_ASSERT(db_create(&second[i], dbenv, 0) == 0); + (void)snprintf(buf, sizeof(buf), "%d.db", i); +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT(second[i]->open(second[i], NULL, + buf, NULL, DB_BTREE, DB_CREATE, 0600) == 0); +#else + DB_BENCH_ASSERT(second[i]->open(second[i], + buf, NULL, DB_BTREE, DB_CREATE, 0600) == 0); +#endif +#if DB_VERSION_MAJOR > 3 || DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 3 +#if DB_VERSION_MAJOR > 3 && DB_VERSION_MINOR > 0 + /* + * The DB_TXN argument to Db.associate was added in + * 4.1.25. + */ + DB_BENCH_ASSERT(dbp->associate( + dbp, NULL, second[i], b_put_secondary, 0) == 0); +#else + DB_BENCH_ASSERT(dbp->associate( + dbp, second[i], b_put_secondary, 0) == 0); +#endif +#endif + } + } + + /* Store a key/data pair. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + switch (type) { + case DB_BTREE: + case DB_HASH: + key.data = "01234567890123456789"; + key.size = 20; + break; + case DB_QUEUE: + case DB_RECNO: + recno = 1; + key.data = &recno; + key.size = sizeof(recno); + break; + case DB_UNKNOWN: + b_util_abort(); + break; + } + + data.size = dsize; + DB_BENCH_ASSERT( + (data.data = malloc((size_t)dsize)) != NULL); + + /* Store the key/data pair count times. */ + TIMER_START; + for (i = 0; i < count; ++i) { + /* Change data value so the secondaries are updated. */ + (void)snprintf(data.data, data.size, "%10lu", (u_long)i); + DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + TIMER_STOP; + + if (type == DB_BTREE || type == DB_HASH) + printf( + "# %d %s database put of 10 byte key, %lu byte data", + count, ts, (u_long)dsize); + else + printf("# %d %s database put of key, %lu byte data", + count, ts, (u_long)dsize); + if (secondaries) + printf(" with %d secondaries", secondaries); + printf("\n"); + TIMER_DISPLAY(count); + + if (second != NULL) { + for (i = 0; i < secondaries; ++i) + DB_BENCH_ASSERT(second[i]->close(second[i], 0) == 0); + free(second); + } + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); + + return (0); +} + +static int +b_put_secondary(dbp, pkey, pdata, skey) + DB *dbp; + const DBT *pkey, *pdata; + DBT *skey; +{ + skey->data = pdata->data; + skey->size = pdata->size; + + COMPQUIET(dbp, NULL); + COMPQUIET(pkey, NULL); + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, "usage: b_put %s\n", + "[-C cachesz] [-c count] [-d bytes] [-s secondaries] [-t type]"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_recover.c b/test_micro/source/b_recover.c new file mode 100644 index 0000000..cbe3306 --- /dev/null +++ b/test_micro/source/b_recover.c @@ -0,0 +1,141 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); + +int +b_recover(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *dbp; + DBT key, data; + DB_ENV *dbenv; + DB_TXN *txn; + u_int32_t cachesize; + int ch, i, count; + + /* + * Recover was too slow before release 4.0 that it's not worth + * running the test. + */ +#if DB_VERSION_MAJOR < 4 + return (0); +#endif + cachesize = MEGABYTE; + count = 1000; + while ((ch = getopt(argc, argv, "C:c:")) != EOF) + switch (ch) { + case 'C': + cachesize = (u_int32_t)atoi(optarg); + break; + case 'c': + count = atoi(optarg); + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* Create the environment. */ + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + dbenv->set_errfile(dbenv, stderr); + DB_BENCH_ASSERT(dbenv->set_cachesize(dbenv, 0, cachesize, 0) == 0); + +#define OFLAGS \ + (DB_CREATE | DB_INIT_LOCK | \ + DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE) +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0 + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, NULL, OFLAGS, 0666) == 0); +#endif +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, OFLAGS, 0666) == 0); +#endif +#if DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR > 1 + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, OFLAGS, 0666) == 0); +#endif + + /* Create the database. */ + DB_BENCH_ASSERT(db_create(&dbp, dbenv, 0) == 0); +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT(dbp->open(dbp, NULL, + TESTFILE, NULL, DB_BTREE, DB_CREATE | DB_AUTO_COMMIT, 0666) == 0); +#else + DB_BENCH_ASSERT( + dbp->open(dbp, TESTFILE, NULL, DB_BTREE, DB_CREATE, 0666) == 0); +#endif + + /* Initialize the data. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.size = data.size = 20; + key.data = data.data = "01234567890123456789"; + + /* Start/commit a transaction count times. */ + for (i = 0; i < count; ++i) { +#if DB_VERSION_MAJOR < 4 + DB_BENCH_ASSERT( + txn_begin(dbenv, NULL, &txn, DB_TXN_NOSYNC) == 0); + DB_BENCH_ASSERT(dbp->put(dbp, txn, &key, &data, 0) == 0); + DB_BENCH_ASSERT(txn_commit(txn, 0) == 0); +#else + DB_BENCH_ASSERT( + dbenv->txn_begin(dbenv, NULL, &txn, DB_TXN_NOSYNC) == 0); + DB_BENCH_ASSERT(dbp->put(dbp, txn, &key, &data, 0) == 0); + DB_BENCH_ASSERT(txn->commit(txn, 0) == 0); +#endif + } + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); + + /* Create a new DB_ENV handle. */ + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + dbenv->set_errfile(dbenv, stderr); + DB_BENCH_ASSERT( + dbenv->set_cachesize(dbenv, 0, 1048576 /* 1MB */, 0) == 0); + + /* Now run recovery. */ + TIMER_START; +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0 + DB_BENCH_ASSERT(dbenv->open( + dbenv, TESTDIR, NULL, OFLAGS | DB_RECOVER, 0666) == 0); +#endif +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 + DB_BENCH_ASSERT( + dbenv->open(dbenv, TESTDIR, OFLAGS | DB_RECOVER, 0666) == 0); +#endif +#if DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR > 1 + DB_BENCH_ASSERT( + dbenv->open(dbenv, TESTDIR, OFLAGS | DB_RECOVER, 0666) == 0); +#endif + TIMER_STOP; + + /* + * We divide the time by the number of transactions, so an "operation" + * is the recovery of a single transaction. + */ + printf("# recovery after %d transactions\n", count); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, "usage: b_recover [-C cachesz] [-c count]\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_txn.c b/test_micro/source/b_txn.c new file mode 100644 index 0000000..ddd7045 --- /dev/null +++ b/test_micro/source/b_txn.c @@ -0,0 +1,93 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage(void); + +int +b_txn(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB_ENV *dbenv; + DB_TXN *txn; + int tabort, ch, i, count; + + count = 1000; + tabort = 0; + while ((ch = getopt(argc, argv, "ac:")) != EOF) + switch (ch) { + case 'a': + tabort = 1; + break; + case 'c': + count = atoi(optarg); + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* Create the environment. */ + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + dbenv->set_errfile(dbenv, stderr); +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 1 + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, + NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE, 0666) == 0); +#endif + + /* Start and commit/abort a transaction count times. */ + TIMER_START; + if (tabort) + for (i = 0; i < count; ++i) { +#if DB_VERSION_MAJOR < 4 + DB_BENCH_ASSERT(txn_begin(dbenv, NULL, &txn, 0) == 0); + DB_BENCH_ASSERT(txn_abort(txn) == 0); +#else + DB_BENCH_ASSERT( + dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0); + DB_BENCH_ASSERT(txn->abort(txn) == 0); +#endif + } + else + for (i = 0; i < count; ++i) { +#if DB_VERSION_MAJOR < 4 + DB_BENCH_ASSERT(txn_begin(dbenv, NULL, &txn, 0) == 0); + DB_BENCH_ASSERT(txn_commit(txn, 0) == 0); +#else + DB_BENCH_ASSERT( + dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0); + DB_BENCH_ASSERT(txn->commit(txn, 0) == 0); +#endif + } + TIMER_STOP; + + printf("# %d empty transaction start/%s pairs\n", + count, tabort ? "abort" : "commit"); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, "usage: b_txn [-a] [-c count]\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_txn_write.c b/test_micro/source/b_txn_write.c new file mode 100644 index 0000000..dcf189f --- /dev/null +++ b/test_micro/source/b_txn_write.c @@ -0,0 +1,172 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#include "bench.h" + +static int usage __P((void)); + +#ifdef DB_INIT_REP +static int b_txn_write_send __P((DB_ENV *, + const DBT *, const DBT *, const DB_LSN *, int, u_int32_t)); + +/* + * b_txn_write_send -- + * A stubbed-out replication message function. + */ +static int +b_txn_write_send(dbenv, control, rec, lsn, eid, flags) + DB_ENV *dbenv; + const DBT *control, *rec; + const DB_LSN *lsn; + int eid; + u_int32_t flags; +{ + COMPQUIET(dbenv, NULL); + COMPQUIET(control, NULL); + COMPQUIET(rec, NULL); + COMPQUIET(lsn, NULL); + COMPQUIET(eid, 0); + COMPQUIET(flags, 0); + return (0); +} +#endif + +int +b_txn_write(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *dbp; + DBT key, data; + DB_ENV *dbenv; + DB_TXN *txn; + u_int32_t flags, oflags; + int ch, i, count, rep_stub; + char *config; + + count = 1000; + oflags = flags = 0; + rep_stub = 0; + config = "synchronous"; + while ((ch = getopt(argc, argv, "ac:rw")) != EOF) + switch (ch) { + case 'a': + config = "nosync"; + flags = DB_TXN_NOSYNC; + break; + case 'c': + count = atoi(optarg); + break; + case 'r': +#ifdef DB_INIT_REP + rep_stub = 1; +#else + exit(0); +#endif + break; + case 'w': + config = "write-nosync"; +#ifdef DB_TXN_WRITE_NOSYNC + flags = DB_TXN_WRITE_NOSYNC; +#else + exit(0); +#endif + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* Create the environment. */ + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + dbenv->set_errfile(dbenv, stderr); + +#ifdef DB_INIT_REP + if (rep_stub) { +#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5 || DB_VERSION_MAJOR > 4 + DB_BENCH_ASSERT( + dbenv->rep_set_transport(dbenv, 1, b_txn_write_send) == 0); +#else + DB_BENCH_ASSERT( + dbenv->set_rep_transport(dbenv, 1, b_txn_write_send) == 0); +#endif + oflags |= DB_INIT_REP; + } +#endif + oflags |= DB_CREATE | DB_INIT_LOCK | + DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE; +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0 + DB_BENCH_ASSERT( + dbenv->open(dbenv, TESTDIR, NULL, flags | oflags, 0666) == 0); +#endif +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 + DB_BENCH_ASSERT( + dbenv->open(dbenv, TESTDIR, flags | oflags, 0666) == 0); +#endif +#if DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR > 1 + if (flags != 0) + DB_BENCH_ASSERT(dbenv->set_flags(dbenv, flags, 1) == 0); + DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, oflags, 0666) == 0); +#endif + +#ifdef DB_INIT_REP + if (rep_stub) + DB_BENCH_ASSERT( + dbenv->rep_start(dbenv, NULL, DB_REP_MASTER) == 0); +#endif + + /* Create the database. */ + DB_BENCH_ASSERT(db_create(&dbp, dbenv, 0) == 0); +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT(dbp->open(dbp, NULL, + TESTFILE, NULL, DB_BTREE, DB_CREATE | DB_AUTO_COMMIT, 0666) == 0); +#else + DB_BENCH_ASSERT( + dbp->open(dbp, TESTFILE, NULL, DB_BTREE, DB_CREATE, 0666) == 0); +#endif + + /* Initialize the data. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.size = data.size = 20; + key.data = data.data = "01234567890123456789"; + + /* Start/commit a transaction count times. */ + TIMER_START; + for (i = 0; i < count; ++i) { +#if DB_VERSION_MAJOR < 4 + DB_BENCH_ASSERT(txn_begin(dbenv, NULL, &txn, 0) == 0); + DB_BENCH_ASSERT(dbp->put(dbp, txn, &key, &data, 0) == 0); + DB_BENCH_ASSERT(txn_commit(txn, 0) == 0); +#else + DB_BENCH_ASSERT(dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0); + DB_BENCH_ASSERT(dbp->put(dbp, txn, &key, &data, 0) == 0); + DB_BENCH_ASSERT(txn->commit(txn, 0) == 0); +#endif + } + TIMER_STOP; + + printf("# %d %stransactions write %s commit pairs\n", + count, rep_stub ? "replicated ": "", config); + TIMER_DISPLAY(count); + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, "usage: b_txn_write [-arw] [-c count]\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_uname.c b/test_micro/source/b_uname.c new file mode 100644 index 0000000..fab0e7c --- /dev/null +++ b/test_micro/source/b_uname.c @@ -0,0 +1,147 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "bench.h" + +#define UNAMEFILE "NODENAME" + +static int write_info __P((FILE *)); + +int +b_uname() +{ + FILE *fp; + int ret; + + if ((fp = fopen(UNAMEFILE, "w")) == NULL) + goto file_err; + + ret = write_info(fp); + + if (fclose(fp) != 0) { +file_err: fprintf(stderr, + "%s: %s: %s\n", progname, UNAMEFILE, strerror(errno)); + return (1); + } + + return (ret); +} + +#ifdef DB_WIN32 +static int +write_info(fp) + FILE *fp; +{ + OSVERSIONINFO osver; + SYSTEM_INFO sysinfo; + char *p; + +#ifdef DB_WINCE + p = "WinCE"; +#else + { + DWORD len; + char buf[1024]; + + len = sizeof(buf) - 1; + GetComputerName(buf, &len); + p = buf; + } +#endif + fprintf(fp, "<p>%s, ", p); + + GetSystemInfo(&sysinfo); + switch (sysinfo.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_ALPHA: + p = "alpha"; + break; + case PROCESSOR_ARCHITECTURE_INTEL: + p = "x86"; + break; + case PROCESSOR_ARCHITECTURE_MIPS: + p = "mips"; + break; + case PROCESSOR_ARCHITECTURE_PPC: + p = "ppc"; + break; + default: + p = "unknown"; + break; + } + fprintf(fp, "%s<br>\n", p); + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + GetVersionEx(&osver); + switch (osver.dwPlatformId) { + case VER_PLATFORM_WIN32_NT: /* NT, Windows 2000 or Windows XP */ + if (osver.dwMajorVersion == 4) + p = "Windows NT4x"; + else if (osver.dwMajorVersion <= 3) + p = "Windows NT3x"; + else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion < 1) + p = "Windows 2000"; + else if (osver.dwMajorVersion >= 5) + p = "Windows XP"; + else + p = "unknown"; + break; + case VER_PLATFORM_WIN32_WINDOWS: /* Win95, Win98 or WinME */ + if ((osver.dwMajorVersion > 4) || + ((osver.dwMajorVersion == 4) && (osver.dwMinorVersion > 0))) { + if (osver.dwMinorVersion >= 90) + p = "Windows ME"; + else + p = "Windows 98"; + } else + p = "Windows 95"; + break; + case VER_PLATFORM_WIN32s: /* Windows 3.x */ + p = "Windows"; + break; + default: + p = "unknown"; + break; + } + fprintf(fp, + "%s, %ld.%02ld", p, osver.dwMajorVersion, osver.dwMinorVersion); + return (0); +} + +#elif defined(HAVE_VXWORKS) +static int +write_info(fp) + FILE *fp; +{ + fprintf(fp, "<p>VxWorks"); + return (0); +} + +#else /* POSIX */ +#include <sys/utsname.h> + +static int +write_info(fp) + FILE *fp; +{ + struct utsname name; + + if (uname(&name) == 0) + fprintf(fp, "<p>%s, %s<br>\n%s, %s, %s</p>\n", name.nodename, + name.machine, name.sysname, name.release, name.version); + else { + /* + * We've seen random failures on some systems, complain and + * skip the call if it fails. + */ + fprintf(stderr, "%s: uname: %s\n", progname, strerror(errno)); + + fprintf(fp, "<p>POSIX"); + } + return (0); +} +#endif diff --git a/test_micro/source/b_util.c b/test_micro/source/b_util.c new file mode 100644 index 0000000..2610bc5 --- /dev/null +++ b/test_micro/source/b_util.c @@ -0,0 +1,157 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "bench.h" + +static int testdir_remove __P((char *)); + +int +b_util_have_hash() +{ +#if defined(HAVE_HASH) ||\ + DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 2 + return (0); +#else + fprintf(stderr, + "library build did not include support for the Hash access method\n"); + return (1); +#endif +} + +int +b_util_have_queue() +{ +#if defined(HAVE_QUEUE) ||\ + DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 2 + return (0); +#else + fprintf(stderr, + "library build did not include support for the Queue access method\n"); + return (1); +#endif +} + +/* + * b_util_dir_setup -- + * Create the test directory. + */ +int +b_util_dir_setup() +{ + int ret; + +#if DB_VERSION_MAJOR > 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 3 + if ((ret = __os_mkdir(NULL, TESTDIR, 0755)) != 0) { +#else + if ((ret = mkdir(TESTDIR, 0755)) != 0) { +#endif + fprintf(stderr, + "%s: %s: %s\n", progname, TESTDIR, db_strerror(ret)); + return (1); + } + return (0); +} + +#if DB_VERSION_MAJOR > 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 4 +#define OS_EXISTS(a, b, c) __os_exists(a, b, c) +#else +#define OS_EXISTS(a, b, c) __os_exists(b, c) +#endif + +/* + * b_util_dir_teardown + * Clean up the test directory. + */ +int +b_util_dir_teardown() +{ + int ret; + + if (OS_EXISTS(NULL, TESTFILE, NULL) == 0 && + (ret = b_util_unlink(TESTFILE)) != 0) { + fprintf(stderr, + "%s: %s: %s\n", progname, TESTFILE, db_strerror(ret)); + return (1); + } + return (testdir_remove(TESTDIR) ? 1 : 0); +} + +/* + * testdir_remove -- + * Remove a directory and all its contents, the "dir" must contain no + * subdirectories, because testdir_remove will not recursively delete + * all subdirectories. + */ +static int +testdir_remove(dir) + char *dir; +{ + int cnt, i, isdir, ret; + char buf[1024], **names; + + ret = 0; + + /* If the directory doesn't exist, we're done. */ + if (OS_EXISTS(NULL, dir, &isdir) != 0) + return (0); + + /* Get a list of the directory contents. */ +#if DB_VERSION_MAJOR > 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 6 + if ((ret = __os_dirlist(NULL, dir, 0, &names, &cnt)) != 0) + return (ret); +#else + if ((ret = __os_dirlist(NULL, dir, &names, &cnt)) != 0) + return (ret); +#endif + /* Go through the file name list, remove each file in the list */ + for (i = 0; i < cnt; ++i) { + (void)snprintf(buf, sizeof(buf), + "%s%c%s", dir, PATH_SEPARATOR[0], names[i]); + if ((ret = OS_EXISTS(NULL, buf, &isdir)) != 0) + goto file_err; + if (!isdir && (ret = b_util_unlink(buf)) != 0) { +file_err: fprintf(stderr, "%s: %s: %s\n", + progname, buf, db_strerror(ret)); + break; + } + } + + __os_dirfree(NULL, names, cnt); + + /* + * If we removed the contents of the directory, remove the directory + * itself. + */ + if (i == cnt && (ret = rmdir(dir)) != 0) + fprintf(stderr, + "%s: %s: %s\n", progname, dir, db_strerror(errno)); + return (ret); +} + +void +b_util_abort() +{ +#if DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 6 + abort(); +#elif DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 6 + __os_abort(); +#else + __os_abort(NULL); +#endif +} + +int +b_util_unlink(path) + char *path; +{ +#if DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 7 + return (__os_unlink(NULL, path)); +#else + return (__os_unlink(NULL, path, 0)); +#endif +} diff --git a/test_micro/source/b_workload.c b/test_micro/source/b_workload.c new file mode 100644 index 0000000..6851a43 --- /dev/null +++ b/test_micro/source/b_workload.c @@ -0,0 +1,631 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "bench.h" +#include "b_workload.h" + +static int dump_verbose_stats __P((DB *, CONFIG *)); +static int is_del_workload __P((int)); +static int is_get_workload __P((int)); +static int is_put_workload __P((int)); +static int run_mixed_workload __P((DB *, CONFIG *)); +static int run_std_workload __P((DB *, CONFIG *)); +static int usage __P((void)); +static char *workload_str __P((int)); + +/* + * General TODO list: + * * The workload type. Might work better as a bitmask than the current enum. + * * Improve the verbose stats, so they can be easily parsed. + * * Think about doing automatic btree/hash comparison in here. + */ +int +b_workload(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + CONFIG conf; + DB *dbp; + DB_ENV *dbenv; + int ch, ffactor, ksz; + + dbenv = NULL; + memset(&conf, 0, sizeof(conf)); + conf.seed = 124087; + srand(conf.seed); + + conf.pcount = 100000; + conf.ts = "Btree"; + conf.type = DB_BTREE; + conf.dsize = 20; + conf.presize = 0; + conf.workload = T_PUT_GET_DELETE; + + while ((ch = getopt(argc, argv, "b:c:d:e:g:ik:m:op:r:t:vw:")) != EOF) + switch (ch) { + case 'b': + conf.cachesz = atoi(optarg); + break; + case 'c': + conf.pcount = atoi(optarg); + break; + case 'd': + conf.dsize = atoi(optarg); + break; + case 'e': + conf.cursor_del = atoi(optarg); + break; + case 'g': + conf.gcount = atoi(optarg); + break; + case 'i': + conf.presize = 1; + break; + case 'k': + conf.ksize = atoi(optarg); + break; + case 'm': + conf.message = optarg; + break; + case 'o': + conf.orderedkeys = 1; + break; + case 'p': + conf.pagesz = atoi(optarg); + break; + case 'r': + conf.num_dups = atoi(optarg); + break; + case 't': + switch (optarg[0]) { + case 'B': case 'b': + conf.ts = "Btree"; + conf.type = DB_BTREE; + break; + case 'H': case 'h': + if (b_util_have_hash()) + return (0); + conf.ts = "Hash"; + conf.type = DB_HASH; + break; + default: + return (usage()); + } + break; + case 'v': + conf.verbose = 1; + break; + case 'w': + switch (optarg[0]) { + case 'A': + conf.workload = T_PUT_GET_DELETE; + break; + case 'B': + conf.workload = T_GET; + break; + case 'C': + conf.workload = T_PUT; + break; + case 'D': + conf.workload = T_DELETE; + break; + case 'E': + conf.workload = T_PUT_GET; + break; + case 'F': + conf.workload = T_PUT_DELETE; + break; + case 'G': + conf.workload = T_GET_DELETE; + break; + case 'H': + conf.workload = T_MIXED; + break; + default: + return (usage()); + } + break; + case '?': + default: + fprintf(stderr, "Invalid option: %c\n", ch); + return (usage()); + } + argc -= optind; + argv += optind; + if (argc != 0) + return (usage()); + + /* + * Validate the input parameters if specified. + */ + if (conf.pagesz != 0) + DB_BENCH_ASSERT(conf.pagesz >= 512 && conf.pagesz <= 65536 && + ((conf.pagesz & (conf.pagesz - 1)) == 0)); + + if (conf.cachesz != 0) + DB_BENCH_ASSERT(conf.cachesz > 20480); + DB_BENCH_ASSERT(conf.ksize == 0 || conf.orderedkeys == 0); + + /* Create the environment. */ + DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); + dbenv->set_errfile(dbenv, stderr); + if (conf.cachesz != 0) + DB_BENCH_ASSERT( + dbenv->set_cachesize(dbenv, 0, conf.cachesz, 0) == 0); + +#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 1 + DB_BENCH_ASSERT(dbenv->open(dbenv, "TESTDIR", + NULL, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbenv->open(dbenv, "TESTDIR", + DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0666) == 0); +#endif + + DB_BENCH_ASSERT(db_create(&dbp, dbenv, 0) == 0); + if (conf.pagesz != 0) + DB_BENCH_ASSERT( + dbp->set_pagesize(dbp, conf.pagesz) == 0); + if (conf.presize != 0 && conf.type == DB_HASH) { + ksz = (conf.orderedkeys != 0) ? sizeof(u_int32_t) : conf.ksize; + if (ksz == 0) + ksz = 10; + ffactor = (conf.pagesz - 32)/(ksz + conf.dsize + 8); + fprintf(stderr, "ffactor: %d\n", ffactor); + DB_BENCH_ASSERT( + dbp->set_h_ffactor(dbp, ffactor) == 0); + DB_BENCH_ASSERT( + dbp->set_h_nelem(dbp, conf.pcount*10) == 0); + } +#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 + DB_BENCH_ASSERT(dbp->open( + dbp, NULL, TESTFILE, NULL, conf.type, DB_CREATE, 0666) == 0); +#else + DB_BENCH_ASSERT(dbp->open( + dbp, TESTFILE, NULL, conf.type, DB_CREATE, 0666) == 0); +#endif + + if (conf.workload == T_MIXED) + run_mixed_workload(dbp, &conf); + else + run_std_workload(dbp, &conf); + + if (is_put_workload(conf.workload) == 0) + timespecadd(&conf.tot_time, &conf.put_time); + if (is_get_workload(conf.workload) == 0) + timespecadd(&conf.tot_time, &conf.get_time); + if (is_del_workload(conf.workload) == 0) + timespecadd(&conf.tot_time, &conf.del_time); + + /* Ensure data is flushed for following measurements. */ + DB_BENCH_ASSERT(dbp->sync(dbp, 0) == 0); + + if (conf.verbose != 0) + dump_verbose_stats(dbp, &conf); + + DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); + DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); + + /* + * Construct a string for benchmark output. + * + * Insert HTML in-line to make the output prettier -- ugly, but easy. + */ + printf("# workload test: %s: %s<br>%lu ops", + conf.ts, workload_str(conf.workload), (u_long)conf.pcount); + if (conf.ksize != 0) + printf(", key size: %lu", (u_long)conf.ksize); + if (conf.dsize != 0) + printf(", data size: %lu", (u_long)conf.dsize); + if (conf.pagesz != 0) + printf(", page size: %lu", (u_long)conf.pagesz); + else + printf(", page size: default"); + if (conf.cachesz != 0) + printf(", cache size: %lu", (u_long)conf.cachesz); + else + printf(", cache size: default"); + printf(", %s keys", conf.orderedkeys == 1 ? "ordered" : "unordered"); + printf(", num dups: %lu", (u_long)conf.num_dups); + printf("\n"); + + if (conf.workload != T_MIXED) { + if (conf.message != NULL) + printf("%s %s ", conf.message, conf.ts); + TIME_DISPLAY(conf.pcount, conf.tot_time); + } else + TIMER_DISPLAY(conf.pcount); + + return (0); +} + +/* + * The mixed workload is designed to simulate a somewhat real + * usage scenario. + * NOTES: * rand is used to decide on the current operation. This will + * be repeatable, since the same seed is always used. + * * All added keys are stored in a FIFO queue, this is not very + * space efficient, but is the best way I could come up with to + * insert random key values, and be able to retrieve/delete them. + * * TODO: the workload will currently only work with unordered + * fixed length keys. + */ +#define GET_PROPORTION 90 +#define PUT_PROPORTION 7 +#define DEL_PROPORTION 3 + +static int +run_mixed_workload(dbp, config) + DB *dbp; + CONFIG *config; +{ + DBT key, data; + size_t next_op, i, ioff, inscount; + char kbuf[KBUF_LEN]; + struct bench_q operation_queue; + + /* Having ordered insertion does not make sense here */ + DB_BENCH_ASSERT(config->orderedkeys == 0); + + srand(config->seed); + memset(&operation_queue, 0, sizeof(struct bench_q)); + + ioff = 0; + INIT_KEY(key, config); + memset(&data, 0, sizeof(data)); + DB_BENCH_ASSERT( + (data.data = malloc(data.size = config->dsize)) != NULL); + + /* + * Add an initial sample set of data to the DB. + * This should add some stability, and reduce the likelihood + * of deleting all of the entries in the DB. + */ + inscount = 2 * config->pcount; + if (inscount > 100000) + inscount = 100000; + + for (i = 0; i < inscount; ++i) { + GET_KEY_NEXT(key, config, kbuf, i); + BENCH_Q_TAIL_INSERT(operation_queue, kbuf); + DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + + TIMER_START; + for (i = 0; i < config->pcount; ++i) { + next_op = rand()%100; + + if (next_op < GET_PROPORTION ) { + BENCH_Q_POP_PUSH(operation_queue, kbuf); + key.data = kbuf; + key.size = sizeof(kbuf); + dbp->get(dbp, NULL, &key, &data, 0); + } else if (next_op < GET_PROPORTION+PUT_PROPORTION) { + GET_KEY_NEXT(key, config, kbuf, i); + BENCH_Q_TAIL_INSERT(operation_queue, kbuf); + dbp->put(dbp, NULL, &key, &data, 0); + } else { + BENCH_Q_POP(operation_queue, kbuf); + key.data = kbuf; + key.size = sizeof(kbuf); + dbp->del(dbp, NULL, &key, 0); + } + } + TIMER_STOP; + TIMER_GET(config->tot_time); + + return (0); +} + +static int +run_std_workload(dbp, config) + DB *dbp; + CONFIG *config; +{ + DBT key, data; + DBC *dbc; + u_int32_t i; + int ret; + char kbuf[KBUF_LEN]; + + /* Setup a key/data pair. */ + INIT_KEY(key, config); + memset(&data, 0, sizeof(data)); + DB_BENCH_ASSERT( + (data.data = malloc(data.size = config->dsize)) != NULL); + + /* Store the key/data pair count times. */ + TIMER_START; + for (i = 0; i < config->pcount; ++i) { + GET_KEY_NEXT(key, config, kbuf, i); + DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); + } + TIMER_STOP; + TIMER_GET(config->put_time); + + if (is_get_workload(config->workload) == 0) { + TIMER_START; + for (i = 0; i <= config->gcount; ++i) { + DB_BENCH_ASSERT(dbp->cursor(dbp, NULL, &dbc, 0) == 0); + while ((dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0); + DB_BENCH_ASSERT(dbc->c_close(dbc) == 0); + } + TIMER_STOP; + TIMER_GET(config->get_time); + } + + if (is_del_workload(config->workload) == 0) { + /* reset rand to reproduce key sequence. */ + srand(config->seed); + + TIMER_START; + if (config->cursor_del != 0) { + DB_BENCH_ASSERT(dbp->cursor(dbp, NULL, &dbc, 0) == 0); + while ( + (ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) + DB_BENCH_ASSERT(dbc->c_del(dbc, 0) == 0); + DB_BENCH_ASSERT (ret == DB_NOTFOUND); + } else { + INIT_KEY(key, config); + for (i = 0; i < config->pcount; ++i) { + GET_KEY_NEXT(key, config, kbuf, i); + + ret = dbp->del(dbp, NULL, &key, 0); + /* + * Random key generation can cause dups, + * so NOTFOUND result is OK. + */ + if (config->ksize == 0) + DB_BENCH_ASSERT + (ret == 0 || ret == DB_NOTFOUND); + else + DB_BENCH_ASSERT(ret == 0); + } + } + TIMER_STOP; + TIMER_GET(config->del_time); + } + return (0); +} + +static int +dump_verbose_stats(dbp, config) + DB *dbp; + CONFIG *config; +{ +/* + * It would be nice to be able to define stat as _stat on + * Windows, but that substitutes _stat for the db call as well. + */ +#ifdef DB_WIN32 + struct _stat fstat; +#else + struct stat fstat; +#endif + DB_HASH_STAT *hstat; + DB_BTREE_STAT *bstat; + double free_prop; + char path[1024]; + +#ifdef DB_BENCH_INCLUDE_CONFIG_SUMMARY + printf("Completed workload benchmark.\n"); + printf("Configuration summary:\n"); + printf("\tworkload type: %d\n", (int)config->workload); + printf("\tdatabase type: %s\n", config->ts); + if (config->cachesz != 0) + printf("\tcache size: %lu\n", (u_long)config->cachesz); + if (config->pagesz != 0) + printf("\tdatabase page size: %lu\n", (u_long)config->pagesz); + printf("\tput element count: %lu\n", (u_long)config->pcount); + if ( is_get_workload(config->workload) == 0) + printf("\tget element count: %lu\n", (u_long)config->gcount); + if (config->orderedkeys) + printf("\tInserting items in order\n"); + else if (config->ksize == 0) + printf("\tInserting keys with size 10\n"); + else + printf( + "\tInserting keys with size: %lu\n", (u_long)config->ksize); + + printf("\tInserting data elements size: %lu\n", (u_long)config->dsize); + + if (is_del_workload(config->workload) == 0) { + if (config->cursor_del) + printf("\tDeleting items using a cursor\n"); + else + printf("\tDeleting items without a cursor\n"); + } +#endif /* DB_BENCH_INCLUDE_CONFIG_SUMMARY */ + + if (is_put_workload(config->workload) == 0) + printf("%s Time spent inserting (%lu) (%s) items: %lu/%lu\n", + config->message[0] == '\0' ? "" : config->message, + (u_long)config->pcount, config->ts, + (u_long)config->put_time.tv_sec, config->put_time.tv_nsec); + + if (is_get_workload(config->workload) == 0) + printf("%s Time spent getting (%lu) (%s) items: %lu/%lu\n", + config->message[0] == '\0' ? "" : config->message, + (u_long)config->pcount * ((config->gcount == 0) ? + 1 : config->gcount), config->ts, + (u_long)config->get_time.tv_sec, config->get_time.tv_nsec); + + if (is_del_workload(config->workload) == 0) + printf("%s Time spent deleting (%lu) (%s) items: %lu/%lu\n", + config->message[0] == '\0' ? "" : config->message, + (u_long)config->pcount, config->ts, + (u_long)config->del_time.tv_sec, config->del_time.tv_nsec); + + (void)snprintf(path, sizeof(path), + "%s%c%s", TESTDIR, PATH_SEPARATOR[0], TESTFILE); +#ifdef DB_WIN32 + if (_stat(path, &fstat) == 0) { +#else + if (stat(path, &fstat) == 0) { +#endif + printf("%s Size of db file (%s): %lu K\n", + config->message[0] == '\0' ? "" : config->message, + config->ts, (u_long)fstat.st_size/1024); + } + + if (config->type == DB_HASH) { +#if DB_VERSION_MAJOR < 3 || DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2 + DB_BENCH_ASSERT(dbp->stat(dbp, &hstat, NULL, 0) == 0); +#elif DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR <= 2 + DB_BENCH_ASSERT(dbp->stat(dbp, &hstat, 0) == 0); +#else + DB_BENCH_ASSERT(dbp->stat(dbp, NULL, &hstat, 0) == 0); +#endif + /* + * Hash fill factor is a bit tricky. Want to include + * both bucket and overflow buckets (not offpage). + */ + free_prop = hstat->hash_pagesize*hstat->hash_buckets; + free_prop += hstat->hash_pagesize*hstat->hash_overflows; + free_prop = + (free_prop - hstat->hash_bfree - hstat->hash_ovfl_free)/ + free_prop; + printf("%s db fill factor (%s): %.2f%%\n", + config->message[0] == '\0' ? "" : config->message, + config->ts, free_prop*100); + free(hstat); + } else { /* Btree */ +#if DB_VERSION_MAJOR < 3 || DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2 + DB_BENCH_ASSERT(dbp->stat(dbp, &bstat, NULL, 0) == 0); +#elif DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR <= 2 + DB_BENCH_ASSERT(dbp->stat(dbp, &bstat, 0) == 0); +#else + DB_BENCH_ASSERT(dbp->stat(dbp, NULL, &bstat, 0) == 0); +#endif + free_prop = bstat->bt_pagesize*bstat->bt_leaf_pg; + free_prop = (free_prop-bstat->bt_leaf_pgfree)/free_prop; + printf("%s db fill factor (%s): %.2f%%\n", + config->message[0] == '\0' ? "" : config->message, + config->ts, free_prop*100); + free(bstat); + } + return (0); +} + +static char * +workload_str(workload) + int workload; +{ + static char buf[128]; + + switch (workload) { + case T_PUT_GET_DELETE: + return ("PUT/GET/DELETE"); + /* NOTREACHED */ + case T_GET: + return ("GET"); + /* NOTREACHED */ + case T_PUT: + return ("PUT"); + /* NOTREACHED */ + case T_DELETE: + return ("DELETE"); + /* NOTREACHED */ + case T_PUT_GET: + return ("PUT/GET"); + /* NOTREACHED */ + case T_PUT_DELETE: + return ("PUT/DELETE"); + /* NOTREACHED */ + case T_GET_DELETE: + return ("GET/DELETE"); + /* NOTREACHED */ + case T_MIXED: + snprintf(buf, sizeof(buf), "MIXED (get: %d, put: %d, del: %d)", + (int)GET_PROPORTION, + (int)PUT_PROPORTION, (int)DEL_PROPORTION); + return (buf); + default: + break; + } + + exit(usage()); + /* NOTREACHED */ +} + +static int +is_get_workload(workload) + int workload; +{ + switch (workload) { + case T_GET: + case T_PUT_GET: + case T_PUT_GET_DELETE: + case T_GET_DELETE: + return 0; + } + return 1; +} + +static int +is_put_workload(workload) + int workload; +{ + switch (workload) { + case T_PUT: + case T_PUT_GET: + case T_PUT_GET_DELETE: + case T_PUT_DELETE: + return 0; + } + return 1; +} + +static int +is_del_workload(workload) + int workload; +{ + switch (workload) { + case T_DELETE: + case T_PUT_DELETE: + case T_PUT_GET_DELETE: + case T_GET_DELETE: + return 0; + } + return 1; +} + +static int +usage() +{ + (void)fprintf(stderr, + "usage: b_workload [-b cachesz] [-c count] [-d bytes] [-e]\n"); + (void)fprintf(stderr, + "\t[-g getitrs] [-i] [-k keysize] [-m message] [-o] [-p pagesz]\n"); + (void)fprintf(stderr, "\t[-r dup_count] [-t type] [-w type]\n"); + + (void)fprintf(stderr, "Where:\n"); + (void)fprintf(stderr, "\t-b the size of the DB cache.\n"); + (void)fprintf(stderr, "\t-c the number of elements to be measured.\n"); + (void)fprintf(stderr, "\t-d the size of each data element.\n"); + (void)fprintf(stderr, "\t-e delete entries using a cursor.\n"); + (void)fprintf(stderr, "\t-g number of get cursor traverses.\n"); + (void)fprintf(stderr, "\t-i Pre-init hash DB bucket count.\n"); + (void)fprintf(stderr, "\t-k the size of each key inserted.\n"); + (void)fprintf(stderr, "\t-m message pre-pended to log output.\n"); + (void)fprintf(stderr, "\t-o keys should be ordered for insert.\n"); + (void)fprintf(stderr, "\t-p the page size for the database.\n"); + (void)fprintf(stderr, "\t-r the number of duplicates to insert\n"); + (void)fprintf(stderr, "\t-t type of the underlying database.\n"); + (void)fprintf(stderr, "\t-w the workload to measure, available:\n"); + (void)fprintf(stderr, "\t\tA - PUT_GET_DELETE\n"); + (void)fprintf(stderr, "\t\tB - GET\n"); + (void)fprintf(stderr, "\t\tC - PUT\n"); + (void)fprintf(stderr, "\t\tD - DELETE\n"); + (void)fprintf(stderr, "\t\tE - PUT_GET\n"); + (void)fprintf(stderr, "\t\tF - PUT_DELETE\n"); + (void)fprintf(stderr, "\t\tG - GET_DELETE\n"); + (void)fprintf(stderr, "\t\tH - MIXED\n"); + return (EXIT_FAILURE); +} diff --git a/test_micro/source/b_workload.h b/test_micro/source/b_workload.h new file mode 100644 index 0000000..799720d --- /dev/null +++ b/test_micro/source/b_workload.h @@ -0,0 +1,153 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +/* + * Macros to help with initializing/assigning key dbts + */ + +#define KBUF_LEN 12 +#define INIT_KEY(key, config) do { \ + memset(&key, 0, sizeof(key)); \ + if (config->orderedkeys) { \ + key.size = sizeof (u_int32_t); \ + } else if (config->ksize != 0) { \ + DB_BENCH_ASSERT( \ + (key.data = malloc(key.size = config->ksize)) != NULL); \ + } else { \ + key.data = kbuf; \ + key.size = 10; \ + } \ + } while (0) + +#define GET_KEY_NEXT(key, config, kbuf, i) do { \ + size_t tmp_int; \ + if (config->orderedkeys) { \ + /* Will be sorted on little-endian system. */ \ + tmp_int = i; \ + M_32_SWAP(tmp_int); \ + key.data = &tmp_int; \ + } else if (config->ksize == 0) { \ + /* \ + * This will produce duplicate keys. \ + * That is not such a big deal, since we are \ + * using the same seed to srand each time, \ + * the scenario is reproducible. \ + */ \ + (void)snprintf(kbuf, sizeof(kbuf), "%10d", rand()); \ + } else { \ + /* TODO: Not sure of the best approach here. */ \ + (void)snprintf(key.data, config->ksize, "%10lu", (u_long)i); \ + } \ + } while (0) + +/* Taken from dbinc/db_swap.h */ +#undef M_32_SWAP +#define M_32_SWAP(a) { \ + u_int32_t _tmp; \ + _tmp = (u_int32_t)a; \ + ((u_int8_t *)&a)[0] = ((u_int8_t *)&_tmp)[3]; \ + ((u_int8_t *)&a)[1] = ((u_int8_t *)&_tmp)[2]; \ + ((u_int8_t *)&a)[2] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)&a)[3] = ((u_int8_t *)&_tmp)[0]; \ +} + +/* + * A singly linked list, that maintains a pointer + * to the start and the end of the queue. + * Should be possible to use a STAILQ, but this seemed easier + */ +typedef struct bench_qentry { + char data[KBUF_LEN]; + struct bench_qentry *next; +}bench_qentry; +typedef struct bench_q { + struct bench_qentry *head; + struct bench_qentry *tail; +} bench_q; +#define BENCH_Q_TAIL_INSERT(queue, buf) do { \ + struct bench_qentry *entry; \ + DB_BENCH_ASSERT( \ + (entry = malloc(sizeof(struct bench_qentry))) != NULL); \ + memcpy(entry->data, buf, sizeof(entry->data)); \ + if (queue.head == NULL) \ + queue.head = queue.tail = entry; \ + else { \ + queue.tail->next = entry; \ + queue.tail = entry; \ + } \ +} while (0) + +#define BENCH_Q_POP(queue, buf) do { \ + struct bench_qentry *popped = queue.head; \ + if (popped == NULL) \ + break; \ + if (queue.head->next == NULL) \ + queue.head = queue.tail = NULL; \ + else \ + queue.head = queue.head->next; \ + memcpy(buf, popped->data, sizeof(buf)); \ + free(popped); \ +} while (0) + +/* + * Retrieve the head of the queue, save the data into user + * buffer, and push the item back onto the end of the list. + * Same functionality as pop/insert, but saves a malloc/free + */ +#define BENCH_Q_POP_PUSH(queue, buf) do { \ + struct bench_qentry *popped = queue.head; \ + if (popped == NULL) \ + break; \ + if (queue.head->next == NULL) \ + queue.head = queue.tail = NULL; \ + else \ + queue.head = queue.head->next; \ + memcpy(buf, popped->data, sizeof(buf)); \ + if (queue.head == NULL) \ + queue.head = queue.tail = popped; \ + else { \ + queue.tail->next = popped; \ + queue.tail = popped; \ + } \ +} while (0) + +typedef enum { + T_PUT, + T_GET, + T_DELETE, + T_PUT_GET, + T_PUT_DELETE, + T_PUT_GET_DELETE, + T_GET_DELETE, + T_MIXED +} test_type; + +typedef struct +{ + u_int32_t ksize; + u_int32_t dsize; + size_t orderedkeys; + size_t num_dups; + u_int32_t pagesz; + u_int32_t cachesz; + u_int32_t pcount; + size_t gcount; + size_t cursor_del; + size_t verbose; + test_type workload; + u_int32_t seed; + size_t presize; + DBTYPE type; + char *ts; + char *message; + /* Fields used to store timing information */ + db_timespec put_time; + db_timespec get_time; + db_timespec del_time; + db_timespec tot_time; +} CONFIG; diff --git a/test_micro/source/bench.h b/test_micro/source/bench.h new file mode 100644 index 0000000..08493ab --- /dev/null +++ b/test_micro/source/bench.h @@ -0,0 +1,217 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ +#ifndef _BENCH_H_ +#define _BENCH_H_ +#include "db_config.h" + +#include "db_int.h" + +#if DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 5 +/* + * Older releases of Berkeley DB don't include standard include files in + * db_int.h. + */ +#ifdef DB_WIN32 +#define WIN32_LEAN_AND_MEAN 1 +#include <windows.h> +#include <direct.h> +#include <sys/timeb.h> +#else +#include <sys/stat.h> +#include <sys/time.h> + +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#endif +#endif + +#define TESTDIR "TESTDIR" +#define TESTFILE "test_micro.db" + +/* + * Implement a custom assert to allow consistent behavior across builds and + * platforms. + * + * The BDB library DB_ASSERT implementation is only enabled in diagnostic + * builds -- so is not suitable here. + */ +#define DB_BENCH_ASSERT(e) do { \ + (e) ? (void)0 : \ + (fprintf(stderr, \ + "assert failure: %s/%d: \"%s\"\n", __FILE__, __LINE__, #e), \ + b_util_abort()); \ +} while (0) + +#ifndef NS_PER_SEC +#define NS_PER_SEC 1000000000 /* Nanoseconds in a second */ +#endif +#ifndef NS_PER_US +#define NS_PER_US 1000 /* Nanoseconds in a microsecond */ +#endif +#ifndef MS_PER_NS +#define MS_PER_NS 1000000 /* Milliseconds in a nanosecond */ +#endif + +#ifdef DB_TIMEOUT_TO_TIMESPEC +/* + * We have the timer routines in the Berkeley DB library after their conversion + * to the POSIX timespec interfaces. We'd rather use something that gives us + * better information than elapsed wallclock time, so use getrusage instead if + * it's available. + */ +#ifdef HAVE_GETRUSAGE +#include <sys/resource.h> + +#define SET_TIMER_FROM_GETRUSAGE(tp) do { \ + struct rusage __usage; \ + DB_BENCH_ASSERT(getrusage(RUSAGE_SELF, &__usage) == 0); \ + (tp)->tv_sec = \ + __usage.ru_utime.tv_sec + __usage.ru_stime.tv_sec; \ + (tp)->tv_nsec = NS_PER_US * \ + (__usage.ru_utime.tv_usec + __usage.ru_stime.tv_usec); \ +} while (0); + +#define TIMER_START SET_TIMER_FROM_GETRUSAGE(&__start_time); +#define TIMER_STOP SET_TIMER_FROM_GETRUSAGE(&__end_time); + +#elif defined(DB_WIN32) && !defined(DB_WINCE) + +#define SET_TIMER_FROM_GETPROCESSTIMES(tp) do { \ + FILETIME lpCreationTime, lpExitTime, lpKernelTime, lpUserTIme; \ + LARGE_INTEGER large_int; \ + LONGLONG __ns_since_epoch; \ + DB_BENCH_ASSERT( \ + GetProcessTimes(GetCurrentProcess(), &lpCreationTime, \ + &lpExitTime, &lpKernelTime, &lpUserTIme) != 0); \ + memcpy(&large_int, &lpKernelTime, sizeof(lpKernelTime)); \ + __ns_since_epoch = (large_int.QuadPart * 100); \ + (tp)->tv_sec = (time_t)(__ns_since_epoch / NS_PER_SEC); \ + (tp)->tv_nsec = (long)(__ns_since_epoch % NS_PER_SEC); \ + memcpy(&large_int, &lpUserTIme, sizeof(lpUserTIme)); \ + __ns_since_epoch = (large_int.QuadPart * 100); \ + (tp)->tv_sec += (time_t)(__ns_since_epoch / NS_PER_SEC); \ + (tp)->tv_nsec += (long)(__ns_since_epoch % NS_PER_SEC); \ +} while (0); + +#define TIMER_START SET_TIMER_FROM_GETPROCESSTIMES(&__start_time); +#define TIMER_STOP SET_TIMER_FROM_GETPROCESSTIMES(&__end_time); + +#else /* !HAVEGETRUSAGE && !DB_WIN32 */ + +#if DB_VERSION_MAJOR > 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 6 +#define TIMER_START __os_gettime(NULL, &__start_time, 1) +#define TIMER_STOP __os_gettime(NULL, &__end_time, 1) +#else +#define TIMER_START __os_gettime(NULL, &__start_time) +#define TIMER_STOP __os_gettime(NULL, &__end_time) +#endif +#endif /* !HAVE_GETRUSAGE */ + +#else /* !DB_TIMEOUT_TO_TIMESPEC */ + +#if defined(HAVE_CLOCK_GETTIME) +typedef struct timespec db_timespec; +#else +typedef struct { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +} db_timespec; +#endif + +#define timespecadd(vvp, uvp) \ + do { \ + (vvp)->tv_sec += (uvp)->tv_sec; \ + (vvp)->tv_nsec += (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec >= NS_PER_SEC) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_nsec -= NS_PER_SEC; \ + } \ + } while (0) +#define timespecsub(vvp, uvp) \ + do { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_nsec -= (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_nsec += NS_PER_SEC; \ + } \ + } while (0) + +#define TIMER_START CLOCK(__start_time) +#define TIMER_STOP CLOCK(__end_time) + +#if defined(HAVE_CLOCK_GETTIME) +#define CLOCK(tm) do { \ + DB_BENCH_ASSERT(clock_gettime( \ + CLOCK_REALTIME, (struct timespec *)&(tm)) == 0); \ +} while (0) +#elif defined(DB_WIN32) +#define CLOCK(tm) do { \ + struct _timeb __now; \ + _ftime(&__now); \ + (tm).tv_sec = __now.time; \ + (tm).tv_nsec = __now.millitm * MS_PER_NS; \ +} while (0) +#else +#define CLOCK(tm) do { \ + struct timeval __tp; \ + DB_BENCH_ASSERT(gettimeofday(&__tp, NULL) == 0); \ + (tm).tv_sec = __tp.tv_sec; \ + (tm).tv_nsec = __tp.tv_usec * NS_PER_US; \ +} while (0) +#endif +#endif /* !DB_TIMEOUT_TO_TIMESPEC */ + +extern db_timespec __start_time, __end_time; + +#define TIMER_GET(tm) do { \ + tm = __end_time; \ + timespecsub(&(tm), &__start_time); \ +} while (0) +#define TIMER_DISPLAY(ops) do { \ + db_timespec __tmp_time; \ + __tmp_time = __end_time; \ + timespecsub(&__tmp_time, &__start_time); \ + TIME_DISPLAY(ops, __tmp_time); \ +} while (0) +#define TIME_DISPLAY(ops, tm) do { \ + double __secs; \ + int __major, __minor, __patch; \ + __secs = (tm).tv_sec + (double)(tm).tv_nsec / NS_PER_SEC; \ + (void)db_version(&__major, &__minor, &__patch); \ + printf("%d.%d.%d\t%.2f\n", __major, __minor, __patch, \ + (__secs == 0) ? 0.0 : (ops) / __secs); \ +} while (0) + +extern char *progname; /* program name */ + +int b_curalloc __P((int, char *[])); +int b_curwalk __P((int, char *[])); +int b_del __P((int, char *[])); +int b_get __P((int, char *[])); +int b_inmem __P((int, char *[])); +int b_latch __P((int, char *[])); +int b_load __P((int, char *[])); +int b_open __P((int, char *[])); +int b_put __P((int, char *[])); +int b_recover __P((int, char *[])); +int b_txn __P((int, char *[])); +int b_txn_write __P((int, char *[])); +int b_uname __P((void)); +void b_util_abort __P((void)); +int b_util_dir_setup __P((void)); +int b_util_dir_teardown __P((void)); +int b_util_have_hash __P((void)); +int b_util_have_queue __P((void)); +int b_util_unlink __P((char *)); +int b_workload __P((int, char *[])); +u_int32_t part_callback __P((DB *, DBT *)); + +#endif /* !_BENCH_H_ */ diff --git a/test_micro/source/test_micro.c b/test_micro/source/test_micro.c new file mode 100644 index 0000000..49b43de --- /dev/null +++ b/test_micro/source/test_micro.c @@ -0,0 +1,223 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2005-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "bench.h" + +int main __P((int, char *[])); + +static int run __P((char *)); +static int usage __P((void)); + +char *progname; /* program name */ +db_timespec __start_time, __end_time; /* TIMER_START & TIMER_END */ + +static int test_start = 1; /* first test to run */ +static int test_end = 0; /* last test to run */ + +static struct { + char *name; /* command name */ + int (*f)(int, char *[]); /* function */ +} cmdlist[] = { + { "b_curalloc", b_curalloc }, + { "b_curwalk", b_curwalk }, + { "b_del", b_del }, + { "b_get", b_get }, + { "b_inmem", b_inmem }, + { "b_latch", b_latch }, + { "b_load", b_load }, + { "b_open", b_open }, + { "b_put", b_put }, + { "b_recover", b_recover }, + { "b_txn", b_txn }, + { "b_txn_write", b_txn_write }, + { "b_workload", b_workload }, + { NULL, NULL } +}; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + int ch, ret; + char *run_directory, *ifile; + + if ((progname = __db_rpath(argv[0])) == NULL) + progname = argv[0]; + else + ++progname; + +#ifdef DB_BREW + if (bdb_brew_begin() != 0) { + fprintf(stderr, + "%s: failed to initialize Berkeley DB on BREW\n"); + return (EXIT_FAILURE); + } +#endif + + run_directory = NULL; + ifile = "run.std"; + while ((ch = getopt(argc, argv, "d:e:i:s:")) != EOF) + switch (ch) { + case 'd': + run_directory = optarg; + break; + case 'e': + test_end = atoi(optarg); + break; + case 'i': + ifile = optarg; + break; + case 's': + test_start = atoi(optarg); + break; + case '?': + default: + return (usage()); + } + argc -= optind; + argv += optind; + + /* Run in the target directory. */ + if (run_directory != NULL && chdir(run_directory) != 0) { + fprintf(stderr, + "%s: %s: %s\n", progname, run_directory, strerror(errno)); + return (1); + } + + /* Clean up any left-over test directory. */ + if (b_util_dir_teardown()) + return (1); + + ret = run(ifile); + +#ifdef DB_BREW + bdb_brew_end(); +#endif + + return (ret ? EXIT_FAILURE : EXIT_SUCCESS); +} + +/* + * run -- + * Read a configuration file and run the tests. + */ +static int +run(ifile) + char *ifile; +{ +#ifdef HAVE_GETOPT_OPTRESET + extern int optreset; +#endif + extern int optind; + static int test_cur = 0; + FILE *ifp; + int argc, cmdindx, lineno, ret; + char *p, cmd[1024], path[1024], **argv; + + /* Identify the run. */ + if (b_uname() != 0) + return (1); + + /* Open the list of tests. */ + if ((ifp = fopen(ifile, "r")) == NULL) { + fprintf(stderr, + "%s: %s: %s\n", progname, ifile, strerror(errno)); + return (1); + } + + for (lineno = 1; fgets(cmd, sizeof(cmd), ifp) != NULL; ++lineno) { + /* + * Nul-terminate the command line; check for a trailing \r + * on Windows. + */ + if ((p = strchr(cmd, '\n')) == NULL) { +format_err: fprintf(stderr, "%s: %s: line %d: illegal input\n", + progname, ifile, lineno); + return (1); + } + if (p > cmd && p[-1] == '\r') + --p; + *p = '\0'; + + /* Skip empty lines and comments. */ + if (cmd[0] == '\0' || cmd[0] == '#') + continue; + + /* Optionally limit the test run to specific tests. */ + if (++test_cur < test_start || + (test_end != 0 && test_cur > test_end)) + continue; + + fprintf(stderr, "%d: %s\n", test_cur, cmd); + + /* Find the command. */ + if ((p = strchr(cmd, ' ')) == NULL) + goto format_err; + *p++ = '\0'; + for (cmdindx = 0; cmdlist[cmdindx].name != NULL; ++cmdindx) + if (strcmp(cmd, cmdlist[cmdindx].name) == 0) + break; + if (cmdlist[cmdindx].name == NULL) + goto format_err; + + /* Build argc/argv. */ + if (__db_util_arg(cmd, p, &argc, &argv) != 0) + return (1); + + /* Re-direct output into the test log file. */ + (void)snprintf(path, sizeof(path), "%d", test_cur); + if (freopen(path, "a", stdout) == NULL) { + fprintf(stderr, + "%s: %s: %s\n", progname, path, strerror(errno)); + return (1); + } + + /* + * Each underlying "program" re-parses its arguments -- + * reset getopt. + */ +#ifdef HAVE_GETOPT_OPTRESET + optreset = 1; +#endif + optind = 1; + + /* Prepare the test directory. */ + if (b_util_dir_setup()) + return (1); + + ret = cmdlist[cmdindx].f(argc, argv); + + /* Clean up the test directory. */ + if (b_util_dir_teardown()) + return (1); + + (void)fflush(stdout); + +#if DB_VERSION_MAJOR < 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1 + __os_free(NULL, argv, 0); +#else + __os_free(NULL, argv); +#endif + if (ret != 0) + return (ret); + } + + return (0); +} + +static int +usage() +{ + (void)fprintf(stderr, + "usage: %s [-d directory] [-e end] [-i input] [-s start]\n", + progname); + return (EXIT_FAILURE); +} |