summaryrefslogtreecommitdiff
path: root/test_micro
diff options
context:
space:
mode:
Diffstat (limited to 'test_micro')
-rw-r--r--test_micro/README84
-rw-r--r--test_micro/configs/run.small115
-rw-r--r--test_micro/configs/run.std123
-rw-r--r--test_micro/configs/run.workload38
-rw-r--r--test_micro/report121
-rw-r--r--test_micro/report.awk40
-rw-r--r--test_micro/source/LIST101
-rw-r--r--test_micro/source/b_curalloc.c69
-rw-r--r--test_micro/source/b_curwalk.c208
-rw-r--r--test_micro/source/b_del.c166
-rw-r--r--test_micro/source/b_get.c162
-rw-r--r--test_micro/source/b_inmem.c426
-rw-r--r--test_micro/source/b_latch.c199
-rw-r--r--test_micro/source/b_load.c164
-rw-r--r--test_micro/source/b_open.c144
-rw-r--r--test_micro/source/b_put.c225
-rw-r--r--test_micro/source/b_recover.c141
-rw-r--r--test_micro/source/b_txn.c93
-rw-r--r--test_micro/source/b_txn_write.c172
-rw-r--r--test_micro/source/b_uname.c147
-rw-r--r--test_micro/source/b_util.c157
-rw-r--r--test_micro/source/b_workload.c631
-rw-r--r--test_micro/source/b_workload.h153
-rw-r--r--test_micro/source/bench.h217
-rw-r--r--test_micro/source/test_micro.c223
-rw-r--r--test_micro/test_micro170
26 files changed, 4489 insertions, 0 deletions
diff --git a/test_micro/README b/test_micro/README
new file mode 100644
index 0000000..2d35358
--- /dev/null
+++ b/test_micro/README
@@ -0,0 +1,84 @@
+# $Id$
+
+A simple framework for core Berkeley DB micro-benchmarks, intended for
+two purposes: to certify a port of Berkeley DB to a new platform, and
+to provide micro-benchmark information between different Berkeley DB
+releases.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+To run the tests:
+
+1. Unpack and build the Berkeley DB releases you want to run against.
+(Note that test_micro is only known to work on release 4.0 and later.)
+
+2. Run the tests:
+
+ % sh test_micro
+
+ By default, tests are run for all of the Berkeley DB builds found in
+ the current working directory. A build is identified by its
+ top-level name, and is expected to be of the form:
+
+ db-<major>.<minor>.<patch>
+
+ and the fact the Berkeley DB library has been built in the standard
+ location in that directory tree (for example, "build_unix/libdb.a".
+ Directories with other names and directories without a library will
+ be ignored.
+
+ You can run a subset of the tests using command-line arguments:
+
+ % sh test_micro 3 # Run test 3
+ % sh test_micro 3-5 # Run tests 3-5
+ % sh test_micro 3- # Run test 3 to the maximum test
+ % sh test_micro -3 # Run tests 1-3
+
+ You can run on a subset of the releases using the MAJOR and MINOR
+ environment variables:
+
+ % env MAJOR=4 MINOR=2 sh test_micro # Run on 4.2.XX
+ # Run on 4.1.XX and 4.2.XX
+ % env MAJOR=4 MINOR='[12]' sh test_micro
+
+3. If you want to generate the micro-benchmark output build the HTML
+ page after the run:
+
+ % sh report
+
+ The output of the tests and the web page are created in the directory
+ RUN.hostname (for example, "RUN.abyssinian"). The tests are numeric
+ filenames in that directory (for example, "1", "2", "36"). The web
+ page output is in the file "hostname.html".
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+To run different test configurations:
+
+1. Modify the configuration files in the configs/ directory to run the
+ tests you want to run. The configuration file configs/run.std is the
+ tests that are run by the test_micro shell script.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+To add a new test program:
+
+1. Add a new file to the SOURCE directory, and build it as part of
+ building the test_micro program. This will require changes to
+ the test_micro shell script, as well as the standard build rules
+ for all of the Berkeley DB systems, found in the dist/ directory.
+
+ The file must output the following line on stdout:
+
+ # title
+ major.minor.patch<tab>operations/second
+
+ For example:
+
+ # 10000 Btree database open/close pairs
+ 3.0.55 29600.69
+ 3.1.17 30438.25
+
+2. Modify the file test_micro/test_micro.c to exec your new command
+ (this should only require changing the cmdlist structure at the top
+ of that file).
+
+3. Modify the test_micro configuration files in the configs/ directory
+ to run your new command.
diff --git a/test_micro/configs/run.small b/test_micro/configs/run.small
new file mode 100644
index 0000000..6bf408c
--- /dev/null
+++ b/test_micro/configs/run.small
@@ -0,0 +1,115 @@
+b_curalloc -c 100
+b_curwalk -c 10 -d 10 -Ss -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -Ss -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -p -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -p -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -pSs -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -pSs -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -ps -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -ps -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -s -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -s -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 100 -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 100 -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 10 -d 10 -s -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -d 10 -s -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -d 10 -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -d 10 -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -p -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -p -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -p -t queue -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -p -t recno -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -t btree -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -t hash -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -t queue -w 10 -C 524288 -P 1024
+b_curwalk -c 100 -t recno -w 10 -C 524288 -P 1024
+
+b_del -c 100 -t btree -C 524288
+b_del -c 100 -t hash -C 524288
+b_del -c 100 -t queue -C 524288
+b_del -c 100 -t recno -C 524288
+b_del -w -c 100 -t btree -C 524288
+b_del -w -c 100 -t hash -C 524288
+b_del -w -c 100 -t queue -C 524288
+b_del -w -c 100 -t recno -C 524288
+
+b_get -c 100 -t btree -C 524288
+b_get -c 100 -t hash -C 524288
+b_get -c 100 -t queue -C 524288
+b_get -c 100 -t recno -C 524288
+
+b_inmem -d 32 -k 8 -o 10 -P 1024 -C 524288 bulk
+b_inmem -d 32 -k 8 -o 10 -P 1024 -C 524288 txn-sync
+b_inmem -d 32 -k 8 -o 10 -P 1024 -C 524288 read
+b_inmem -d 32 -k 8 -o 100 -P 1024 -C 524288 txn-nosync
+b_inmem -d 32 -k 8 -o 100 -P 1024 -C 524288 txn-read
+b_inmem -d 32 -k 8 -o 100 -P 1024 -C 524288 txn-write
+b_inmem -d 32 -k 8 -o 100 -P 1024 -C 524288 txn-write-nosync
+b_inmem -d 32 -k 8 -o 100 -P 1024 -C 524288 write
+
+b_load -c 100 -t hash -C 524288
+b_load -c 100 -t btree -C 524288
+b_load -c 100 -t queue -C 524288
+b_load -c 100 -t recno -C 524288
+b_load -d -c 100 -t btree -C 524288
+b_load -d -c 100 -t hash -C 524288
+
+b_open -c 100 -d -t btree
+b_open -c 100 -d -t hash
+b_open -c 100 -d -t queue
+b_open -c 100 -d -t recno
+b_open -c 100 -f -t btree
+b_open -c 100 -f -t hash
+b_open -c 100 -f -t queue
+b_open -c 100 -f -t recno
+b_open -c 100 -fd -t btree
+b_open -c 100 -fd -t hash
+b_open -c 100 -fd -t recno
+b_open -c 100 -t btree
+b_open -c 100 -t hash
+b_open -c 100 -t queue
+b_open -c 100 -t recno
+
+b_put -c 10 -d 64 -t btree -C 524288
+b_put -c 10 -d 64 -t hash -C 524288
+b_put -c 10 -d 64 -t recno -C 524288
+b_put -c 100 -s 10 -t btree -C 524288
+b_put -c 100 -s 10 -t hash -C 524288
+b_put -c 100 -s 10 -t queue -C 524288
+b_put -c 100 -s 10 -t recno -C 524288
+b_put -c 100 -t btree -C 524288
+b_put -c 100 -t hash -C 524288
+b_put -c 100 -t queue -C 524288
+b_put -c 100 -t recno -C 524288
+
+b_recover -c 100 -C 524288
+
+b_txn -a -c 100
+b_txn -c 100
+
+b_txn_write -a -c 100
+b_txn_write -ar -c 100
+b_txn_write -c 100
+b_txn_write -r -c 100
+b_txn_write -rw -c 100
+b_txn_write -w -c 100
+
+b_workload -w A -c 100 -g 10 -d 20 -p 1024 -t btree
+b_workload -w A -c 100 -g 10 -d 20 -p 1024 -t hash
+b_workload -w A -c 100 -g 10 -d 20 -p 1024 -t btree
+b_workload -w A -c 100 -g 10 -d 20 -p 1024 -t hash
+b_workload -w A -c 100 -g 10 -d 20 -p 1024 -t btree
+b_workload -w A -c 100 -g 10 -d 20 -p 1024 -t hash
+b_workload -w A -c 100 -g 10 -d 20 -p 1024 -t btree
+b_workload -w A -c 100 -g 10 -d 20 -p 1024 -t hash
+b_workload -w A -c 100 -g 10 -d 256 -p 1024 -t btree
+b_workload -w A -c 100 -g 10 -d 256 -p 1024 -t hash
+b_workload -w A -c 100 -g 10 -o -t btree -p 1024
+b_workload -w A -c 100 -g 10 -o -t hash -p 1024
+b_workload -w E -c 100 -g 10 -d 20 -p 1024 -t btree
+b_workload -w E -c 100 -g 10 -d 20 -p 1024 -t hash
+b_workload -w F -c 100 -g 10 -d 20 -p 1024 -t btree
+b_workload -w F -c 100 -g 10 -d 20 -p 1024 -t hash
+b_workload -w G -c 100 -g 10 -d 20 -p 1024 -t btree
+b_workload -w G -c 100 -g 10 -d 20 -p 1024 -t hash
+b_workload -w H -c 100 -d 20 -p 1024 -t hash
diff --git a/test_micro/configs/run.std b/test_micro/configs/run.std
new file mode 100644
index 0000000..264e1d9
--- /dev/null
+++ b/test_micro/configs/run.std
@@ -0,0 +1,123 @@
+b_curalloc -c 1000000
+
+b_curwalk -c 100 -d 1000 -Ss -t btree -w 100
+b_curwalk -c 100 -d 1000 -Ss -t hash -w 100
+b_curwalk -c 100 -d 1000 -p -t btree -w 100
+b_curwalk -c 100 -d 1000 -p -t hash -w 100
+b_curwalk -c 100 -d 1000 -pSs -t btree -w 100
+b_curwalk -c 100 -d 1000 -pSs -t hash -w 100
+b_curwalk -c 100 -d 1000 -ps -t btree -w 100
+b_curwalk -c 100 -d 1000 -ps -t hash -w 100
+b_curwalk -c 100 -d 1000 -s -t btree -w 100
+b_curwalk -c 100 -d 1000 -s -t hash -w 100
+b_curwalk -c 100 -d 1000 -t btree -w 100
+b_curwalk -c 100 -d 1000 -t hash -w 100
+b_curwalk -c 10000 -d 10 -s -t btree -w 100
+b_curwalk -c 10000 -d 10 -s -t hash -w 100
+b_curwalk -c 10000 -d 10 -t btree -w 100
+b_curwalk -c 10000 -d 10 -t hash -w 100
+b_curwalk -c 100000 -p -t btree -w 100
+b_curwalk -c 100000 -p -t hash -w 100
+b_curwalk -c 100000 -p -t queue -w 100
+b_curwalk -c 100000 -p -t recno -w 100
+b_curwalk -c 100000 -t btree -w 100
+b_curwalk -c 100000 -t hash -w 100
+b_curwalk -c 100000 -t queue -w 100
+b_curwalk -c 100000 -t recno -w 100
+
+b_del -c 100000 -t btree
+b_del -c 100000 -t hash
+b_del -c 100000 -t queue
+b_del -c 100000 -t recno
+b_del -w -c 100000 -t btree
+b_del -w -c 100000 -t hash
+b_del -w -c 100000 -t queue
+b_del -w -c 100000 -t recno
+
+b_get -c 1000000 -t btree
+b_get -c 1000000 -t hash
+b_get -c 1000000 -t queue
+b_get -c 1000000 -t recno
+
+b_inmem -d 32 -k 8 -o 100000 -P 32768 bulk
+b_inmem -d 32 -k 8 -o 100000 -P 32768 txn-sync
+b_inmem -d 32 -k 8 -o 1000000 -P 32768 read
+b_inmem -d 32 -k 8 -o 1000000 -P 32768 txn-nosync
+b_inmem -d 32 -k 8 -o 1000000 -P 32768 txn-read
+b_inmem -d 32 -k 8 -o 1000000 -P 32768 txn-write
+b_inmem -d 32 -k 8 -o 1000000 -P 32768 txn-write-nosync
+b_inmem -d 32 -k 8 -o 1000000 -P 32768 write
+
+b_load -c 100000 -t hash
+b_load -c 1000000 -t btree
+b_load -c 1000000 -t queue
+b_load -c 1000000 -t recno
+b_load -d -c 1000000 -t btree
+b_load -d -c 1000000 -t hash
+
+b_open -c 10000 -d -t btree
+b_open -c 10000 -d -t hash
+b_open -c 10000 -d -t queue
+b_open -c 10000 -d -t recno
+b_open -c 10000 -f -t btree
+b_open -c 10000 -f -t hash
+b_open -c 10000 -f -t queue
+b_open -c 10000 -f -t recno
+b_open -c 10000 -fd -t btree
+b_open -c 10000 -fd -t hash
+b_open -c 10000 -fd -t recno
+b_open -c 10000 -t btree
+b_open -c 10000 -t hash
+b_open -c 10000 -t queue
+b_open -c 10000 -t recno
+
+b_put -c 100000 -d 204800 -t btree
+b_put -c 100000 -d 204800 -t hash
+b_put -c 100000 -d 204800 -t recno
+b_put -c 1000000 -s 10 -t btree
+b_put -c 1000000 -s 10 -t hash
+b_put -c 1000000 -s 10 -t queue
+b_put -c 1000000 -s 10 -t recno
+b_put -c 1000000 -t btree
+b_put -c 1000000 -t hash
+b_put -c 1000000 -t queue
+b_put -c 1000000 -t recno
+
+b_recover -c 1000000
+
+b_txn -a -c 1000000
+b_txn -c 1000000
+
+b_txn_write -a -c 100000
+b_txn_write -ar -c 100000
+b_txn_write -c 10000
+b_txn_write -r -c 10000
+b_txn_write -rw -c 100000
+b_txn_write -w -c 100000
+
+b_workload -w A -c 100000 -g 10 -d 20 -p 1024 -t btree
+b_workload -w A -c 100000 -g 10 -d 20 -p 1024 -t hash
+b_workload -w A -c 100000 -g 10 -d 20 -p 32768 -t btree
+b_workload -w A -c 100000 -g 10 -d 20 -p 32768 -t hash
+b_workload -w A -c 100000 -g 10 -d 20 -p 4096 -t btree
+b_workload -w A -c 100000 -g 10 -d 20 -p 4096 -t hash
+b_workload -w A -c 100000 -g 10 -d 20 -p 8192 -t btree
+b_workload -w A -c 100000 -g 10 -d 20 -p 8192 -t hash
+b_workload -w A -c 100000 -g 10 -d 256 -p 1024 -t btree
+b_workload -w A -c 100000 -g 10 -d 256 -p 1024 -t hash
+b_workload -w A -c 100000 -o -t btree
+b_workload -w A -c 100000 -o -t hash
+b_workload -w E -c 100000 -g 10 -d 20 -p 1024 -t btree
+b_workload -w E -c 100000 -g 10 -d 20 -p 1024 -t hash
+b_workload -w F -c 100000 -g 10 -d 20 -p 1024 -t btree
+b_workload -w F -c 100000 -g 10 -d 20 -p 1024 -t hash
+b_workload -w G -c 100000 -g 10 -d 20 -p 1024 -t btree
+b_workload -w G -c 100000 -g 10 -d 20 -p 1024 -t hash
+b_workload -w H -c 10000000 -d 20 -p 1024 -t hash
+
+b_latch -c 100000000
+b_latch -c 100000000 -n 1
+b_latch -c 100000000 -n 2
+b_latch -c 100000000 -n 4
+b_latch -c 100000000 -n 8
+b_latch -c 100000000 -n 64
diff --git a/test_micro/configs/run.workload b/test_micro/configs/run.workload
new file mode 100644
index 0000000..4d289e2
--- /dev/null
+++ b/test_micro/configs/run.workload
@@ -0,0 +1,38 @@
+b_workload -m 1 -w A -v -c 100000 -o -t hash
+b_workload -m 2 -w A -v -c 100000 -o -t btree
+b_workload -m 3 -w A -v -c 100000 -g 10 -d 20 -p 32768 -t hash
+b_workload -m 4 -w A -v -c 100000 -g 10 -d 20 -p 32768 -t btree
+b_workload -m 5 -w A -v -c 100000 -g 10 -d 20 -p 8192 -t hash
+b_workload -m 6 -w A -v -c 100000 -g 10 -d 20 -p 8192 -t btree
+b_workload -m 7 -w A -v -c 100000 -g 10 -d 20 -p 4096 -t hash
+b_workload -m 8 -w A -v -c 100000 -g 10 -d 20 -p 4096 -t btree
+b_workload -m 9 -w A -v -c 100000 -g 10 -d 20 -p 1024 -t hash
+b_workload -m 10 -w A -v -c 100000 -g 10 -d 20 -p 1024 -t btree
+b_workload -m 11 -w A -v -c 10000 -g 10 -d 256 -p 1024 -t hash
+b_workload -m 12 -w A -v -c 10000 -g 10 -d 256 -p 1024 -t btree
+b_workload -m 13 -w F -v -c 100000 -g 10 -d 20 -p 1024 -t hash
+b_workload -m 14 -w F -v -c 100000 -g 10 -d 20 -p 1024 -t btree
+b_workload -m 15 -w G -v -c 100000 -g 10 -d 20 -p 1024 -t hash
+b_workload -m 16 -w G -v -c 100000 -g 10 -d 20 -p 1024 -t btree
+# Run put/get(G) with different page sizes, since fill factor
+# is interesting when not deleting all of the elements.
+b_workload -m 17 -w E -v -c 100000 -g 10 -d 20 -p 32768 -t hash
+b_workload -m 18 -w E -v -c 100000 -g 10 -d 20 -p 32768 -t btree
+b_workload -m 19 -w E -v -c 100000 -g 10 -d 20 -p 8192 -t hash
+b_workload -m 20 -w E -v -c 100000 -g 10 -d 20 -p 8192 -t btree
+b_workload -m 21 -w E -v -c 100000 -g 10 -d 20 -p 4096 -t hash
+b_workload -m 22 -w E -v -c 100000 -g 10 -d 20 -p 4096 -t btree
+b_workload -m 23 -w E -v -c 100000 -g 10 -d 20 -p 1024 -t hash
+b_workload -m 24 -w E -v -c 100000 -g 10 -d 20 -p 1024 -t btree
+b_workload -m 25 -w E -v -c 10000 -g 10 -d 256 -p 1024 -t hash
+b_workload -m 26 -w E -v -c 10000 -g 10 -d 256 -p 1024 -t btree
+b_workload -m 27 -w E -v -c 100000 -g 10 -o -d 10 -p 1024 -t hash
+b_workload -m 28 -w E -v -c 100000 -g 10 -o -d 10 -p 1024 -t btree
+b_workload -m 29 -w A -v -c 10000 -g 10 -d 1024 -p 512 -t hash
+b_workload -m 30 -w A -v -c 10000 -g 10 -d 1024 -p 512 -t btree
+b_workload -m 31 -w H -v -c 1000000 -d 20 -p 8192 -t hash
+b_workload -m 32 -w H -v -c 1000000 -d 20 -p 8192 -t btree
+b_workload -m 33 -w H -v -c 1000000 -d 20 -p 512 -t hash
+b_workload -m 34 -w H -v -c 1000000 -d 20 -p 512 -t btree
+b_workload -m 35 -w H -v -c 10000000 -d 20 -p 512 -t hash
+b_workload -m 36 -w H -v -c 10000000 -d 20 -p 512 -t btree
diff --git a/test_micro/report b/test_micro/report
new file mode 100644
index 0000000..c7358db
--- /dev/null
+++ b/test_micro/report
@@ -0,0 +1,121 @@
+#! /bin/sh
+#
+# $Id$
+
+# Use our pathname to locate the absolute path for our awk scripts.
+t=`dirname $0`
+h=`(cd $t && echo $PWD)`
+
+# We need a temporary file, and we need to clean it up after failure.
+tmp="$PWD/__t"
+trap 'rm -f $tmp; exit 1' 1 2 3 13 15
+trap 'rm -f $tmp; exit 0' 0
+
+# header --
+# Output HTML page header.
+# $1: directory name.
+header()
+{
+ echo "<html>"
+ echo "<head>"
+ machine=`echo $1 | sed 's/.*\.//'`
+ echo "<title>Berkeley DB test_micro run: $machine</title>"
+ echo "</head>"
+ echo "<body bgcolor=white>"
+ echo "<center><h1>Berkeley DB test_micro run: $machine</h1></center>"
+ echo "<p align=right>`date`</p>"
+ test -f UNAME && cat UNAME
+}
+
+# footer --
+# Output HTML page footer.
+footer()
+{
+ echo "</body>"
+ echo "</html>"
+}
+
+# table --
+# Create a table.
+# $1: output file
+table()
+{
+ title="Test $1: `egrep '^#' $1 | sort -u | sed 's/^#[ ]*//'`"
+ echo "<hr size=1 noshade>"
+ echo "<table cellspacing=0 cellpadding=0 border=0>"
+ echo "<th align=left colspan=2>$title</th>"
+ echo "<tr>"
+ echo "<th align=right>Release</th>"
+ echo "<th align=center>Operations/second</th>"
+ echo "</tr>"
+
+ # You can set the MAJOR and MINOR environment variables to limit
+ # the BDB releases for which a report is created.
+ #
+ # Process the output into a single line per release.
+ egrep "^${MAJOR:-[0-9][0-9]*}.${MINOR:-*}" $1 |
+ awk -f $h/report.awk |
+ sort -n > $tmp
+
+ # Get the release count, and maximum value.
+ nrel=`wc -l $tmp`
+ max=`sort -k 2 -n -t ":" < $tmp | tail -1 | awk -F: '{print $2}'`
+
+ # Display the output.
+ IFS=":"
+ cat $tmp | while true; do
+ # release, average, runs, percent, standard deviation
+ read rel avg runs percent rsd
+ if test "X$rel" = "X" ; then
+ break;
+ fi
+
+ # echo "read: rel $rel, avg $avg, runs $runs, percent $percent, rsd $rsd" > /dev/stderr
+
+ echo "<tr>"
+ echo "<td align=right width=80><pre>$rel</pre></td>"
+ echo "<td>"
+ echo "<table>"
+ echo "<tr>"
+ if [ "$max" = "0.00" ];then
+ t=0
+ else
+ t=`echo "400 * ($avg/($max + $max/10))" | bc -l`
+ fi
+ t=`printf %.0f $t`
+ echo "<td bgcolor='#003366' width=$t>&nbsp;</td>"
+ t=`echo "400 - $t" | bc`
+ echo "<td bgcolor='#CCCCCC' width=$t>&nbsp;</td>"
+ echo "<td>&nbsp;&nbsp;</td>"
+ echo "<td align=right width=100><pre>$avg</pre></td>"
+ if test "X$percent" != "X" -o "X$rsd" != "X"; then
+ echo -n "<td align=right><pre>&nbsp;&nbsp;("
+ if test "X$percent" = "X"; then
+ echo -n '***'
+ else
+ echo -n "-$percent"
+ fi
+ if test "X$rsd" != "X"; then
+ echo -n ", $rsd rsd, $runs runs"
+ fi
+ echo ")</pre></td>"
+ fi
+ echo "</tr>"
+ echo "</table>"
+ echo "</tr>"
+ done
+ echo "</table>"
+}
+
+for i in RUN.*; do
+ echo "Building $i..."
+ name=`echo $i | sed 's/RUN.//'`
+ (cd $i
+ header $i
+ for j in `ls [0-9]* | sort -n`; do
+ table $j
+ done
+ footer) > $i/$name.html
+done
+
+exit 0
diff --git a/test_micro/report.awk b/test_micro/report.awk
new file mode 100644
index 0000000..6ae3303
--- /dev/null
+++ b/test_micro/report.awk
@@ -0,0 +1,40 @@
+# $Id$
+
+/^[^#]/ {
+ total[$1] += $2
+ sum[$1] += $2 * $2
+ ++count[$1];
+}
+END {
+ # Compute the average, find the maximum.
+ for (i in total) {
+ avg[i] = total[i] / count[i];
+ if (max < avg[i])
+ max = avg[i]
+ }
+
+ for (i in total) {
+ # Calculate variance by raw score method.
+ var = (sum[i] - ((total[i] * total[i]) / count[i])) / count[i];
+
+ # The standard deviation is the square root of the variance.
+ stdv = sqrt(var);
+
+ # Display the release value, the average score, and run count.
+ printf("%s:%.2f:%d:", i, avg[i], count[i]);
+
+ # If this run wasn't the fastest, display the percent by which
+ # this run was slower.
+ if (max != avg[i])
+ printf("%.0f%%", ((max - avg[i]) / max) * 100);
+
+ printf(":");
+
+ # If there was more than a single run, display the relative
+ # standard deviation.
+ if (count[i] > 1)
+ printf("%.0f%%", stdv * 100 / avg[i]);
+
+ printf("\n");
+ }
+}
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);
+}
diff --git a/test_micro/test_micro b/test_micro/test_micro
new file mode 100644
index 0000000..af3e358
--- /dev/null
+++ b/test_micro/test_micro
@@ -0,0 +1,170 @@
+#! /bin/sh
+#
+# $Id$
+LIBS=${LIBS:-"-lpthread"}
+WINBUILDDIR="Win32/Release"
+
+CYGWIN=0
+HOSTOS="`uname -o 2>/dev/null||uname -s 2>/dev/null`"
+if test `echo "$HOSTOS"|grep -i cygwin|wc -l` -gt 0;then
+ CYGWIN=1
+fi
+
+# build_test_micro_posix
+# Build test_micro on a POSIX system.
+build_test_micro_posix()
+{
+ # See if there's a test_micro binary already.
+ test $clean -eq 0 && test -x test_micro && return 0
+
+ echo 'Compiling test_micro on posix system...'
+ rm -f test_micro
+ CC=${CC:-gcc}
+ if [ "$CC" = "gcc" ]; then
+ CC="$CC -O3 -Wall"
+ else
+ CC="$CC -O"
+ fi
+ $CC -I. -I../dbinc -I../dbinc_auto -I.. -I$h/source \
+ $SRC -o test_micro ./libdb.a $LIBS || return 1
+}
+
+# build_test_micro_windows
+# Build test_micro on a Windows system.
+build_test_micro_windows()
+{
+ # See if there's a test_micro binary already.
+ test $clean -eq 0 && test -x test_micro && return 0
+
+ echo 'Compiling test_micro on windows ...'
+ rm -f test_micro
+
+ cl /nologo /o test_micro /DDB_WIN32 /G6 /Ox /MD\
+ -I./ -I../ -I$h/source/ -I../dbinc -I../dbinc_auto $SRC $WINSRC\
+ ./$WINBUILDDIR/libdb*.lib ./Release/libdb*.lib ws2_32.lib advapi32.lib
+}
+
+# run --
+# $1: args
+run()
+{
+ # You can set the MAJOR and MINOR environment variables to limit
+ # the BDB releases on which the tests are run.
+ echo Versions db-${MAJOR:-[3-9]}.${MINOR:-*}.*
+ for i in db-${MAJOR:-[3-9]}.${MINOR:-*}.*; do
+
+ major=`echo $i|sed "s/db-//g"|cut -d . -f 1`
+ minor=`echo $i|sed "s/db-//g"|cut -d . -f 2`
+ if test $major -gt "4";then
+ WINBUILDDIR="Win32/Release"
+ elif test $major -lt "4";then
+ WINBUILDDIR="Release"
+ elif test "X$minor" = "X" -o "$minor" -lt "8";then
+ WINBUILDDIR="Release"
+ else
+ WINBUILDDIR="Win32/Release"
+ fi
+
+ if [ -f $i/$variant/libdb.a ] ; then
+ (cd $i/$variant/ &&
+ build_test_micro_posix || exit 1)
+ elif [ -f $i/build_windows/${WINBUILDDIR}/libdb??.lib ] ; then
+ (cd $i/build_windows &&
+ build_test_micro_windows || exit 1)
+ fi
+
+ echo "$i run begins: `date`"
+ echo "test_micro $1..."
+ if [ -f $i/$variant/libdb.a ] ; then
+ (cd $i/$variant/ && ./test_micro $1 || exit 1)
+ if [ -f $t/gmon.out ] ; then
+ mv $t/gmon.out $i/$variant
+ gprof $i/$variant/.libs/lt-test_micro $i/$variant/gmon.out > $i/$variant/gprof.out
+ fi
+ elif [ -f $i/build_windows/${WINBUILDDIR}/libdb??.lib ] ; then
+ (cd $i/build_windows/ && ./test_micro $1 || exit 1)
+ fi
+ echo "$i run ends: `date`"
+ done
+}
+
+# Get a path to this shellscript.
+t=`dirname $0`
+h=`(cd $t && pwd)`
+if [ "$CYGWIN" = "1" ];then
+ h="`cygpath -m -a \"$h\"`"
+fi
+# We may need to re-compile, create a list of our sources.
+SRC="$h/source/b_curalloc.c $h/source/b_curwalk.c $h/source/b_del.c
+$h/source/b_get.c $h/source/b_inmem.c $h/source/b_load.c $h/source/b_latch.c
+$h/source/b_open.c $h/source/b_put.c $h/source/b_recover.c
+$h/source/b_txn.c $h/source/b_txn_write.c $h/source/b_uname.c
+$h/source/b_util.c $h/source/b_workload.c $h/source/test_micro.c
+$h/../common/util_arg.c"
+
+WINSRC="$h/../clib/getopt.c"
+
+# Process arguments.
+clean=0 # Rebuild test_micro
+workload=0 # Run workload tests
+start_test=0 # Start test
+end_test=0 # End test
+variant=build_unix
+while :
+ do case "$1" in
+ -c) # Rebuild test_micro.
+ clean=1
+ shift;;
+ -w) # Run workload tests
+ workload=1
+ shift;;
+ [1-9]*-[0-9]*) # Range: -3, 3-, 3-10
+ start_test=`echo $1|sed 's/-.*//'`
+ start_test=${start_test:=1}
+ end_test=`echo $1|sed 's/.*-//'`
+ end_test=${end_test:=0}
+ shift;;
+ [1-9]*) # Specific test
+ start_test="$1"
+ end_test="$1"
+ shift;;
+ -v) variant=$2 # get code here, rather than from build_unix
+ shift; shift;;
+ *)
+ break;;
+ esac
+done
+test "$#" -ne 0 && {
+ echo 'usage: test_micro [-cw] [# | #- | -# | #-#]' >& 2
+ exit 1
+}
+
+if test $start_test != 0; then
+ cmd="$cmd -s $start_test"
+fi
+if test $end_test != 0; then
+ cmd="$cmd -e $end_test"
+fi
+
+# Create the run directory, and initialize test_micro's arguments.
+t=RUN.`hostname | sed 's/\..*//'`
+[ -d $t ] || mkdir $t
+if [ "$CYGWIN" = "1" ];then
+ cmd="$cmd -d `(cd $t && cygpath -m -a \"$PWD\")`"
+else
+ cmd="$cmd -d `(cd $t && pwd)`"
+fi
+# Set input file.
+if test "$workload" -eq 1; then
+ cmd="$cmd -i $h/configs/run.workload"
+else
+ cmd="$cmd -i $h/configs/run.std"
+fi
+
+# Flush any I/O, just to get as a clean a timing as we can, ignore errors,
+# sync is privleged on some systems.
+(sync && sleep 1 2>&1) > /dev/null
+
+run "$cmd"
+
+exit 0