1/* 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2005-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9#include "bench.h" 10 11#if DB_VERSION_MAJOR > 4 || DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0 12/* 13 * The in-memory tests don't run on early releases of Berkeley DB. 14 */ 15#undef MEGABYTE 16#define MEGABYTE (1024 * 1024) 17 18u_int32_t bulkbufsize = 4 * MEGABYTE; 19u_int32_t cachesize = 32 * MEGABYTE; 20u_int32_t datasize = 32; 21u_int32_t keysize = 8; 22u_int32_t logbufsize = 8 * MEGABYTE; 23u_int32_t numitems; 24u_int32_t pagesize = 32 * 1024; 25 26FILE *fp; 27 28static void b_inmem_op_ds __P((u_int, int)); 29static void b_inmem_op_ds_bulk __P((u_int, u_int *)); 30static void b_inmem_op_tds __P((u_int, int, u_int32_t, u_int32_t)); 31static int b_inmem_usage __P((void)); 32 33static void 34b_inmem_op_ds(u_int ops, int update) 35{ 36 DB_ENV *dbenv; 37 char *letters = "abcdefghijklmnopqrstuvwxuz"; 38 DB *dbp; 39 DBT key, data; 40 char *keybuf, *databuf; 41 DB_MPOOL_STAT *gsp; 42 43 DB_BENCH_ASSERT((keybuf = malloc(keysize)) != NULL); 44 DB_BENCH_ASSERT((databuf = malloc(datasize)) != NULL); 45 46 memset(&key, 0, sizeof(key)); 47 memset(&data, 0, sizeof(data)); 48 key.data = keybuf; 49 key.size = keysize; 50 memset(keybuf, 'a', keysize); 51 52 data.data = databuf; 53 data.size = datasize; 54 memset(databuf, 'b', datasize); 55 56 DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); 57 dbenv = dbp->dbenv; 58 dbp->set_errfile(dbp, stderr); 59 60 DB_BENCH_ASSERT(dbp->set_pagesize(dbp, pagesize) == 0); 61 DB_BENCH_ASSERT(dbp->open( 62 dbp, NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0666) == 0); 63 64 (void)dbenv->memp_stat(dbenv, &gsp, NULL, DB_STAT_CLEAR); 65 66 if (update) { 67 TIMER_START; 68 for (; ops > 0; --ops) { 69 keybuf[(ops % keysize)] = letters[(ops % 26)]; 70 DB_BENCH_ASSERT( 71 dbp->put(dbp, NULL, &key, &data, 0) == 0); 72 } 73 TIMER_STOP; 74 } else { 75 DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); 76 TIMER_START; 77 for (; ops > 0; --ops) 78 DB_BENCH_ASSERT( 79 dbp->get(dbp, NULL, &key, &data, 0) == 0); 80 TIMER_STOP; 81 } 82 83 if (dbenv->memp_stat(dbenv, &gsp, NULL, 0) == 0) 84 DB_BENCH_ASSERT(gsp->st_cache_miss == 0); 85 86 DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); 87} 88 89static void 90b_inmem_op_ds_bulk(u_int ops, u_int *totalp) 91{ 92 DB_ENV *dbenv; 93 DB *dbp; 94 DBC *dbc; 95 DBT key, data; 96 u_int32_t len, klen; 97 u_int i, total; 98 char *keybuf, *databuf; 99 void *pointer, *dp, *kp; 100 DB_MPOOL_STAT *gsp; 101 102 DB_BENCH_ASSERT((keybuf = malloc(keysize)) != NULL); 103 DB_BENCH_ASSERT((databuf = malloc(bulkbufsize)) != NULL); 104 105 memset(&key, 0, sizeof(key)); 106 memset(&data, 0, sizeof(data)); 107 key.data = keybuf; 108 key.size = keysize; 109 110 data.data = databuf; 111 data.size = datasize; 112 memset(databuf, 'b', datasize); 113 114 DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0); 115 dbenv = dbp->dbenv; 116 dbp->set_errfile(dbp, stderr); 117 118 DB_BENCH_ASSERT(dbp->set_pagesize(dbp, pagesize) == 0); 119 DB_BENCH_ASSERT(dbp->set_cachesize(dbp, 0, cachesize, 1) == 0); 120 DB_BENCH_ASSERT( 121 dbp->open(dbp, NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0666) == 0); 122 123 for (i = 1; i <= numitems; ++i) { 124 (void)snprintf(keybuf, keysize, "%7d", i); 125 DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); 126 } 127 128#if 0 129 fp = fopen("before", "w"); 130 dbp->set_msgfile(dbp, fp); 131 DB_BENCH_ASSERT (dbp->stat_print(dbp, DB_STAT_ALL) == 0); 132#endif 133 134 DB_BENCH_ASSERT(dbp->cursor(dbp, NULL, &dbc, 0) == 0); 135 136 data.ulen = bulkbufsize; 137 data.flags = DB_DBT_USERMEM; 138 139 (void)dbenv->memp_stat(dbenv, &gsp, NULL, DB_STAT_CLEAR); 140 141 TIMER_START; 142 for (total = 0; ops > 0; --ops) { 143 DB_BENCH_ASSERT(dbc->c_get( 144 dbc, &key, &data, DB_FIRST | DB_MULTIPLE_KEY) == 0); 145 DB_MULTIPLE_INIT(pointer, &data); 146 while (pointer != NULL) { 147 DB_MULTIPLE_KEY_NEXT(pointer, &data, kp, klen, dp, len); 148 if (kp != NULL) 149 ++total; 150 } 151 } 152 TIMER_STOP; 153 *totalp = total; 154 155 if (dbenv->memp_stat(dbenv, &gsp, NULL, 0) == 0) 156 DB_BENCH_ASSERT(gsp->st_cache_miss == 0); 157 158#if 0 159 fp = fopen("before", "w"); 160 dbp->set_msgfile(dbp, fp); 161 DB_BENCH_ASSERT (dbp->stat_print(dbp, DB_STAT_ALL) == 0); 162#endif 163 164 DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); 165 166 COMPQUIET(dp, NULL); 167 COMPQUIET(klen, 0); 168 COMPQUIET(len, 0); 169} 170 171static void 172b_inmem_op_tds(u_int ops, int update, u_int32_t env_flags, u_int32_t log_flags) 173{ 174 DB *dbp; 175 DBT key, data; 176 DB_ENV *dbenv; 177 DB_MPOOL_STAT *gsp; 178 DB_TXN *txn; 179 char *keybuf, *databuf; 180 181 DB_BENCH_ASSERT((keybuf = malloc(keysize)) != NULL); 182 DB_BENCH_ASSERT((databuf = malloc(datasize)) != NULL); 183 184 memset(&key, 0, sizeof(key)); 185 memset(&data, 0, sizeof(data)); 186 key.data = keybuf; 187 key.size = keysize; 188 memset(keybuf, 'a', keysize); 189 190 data.data = databuf; 191 data.size = datasize; 192 memset(databuf, 'b', datasize); 193 194 DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); 195 196 dbenv->set_errfile(dbenv, stderr); 197 198 /* General environment configuration. */ 199#ifdef DB_AUTO_COMMIT 200 DB_BENCH_ASSERT(dbenv->set_flags(dbenv, DB_AUTO_COMMIT, 1) == 0); 201#endif 202 if (env_flags != 0) 203 DB_BENCH_ASSERT(dbenv->set_flags(dbenv, env_flags, 1) == 0); 204 205 /* Logging configuration. */ 206 if (log_flags != 0) 207#if DB_VERSION_MINOR >= 7 208 DB_BENCH_ASSERT( 209 dbenv->log_set_config(dbenv, log_flags, 1) == 0); 210#else 211 DB_BENCH_ASSERT(dbenv->set_flags(dbenv, log_flags, 1) == 0); 212#endif 213#ifdef DB_LOG_INMEMORY 214 if (!(log_flags & DB_LOG_INMEMORY)) 215#endif 216#ifdef DB_LOG_IN_MEMORY 217 if (!(log_flags & DB_LOG_IN_MEMORY)) 218#endif 219 DB_BENCH_ASSERT(dbenv->set_lg_max(dbenv, logbufsize * 10) == 0); 220 DB_BENCH_ASSERT(dbenv->set_lg_bsize(dbenv, logbufsize) == 0); 221 222 DB_BENCH_ASSERT(dbenv->open(dbenv, "TESTDIR", 223 DB_CREATE | DB_PRIVATE | DB_INIT_LOCK | 224 DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN, 0666) == 0); 225 226 DB_BENCH_ASSERT(db_create(&dbp, dbenv, 0) == 0); 227 DB_BENCH_ASSERT(dbp->set_pagesize(dbp, pagesize) == 0); 228 DB_BENCH_ASSERT(dbp->open( 229 dbp, NULL, TESTFILE, NULL, DB_BTREE, DB_CREATE, 0666) == 0); 230 231 if (update) { 232 (void)dbenv->memp_stat(dbenv, &gsp, NULL, DB_STAT_CLEAR); 233 234 TIMER_START; 235 for (; ops > 0; --ops) 236 DB_BENCH_ASSERT( 237 dbp->put(dbp, NULL, &key, &data, 0) == 0); 238 TIMER_STOP; 239 240 if (dbenv->memp_stat(dbenv, &gsp, NULL, 0) == 0) 241 DB_BENCH_ASSERT(gsp->st_page_out == 0); 242 } else { 243 DB_BENCH_ASSERT(dbp->put(dbp, NULL, &key, &data, 0) == 0); 244 (void)dbenv->memp_stat(dbenv, &gsp, NULL, DB_STAT_CLEAR); 245 246 TIMER_START; 247 for (; ops > 0; --ops) { 248 DB_BENCH_ASSERT( 249 dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0); 250 DB_BENCH_ASSERT( 251 dbp->get(dbp, NULL, &key, &data, 0) == 0); 252 DB_BENCH_ASSERT(txn->commit(txn, 0) == 0); 253 } 254 TIMER_STOP; 255 256 if (dbenv->memp_stat(dbenv, &gsp, NULL, 0) == 0) 257 DB_BENCH_ASSERT(gsp->st_cache_miss == 0); 258 } 259 260 DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0); 261 DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); 262} 263 264#define DEFAULT_OPS 1000000 265 266int 267b_inmem(int argc, char *argv[]) 268{ 269 extern char *optarg; 270 extern int optind, __db_getopt_reset; 271 u_int ops, total; 272 int ch; 273 274 if ((progname = strrchr(argv[0], '/')) == NULL) 275 progname = argv[0]; 276 else 277 ++progname; 278 279 ops = 0; 280 __db_getopt_reset = 1; 281 while ((ch = getopt(argc, argv, "b:C:d:k:l:o:P:")) != EOF) 282 switch (ch) { 283 case 'b': 284 bulkbufsize = (u_int32_t)atoi(optarg); 285 break; 286 case 'C': 287 cachesize = (u_int32_t)atoi(optarg); 288 break; 289 case 'd': 290 datasize = (u_int)atoi(optarg); 291 break; 292 case 'k': 293 keysize = (u_int)atoi(optarg); 294 break; 295 case 'l': 296 logbufsize = (u_int32_t)atoi(optarg); 297 break; 298 case 'o': 299 ops = (u_int)atoi(optarg); 300 break; 301 case 'P': 302 pagesize = (u_int32_t)atoi(optarg); 303 break; 304 case '?': 305 default: 306 return (b_inmem_usage()); 307 } 308 argc -= optind; 309 argv += optind; 310 311 if (argc != 1) 312 return (b_inmem_usage()); 313 314 numitems = (cachesize / (keysize + datasize - 1)) / 2; 315 316 if (strcasecmp(argv[0], "read") == 0) { 317 if (ops == 0) 318 ops = DEFAULT_OPS; 319 b_inmem_op_ds(ops, 0); 320 printf( 321 "# %u in-memory Btree database reads of %u/%u byte key/data pairs\n", 322 ops, keysize, datasize); 323 } else if (strcasecmp(argv[0], "bulk") == 0) { 324 if (keysize < 8) { 325 fprintf(stderr, 326 "%s: bulk read requires a key size >= 10\n", progname); 327 return (EXIT_FAILURE); 328 } 329 /* 330 * The ops value is the number of bulk operations, not key get 331 * operations. Reduce the value so the test doesn't take so 332 * long, and use the returned number of retrievals as the ops 333 * value for timing purposes. 334 */ 335 if (ops == 0) 336 ops = 100000; 337 b_inmem_op_ds_bulk(ops, &total); 338 ops = total; 339 printf( 340 "# %u bulk in-memory Btree database reads of %u/%u byte key/data pairs\n", 341 ops, keysize, datasize); 342 } else if (strcasecmp(argv[0], "write") == 0) { 343 if (ops == 0) 344 ops = DEFAULT_OPS; 345 b_inmem_op_ds(ops, 1); 346 printf( 347 "# %u in-memory Btree database writes of %u/%u byte key/data pairs\n", 348 ops, keysize, datasize); 349 } else if (strcasecmp(argv[0], "txn-read") == 0) { 350 if (ops == 0) 351 ops = DEFAULT_OPS; 352 b_inmem_op_tds(ops, 0, 0, 0); 353 printf( 354 "# %u transactional in-memory Btree database reads of %u/%u %s", 355 ops, keysize, datasize, "byte key/data pairs\n"); 356 } else if (strcasecmp(argv[0], "txn-write") == 0) { 357 if (ops == 0) 358 ops = DEFAULT_OPS; 359#if defined(DB_LOG_INMEMORY) || defined(DB_LOG_IN_MEMORY) 360#if defined(DB_LOG_INMEMORY) 361 b_inmem_op_tds(ops, 1, 0, DB_LOG_INMEMORY); 362#else 363 b_inmem_op_tds(ops, 1, 0, DB_LOG_IN_MEMORY); 364#endif 365 printf( 366 "# %u transactional in-memory logging Btree database writes of %u/%u%s", 367 ops, keysize, datasize, " byte key/data pairs\n"); 368#else 369 return (EXIT_SUCCESS); 370#endif 371 } else if (strcasecmp(argv[0], "txn-nosync") == 0) { 372 if (ops == 0) 373 ops = DEFAULT_OPS; 374 b_inmem_op_tds(ops, 1, DB_TXN_NOSYNC, 0); 375 printf( 376 "# %u transactional nosync logging Btree database writes of %u/%u %s", 377 ops, keysize, datasize, "byte key/data pairs\n"); 378 } else if (strcasecmp(argv[0], "txn-write-nosync") == 0) { 379 if (ops == 0) 380 ops = DEFAULT_OPS; 381#ifdef DB_TXN_WRITE_NOSYNC 382 b_inmem_op_tds(ops, 1, DB_TXN_WRITE_NOSYNC, 0); 383 printf( 384 "# %u transactional OS-write/nosync logging Btree database writes of %u/%u%s", 385 ops, keysize, datasize, " byte key/data pairs\n"); 386#else 387 return (EXIT_SUCCESS); 388#endif 389 } else if (strcasecmp(argv[0], "txn-sync") == 0) { 390 /* 391 * Flushing to disk takes a long time, reduce the number of 392 * default ops. 393 */ 394 if (ops == 0) 395 ops = 100000; 396 b_inmem_op_tds(ops, 1, 0, 0); 397 printf( 398 "# %u transactional logging Btree database writes of %u/%u %s", 399 ops, keysize, datasize, "byte key/data pairs\n"); 400 } else { 401 fprintf(stderr, "%s: unknown keyword %s\n", progname, argv[0]); 402 return (EXIT_FAILURE); 403 } 404 405 TIMER_DISPLAY(ops); 406 return (EXIT_SUCCESS); 407} 408 409static int 410b_inmem_usage() 411{ 412 fprintf(stderr, "usage: %s %s%s%s%s", 413 progname, "[-b bulkbufsz] [-C cachesz]\n\t", 414 "[-d datasize] [-k keysize] [-l logbufsz] [-o ops] [-P pagesz]\n\t", 415 "[read | bulk | write | txn-read |\n\t", 416 "txn-write | txn-nosync | txn-write-nosync | txn-sync]\n"); 417 return (EXIT_FAILURE); 418} 419#else 420int 421b_inmem(int argc, char *argv[]) 422{ 423 COMPQUIET(argc, 0); 424 COMPQUIET(argv, NULL); 425 return (0); 426} 427#endif 428