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