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 op_ds __P((u_int, int)); 26static void op_ds_bulk __P((u_int, u_int *)); 27static void op_tds __P((u_int, int, u_int32_t, u_int32_t)); 28static int usage __P((void)); 29 30static void 31op_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 87op_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 169op_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; 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 while ((ch = getopt(argc, argv, "b:C:d:k:l:o:P:")) != EOF) 278 switch (ch) { 279 case 'b': 280 bulkbufsize = (u_int32_t)atoi(optarg); 281 break; 282 case 'C': 283 cachesize = (u_int32_t)atoi(optarg); 284 break; 285 case 'd': 286 datasize = (u_int)atoi(optarg); 287 break; 288 case 'k': 289 keysize = (u_int)atoi(optarg); 290 break; 291 case 'l': 292 logbufsize = (u_int32_t)atoi(optarg); 293 break; 294 case 'o': 295 ops = (u_int)atoi(optarg); 296 break; 297 case 'P': 298 pagesize = (u_int32_t)atoi(optarg); 299 break; 300 case '?': 301 default: 302 return (usage()); 303 } 304 argc -= optind; 305 argv += optind; 306 307 if (argc != 1) 308 return (usage()); 309 310 numitems = (cachesize / (keysize + datasize - 1)) / 2; 311 312 if (strcasecmp(argv[0], "read") == 0) { 313 if (ops == 0) 314 ops = DEFAULT_OPS; 315 op_ds(ops, 0); 316 printf( 317 "# %u in-memory Btree database reads of %u/%u byte key/data pairs\n", 318 ops, keysize, datasize); 319 } else if (strcasecmp(argv[0], "bulk") == 0) { 320 if (keysize < 8) { 321 fprintf(stderr, 322 "%s: bulk read requires a key size >= 10\n", progname); 323 return (EXIT_FAILURE); 324 } 325 /* 326 * The ops value is the number of bulk operations, not key get 327 * operations. Reduce the value so the test doesn't take so 328 * long, and use the returned number of retrievals as the ops 329 * value for timing purposes. 330 */ 331 if (ops == 0) 332 ops = 100000; 333 op_ds_bulk(ops, &total); 334 ops = total; 335 printf( 336 "# %u bulk in-memory Btree database reads of %u/%u byte key/data pairs\n", 337 ops, keysize, datasize); 338 } else if (strcasecmp(argv[0], "write") == 0) { 339 if (ops == 0) 340 ops = DEFAULT_OPS; 341 op_ds(ops, 1); 342 printf( 343 "# %u in-memory Btree database writes of %u/%u byte key/data pairs\n", 344 ops, keysize, datasize); 345 } else if (strcasecmp(argv[0], "txn-read") == 0) { 346 if (ops == 0) 347 ops = DEFAULT_OPS; 348 op_tds(ops, 0, 0, 0); 349 printf( 350 "# %u transactional in-memory Btree database reads of %u/%u byte key/data pairs\n", 351 ops, keysize, datasize); 352 } else if (strcasecmp(argv[0], "txn-write") == 0) { 353 if (ops == 0) 354 ops = DEFAULT_OPS; 355#if defined(DB_LOG_INMEMORY) || defined(DB_LOG_IN_MEMORY) 356#if defined(DB_LOG_INMEMORY) 357 op_tds(ops, 1, 0, DB_LOG_INMEMORY); 358#else 359 op_tds(ops, 1, 0, DB_LOG_IN_MEMORY); 360#endif 361 printf( 362 "# %u transactional in-memory logging Btree database writes of %u/%u byte key/data pairs\n", 363 ops, keysize, datasize); 364#else 365 return (EXIT_SUCCESS); 366#endif 367 } else if (strcasecmp(argv[0], "txn-nosync") == 0) { 368 if (ops == 0) 369 ops = DEFAULT_OPS; 370 op_tds(ops, 1, DB_TXN_NOSYNC, 0); 371 printf( 372 "# %u transactional nosync logging Btree database writes of %u/%u byte key/data pairs\n", 373 ops, keysize, datasize); 374 } else if (strcasecmp(argv[0], "txn-write-nosync") == 0) { 375 if (ops == 0) 376 ops = DEFAULT_OPS; 377#ifdef DB_TXN_WRITE_NOSYNC 378 op_tds(ops, 1, DB_TXN_WRITE_NOSYNC, 0); 379 printf( 380 "# %u transactional OS-write/nosync logging Btree database writes of %u/%u byte key/data pairs\n", 381 ops, keysize, datasize); 382#else 383 return (EXIT_SUCCESS); 384#endif 385 } else if (strcasecmp(argv[0], "txn-sync") == 0) { 386 /* 387 * Flushing to disk takes a long time, reduce the number of 388 * default ops. 389 */ 390 if (ops == 0) 391 ops = 100000; 392 op_tds(ops, 1, 0, 0); 393 printf( 394 "# %u transactional logging Btree database writes of %u/%u byte key/data pairs\n", 395 ops, keysize, datasize); 396 } else { 397 fprintf(stderr, "%s: unknown keyword %s\n", progname, argv[0]); 398 return (EXIT_FAILURE); 399 } 400 401 TIMER_DISPLAY(ops); 402 return (EXIT_SUCCESS); 403} 404 405static int 406usage() 407{ 408 fprintf(stderr, "usage: %s %s%s%s%s", 409 progname, "[-b bulkbufsz] [-C cachesz]\n\t", 410 "[-d datasize] [-k keysize] [-l logbufsz] [-o ops] [-P pagesz]\n\t", 411 "[read | bulk | write | txn-read |\n\t", 412 "txn-write | txn-nosync | txn-write-nosync | txn-sync]\n"); 413 return (EXIT_FAILURE); 414} 415#else 416int 417b_inmem(int argc, char *argv[]) 418{ 419 COMPQUIET(argc, 0); 420 COMPQUIET(argv, NULL); 421 return (0); 422} 423#endif 424