diff options
Diffstat (limited to 'src/third_party/wiredtiger/bench/wtperf')
14 files changed, 541 insertions, 270 deletions
diff --git a/src/third_party/wiredtiger/bench/wtperf/Makefile.am b/src/third_party/wiredtiger/bench/wtperf/Makefile.am index 15f151d84b2..cc1f84b5406 100644 --- a/src/third_party/wiredtiger/bench/wtperf/Makefile.am +++ b/src/third_party/wiredtiger/bench/wtperf/Makefile.am @@ -5,7 +5,8 @@ LDADD = $(top_builddir)/libwiredtiger.la -lm noinst_PROGRAMS = wtperf wtperf_LDFLAGS = -static wtperf_SOURCES =\ - config.c misc.c track.c wtperf.c wtperf_truncate.c wtperf.h wtperf_opt.i + config.c idle_table_cycle.c misc.c track.c wtperf.c \ + wtperf.h wtperf_opt.i wtperf_throttle.c wtperf_truncate.c TESTS = smoke.sh AM_TESTS_ENVIRONMENT = rm -rf WT_TEST ; mkdir WT_TEST ; diff --git a/src/third_party/wiredtiger/bench/wtperf/config.c b/src/third_party/wiredtiger/bench/wtperf/config.c index 808e85eedae..d9a22f4708d 100644 --- a/src/third_party/wiredtiger/bench/wtperf/config.c +++ b/src/third_party/wiredtiger/bench/wtperf/config.c @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. @@ -55,29 +55,25 @@ int config_assign(CONFIG *dest, const CONFIG *src) { CONFIG_QUEUE_ENTRY *conf_line, *tmp_line; - size_t i, len; + size_t i; char *newstr, **pstr; config_free(dest); memcpy(dest, src, sizeof(CONFIG)); if (src->uris != NULL) { - dest->uris = calloc(src->table_count, sizeof(char *)); - if (dest->uris == NULL) - return (enomem(dest)); + dest->uris = dcalloc(src->table_count, sizeof(char *)); for (i = 0; i < src->table_count; i++) - dest->uris[i] = strdup(src->uris[i]); + dest->uris[i] = dstrdup(src->uris[i]); } dest->ckptthreads = NULL; dest->popthreads = NULL; dest->workers = NULL; if (src->base_uri != NULL) - dest->base_uri = strdup(src->base_uri); + dest->base_uri = dstrdup(src->base_uri); if (src->workload != NULL) { - dest->workload = calloc(WORKLOAD_MAX, sizeof(WORKLOAD)); - if (dest->workload == NULL) - return (enomem(dest)); + dest->workload = dcalloc(WORKLOAD_MAX, sizeof(WORKLOAD)); memcpy(dest->workload, src->workload, WORKLOAD_MAX * sizeof(WORKLOAD)); } @@ -88,10 +84,7 @@ config_assign(CONFIG *dest, const CONFIG *src) pstr = (char **) ((u_char *)dest + config_opts[i].offset); if (*pstr != NULL) { - len = strlen(*pstr) + 1; - if ((newstr = malloc(len)) == NULL) - return (enomem(src)); - strncpy(newstr, *pstr, len); + newstr = dstrdup(*pstr); *pstr = newstr; } } @@ -101,12 +94,8 @@ config_assign(CONFIG *dest, const CONFIG *src) /* Clone the config string information into the new cfg object */ TAILQ_FOREACH(conf_line, &src->config_head, c) { - len = strlen(conf_line->string); - if ((tmp_line = calloc(sizeof(CONFIG_QUEUE_ENTRY), 1)) == NULL) - return (enomem(src)); - if ((tmp_line->string = calloc(len + 1, 1)) == NULL) - return (enomem(src)); - strncpy(tmp_line->string, conf_line->string, len); + tmp_line = dcalloc(sizeof(CONFIG_QUEUE_ENTRY), 1); + tmp_line->string = dstrdup(conf_line->string); TAILQ_INSERT_TAIL(&dest->config_head, tmp_line, c); } return (0); @@ -212,8 +201,7 @@ config_threads(CONFIG *cfg, const char *config, size_t len) cfg->workers_cnt = 0; } /* Allocate the workload array. */ - if ((cfg->workload = calloc(WORKLOAD_MAX, sizeof(WORKLOAD))) == NULL) - return (enomem(cfg)); + cfg->workload = dcalloc(WORKLOAD_MAX, sizeof(WORKLOAD)); cfg->workload_cnt = 0; /* @@ -249,8 +237,7 @@ config_threads(CONFIG *cfg, const char *config, size_t len) continue; } if (STRING_MATCH("throttle", k.str, k.len)) { - if ((workp->throttle = v.val) < 0) - goto err; + workp->throttle = (uint64_t)v.val; continue; } if (STRING_MATCH("insert", k.str, k.len) || @@ -426,13 +413,10 @@ config_opt(CONFIG *cfg, WT_CONFIG_ITEM *k, WT_CONFIG_ITEM *v) strp = (char **)valueloc; newlen = v->len + 1; if (*strp == NULL) { - if ((newstr = calloc(newlen, sizeof(char))) == NULL) - return (enomem(cfg)); - strncpy(newstr, v->str, v->len); + newstr = dstrdup(v->str); } else { newlen += (strlen(*strp) + 1); - if ((newstr = calloc(newlen, sizeof(char))) == NULL) - return (enomem(cfg)); + newstr = dcalloc(newlen, sizeof(char)); snprintf(newstr, newlen, "%s,%*s", *strp, (int)v->len, v->str); /* Free the old value now we've copied it. */ @@ -457,10 +441,11 @@ config_opt(CONFIG *cfg, WT_CONFIG_ITEM *k, WT_CONFIG_ITEM *v) } strp = (char **)valueloc; free(*strp); - if ((newstr = malloc(v->len + 1)) == NULL) - return (enomem(cfg)); - strncpy(newstr, v->str, v->len); - newstr[v->len] = '\0'; + /* + * We duplicate the string to len rather than len+1 as we want + * to truncate the trailing quotation mark. + */ + newstr = dstrndup(v->str, v->len); *strp = newstr; break; } @@ -495,11 +480,7 @@ config_opt_file(CONFIG *cfg, const char *filename) goto err; } buf_size = (size_t)sb.st_size; - file_buf = calloc(buf_size + 2, 1); - if (file_buf == NULL) { - ret = ENOMEM; - goto err; - } + file_buf = dcalloc(buf_size + 2, 1); read_size = read(fd, file_buf, buf_size); if (read_size == -1 #ifndef _WIN32 @@ -595,7 +576,6 @@ config_opt_line(CONFIG *cfg, const char *optstr) WT_CONFIG_PARSER *scan; size_t len; int ret, t_ret; - char *string_copy; len = strlen(optstr); if ((ret = wiredtiger_config_parser_open( @@ -610,12 +590,8 @@ config_opt_line(CONFIG *cfg, const char *optstr) * any parsed from the original config. We allocate len + 1 to allow for * a null byte to be added. */ - if ((string_copy = calloc(len + 1, 1)) == NULL) - return (enomem(cfg)); - - strncpy(string_copy, optstr, len); - config_line = calloc(sizeof(CONFIG_QUEUE_ENTRY), 1); - config_line->string = string_copy; + config_line = dcalloc(sizeof(CONFIG_QUEUE_ENTRY), 1); + config_line->string = dstrdup(optstr); TAILQ_INSERT_TAIL(&cfg->config_head, config_line, c); while (ret == 0) { @@ -647,8 +623,7 @@ config_opt_str(CONFIG *cfg, const char *name, const char *value) char *optstr; /* name="value" */ - if ((optstr = malloc(strlen(name) + strlen(value) + 4)) == NULL) - return (enomem(cfg)); + optstr = dmalloc(strlen(name) + strlen(value) + 4); sprintf(optstr, "%s=\"%s\"", name, value); ret = config_opt_line(cfg, optstr); free(optstr); @@ -747,13 +722,9 @@ config_to_file(CONFIG *cfg) fp = NULL; /* Backup the config */ - req_len = strlen(cfg->home) + 100; - if ((path = calloc(req_len, 1)) == NULL) { - (void)enomem(cfg); - goto err; - } - - snprintf(path, req_len + 14, "%s/CONFIG.wtperf", cfg->home); + req_len = strlen(cfg->home) + strlen("/CONFIG.wtperf") + 1; + path = dcalloc(req_len, 1); + snprintf(path, req_len, "%s/CONFIG.wtperf", cfg->home); if ((fp = fopen(path, "w")) == NULL) { lprintf(cfg, errno, 0, "%s", path); goto err; diff --git a/src/third_party/wiredtiger/bench/wtperf/config_opt.h b/src/third_party/wiredtiger/bench/wtperf/config_opt.h index 0fb1d988c3a..b7eff8e143f 100644 --- a/src/third_party/wiredtiger/bench/wtperf/config_opt.h +++ b/src/third_party/wiredtiger/bench/wtperf/config_opt.h @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. diff --git a/src/third_party/wiredtiger/bench/wtperf/doxy.c b/src/third_party/wiredtiger/bench/wtperf/doxy.c index 2921caea76c..26d73168ef2 100644 --- a/src/third_party/wiredtiger/bench/wtperf/doxy.c +++ b/src/third_party/wiredtiger/bench/wtperf/doxy.c @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. diff --git a/src/third_party/wiredtiger/bench/wtperf/idle_table_cycle.c b/src/third_party/wiredtiger/bench/wtperf/idle_table_cycle.c new file mode 100644 index 00000000000..b699b5b9dd1 --- /dev/null +++ b/src/third_party/wiredtiger/bench/wtperf/idle_table_cycle.c @@ -0,0 +1,192 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "wtperf.h" + +static int +check_timing(CONFIG *cfg, + const char *name, struct timespec start, struct timespec *stop) +{ + uint64_t last_interval; + int ret; + + if ((ret = __wt_epoch(NULL, stop)) != 0) { + lprintf(cfg, ret, 0, + "Get time failed in cycle_idle_tables."); + cfg->error = ret; + return (ret); + } + + last_interval = (uint64_t)(WT_TIMEDIFF_SEC(*stop, start)); + + if (last_interval > cfg->idle_table_cycle) { + lprintf(cfg, ret, 0, + "Cycling idle table failed because %s took %" PRIu64 + " seconds which is longer than configured acceptable" + " maximum of %" PRIu32 ".", + name, last_interval, cfg->idle_table_cycle); + cfg->error = ETIMEDOUT; + return (ETIMEDOUT); + } + return (0); +} +/* + * Regularly create, open a cursor and drop a table. + * Measure how long each step takes, and flag an error if it exceeds the + * configured maximum. + */ +static void * +cycle_idle_tables(void *arg) +{ + struct timespec start, stop; + CONFIG *cfg; + WT_SESSION *session; + WT_CURSOR *cursor; + int cycle_count, ret; + char uri[512]; + + cfg = (CONFIG *)arg; + cycle_count = 0; + + if ((ret = cfg->conn->open_session( + cfg->conn, NULL, cfg->sess_config, &session)) != 0) { + lprintf(cfg, ret, 0, + "Error opening a session on %s", cfg->home); + return (NULL); + } + + for (cycle_count = 0; cfg->idle_cycle_run; ++cycle_count) { + snprintf(uri, 512, "%s_cycle%07d", cfg->uris[0], cycle_count); + /* Don't busy cycle in this loop. */ + __wt_sleep(1, 0); + + /* Setup a start timer. */ + if ((ret = __wt_epoch(NULL, &start)) != 0) { + lprintf(cfg, ret, 0, + "Get time failed in cycle_idle_tables."); + cfg->error = ret; + return (NULL); + } + + /* Create a table. */ + if ((ret = session->create( + session, uri, cfg->table_config)) != 0) { + if (ret == EBUSY) + continue; + lprintf(cfg, ret, 0, + "Table create failed in cycle_idle_tables."); + cfg->error = ret; + return (NULL); + } + if (check_timing(cfg, "create", start, &stop) != 0) + return (NULL); + start = stop; + + /* Open and close cursor. */ + if ((ret = session->open_cursor( + session, uri, NULL, NULL, &cursor)) != 0) { + lprintf(cfg, ret, 0, + "Cursor open failed in cycle_idle_tables."); + cfg->error = ret; + return (NULL); + } + if ((ret = cursor->close(cursor)) != 0) { + lprintf(cfg, ret, 0, + "Cursor close failed in cycle_idle_tables."); + cfg->error = ret; + return (NULL); + } + if (check_timing(cfg, "cursor", start, &stop) != 0) + return (NULL); + start = stop; + + /* + * Drop the table. Keep retrying on EBUSY failure - it is an + * expected return when checkpoints are happening. + */ + while ((ret = session->drop(session, uri, "force")) == EBUSY) + __wt_sleep(1, 0); + + if (ret != 0 && ret != EBUSY) { + lprintf(cfg, ret, 0, + "Table drop failed in cycle_idle_tables."); + cfg->error = ret; + return (NULL); + } + if (check_timing(cfg, "drop", start, &stop) != 0) + return (NULL); + } + + return (NULL); +} + +/* + * Start a thread the creates and drops tables regularly. + * TODO: Currently accepts a pthread_t as a parameter, since it is not + * possible to portably statically initialize it in the global configuration + * structure. Should reshuffle the configuration structure so explicit static + * initialization isn't necessary. + */ +int +start_idle_table_cycle(CONFIG *cfg, pthread_t *idle_table_cycle_thread) +{ + pthread_t thread_id; + int ret; + + if (cfg->idle_table_cycle == 0) + return (0); + + cfg->idle_cycle_run = true; + if ((ret = pthread_create( + &thread_id, NULL, cycle_idle_tables, cfg)) != 0) { + lprintf( + cfg, ret, 0, "Error creating idle table cycle thread."); + cfg->idle_cycle_run = false; + return (ret); + } + *idle_table_cycle_thread = thread_id; + + return (0); +} + +int +stop_idle_table_cycle(CONFIG *cfg, pthread_t idle_table_cycle_thread) +{ + int ret; + + if (cfg->idle_table_cycle == 0 || !cfg->idle_cycle_run) + return (0); + + cfg->idle_cycle_run = false; + if ((ret = pthread_join(idle_table_cycle_thread, NULL)) != 0) { + lprintf( + cfg, ret, 0, "Error joining idle table cycle thread."); + return (ret); + } + return (0); +} diff --git a/src/third_party/wiredtiger/bench/wtperf/misc.c b/src/third_party/wiredtiger/bench/wtperf/misc.c index 1e47c76214c..bdfd53d5295 100644 --- a/src/third_party/wiredtiger/bench/wtperf/misc.c +++ b/src/third_party/wiredtiger/bench/wtperf/misc.c @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. @@ -28,19 +28,6 @@ #include "wtperf.h" -int -enomem(const CONFIG *cfg) -{ - const char *msg; - - msg = "Unable to allocate memory"; - if (cfg->logf == NULL) - fprintf(stderr, "%s\n", msg); - else - lprintf(cfg, ENOMEM, 0, "%s", msg); - return (ENOMEM); -} - /* Setup the logging output mechanism. */ int setup_log_file(CONFIG *cfg) @@ -53,9 +40,8 @@ setup_log_file(CONFIG *cfg) if (cfg->verbose < 1) return (0); - if ((fname = calloc(strlen(cfg->monitor_dir) + - strlen(cfg->table_name) + strlen(".stat") + 2, 1)) == NULL) - return (enomem(cfg)); + fname = dcalloc(strlen(cfg->monitor_dir) + + strlen(cfg->table_name) + strlen(".stat") + 2, 1); sprintf(fname, "%s/%s.stat", cfg->monitor_dir, cfg->table_name); cfg->logf = fopen(fname, "w"); diff --git a/src/third_party/wiredtiger/bench/wtperf/runners/checkpoint_stress_schema_ops.wtperf b/src/third_party/wiredtiger/bench/wtperf/runners/checkpoint_stress_schema_ops.wtperf new file mode 100644 index 00000000000..b69ead7f8b1 --- /dev/null +++ b/src/third_party/wiredtiger/bench/wtperf/runners/checkpoint_stress_schema_ops.wtperf @@ -0,0 +1,19 @@ +# A stress configuration, to create long running checkpoints and see how +# they interfere with schema level operations (table create, drop). +# Setup a cache size large enough that checkpoints can take a long time. +conn_config="cache_size=8GB,log=(enabled=false),checkpoint=(wait=30)" +table_config="leaf_page_max=4k,internal_page_max=16k,type=file" +icount=10000000 +table_count_idle=100 +# Turn on create/drop of idle tables, and error if a single operation takes +# more than 5 seconds. +idle_table_cycle=5 +populate_threads=5 +checkpoint_threads=0 +report_interval=5 +# 100 million +random_range=100000000 +run_time=1000 +# Setup a workload that dirties a lot of the cache +threads=((count=2,reads=1),(count=2,inserts=1),(count=2,updates=1)) +value_sz=500 diff --git a/src/third_party/wiredtiger/bench/wtperf/runners/get_ckpt.py b/src/third_party/wiredtiger/bench/wtperf/runners/get_ckpt.py index 95354ece190..03bbda7dab1 100755 --- a/src/third_party/wiredtiger/bench/wtperf/runners/get_ckpt.py +++ b/src/third_party/wiredtiger/bench/wtperf/runners/get_ckpt.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Public Domain 2014-2015 MongoDB, Inc. +# Public Domain 2014-2016 MongoDB, Inc. # Public Domain 2008-2014 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. diff --git a/src/third_party/wiredtiger/bench/wtperf/track.c b/src/third_party/wiredtiger/bench/wtperf/track.c index 75f5a012a94..b3f4847d9d0 100644 --- a/src/third_party/wiredtiger/bench/wtperf/track.c +++ b/src/third_party/wiredtiger/bench/wtperf/track.c @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. diff --git a/src/third_party/wiredtiger/bench/wtperf/wtperf.c b/src/third_party/wiredtiger/bench/wtperf/wtperf.c index 5386096d9b7..b2e68198e9a 100644 --- a/src/third_party/wiredtiger/bench/wtperf/wtperf.c +++ b/src/third_party/wiredtiger/bench/wtperf/wtperf.c @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. @@ -57,6 +57,7 @@ static const CONFIG default_cfg = { 0, /* thread error */ 0, /* notify threads to stop */ 0, /* in warmup phase */ + false, /* Signal for idle cycle thread */ 0, /* total seconds running */ 0, /* has truncate */ {NULL, NULL}, /* the truncate queue */ @@ -72,7 +73,6 @@ static const char * const debug_tconfig = ""; static void *checkpoint_worker(void *); static int create_tables(CONFIG *); -static int create_uris(CONFIG *); static int drop_all_tables(CONFIG *); static int execute_populate(CONFIG *); static int execute_workload(CONFIG *); @@ -87,7 +87,7 @@ static int start_threads(CONFIG *, static int stop_threads(CONFIG *, u_int, CONFIG_THREAD *); static void *thread_run_wtperf(void *); static void *worker(void *); -static void worker_throttle(int64_t, int64_t *, struct timespec *); + static uint64_t wtperf_rand(CONFIG_THREAD *); static uint64_t wtperf_value_range(CONFIG *); @@ -422,7 +422,7 @@ do_range_reads(CONFIG *cfg, WT_CURSOR *cursor) static void * worker(void *arg) { - struct timespec start, stop, interval; + struct timespec start, stop; CONFIG *cfg; CONFIG_THREAD *thread; TRACK *trk; @@ -430,7 +430,7 @@ worker(void *arg) WT_CURSOR **cursors, *cursor, *tmp_cursor; WT_SESSION *session; size_t i; - int64_t ops, ops_per_txn, throttle_ops; + int64_t ops, ops_per_txn; uint64_t next_val, usecs; uint8_t *op, *op_end; int measure_latency, ret, truncated; @@ -445,19 +445,13 @@ worker(void *arg) ops_per_txn = thread->workload->ops_per_txn; session = NULL; trk = NULL; - throttle_ops = 0; if ((ret = conn->open_session( conn, NULL, cfg->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "worker: WT_CONNECTION.open_session"); goto err; } - cursors = calloc(cfg->table_count, sizeof(WT_CURSOR *)); - if (cursors == NULL) { - lprintf(cfg, ENOMEM, 0, - "worker: couldn't allocate cursor array"); - goto err; - } + cursors = dcalloc(cfg->table_count, sizeof(WT_CURSOR *)); for (i = 0; i < cfg->table_count_idle; i++) { snprintf(buf, 512, "%s_idle%05d", cfg->uris[0], (int)i); if ((ret = session->open_cursor( @@ -483,10 +477,8 @@ worker(void *arg) } /* Setup the timer for throttling. */ if (thread->workload->throttle != 0 && - (ret = __wt_epoch(NULL, &interval)) != 0) { - lprintf(cfg, ret, 0, "Get time call failed"); + (ret = setup_throttle(thread)) != 0) goto err; - } /* Setup for truncate */ if (thread->workload->truncate != 0) @@ -736,13 +728,11 @@ op_err: if (ret == WT_ROLLBACK && ops_per_txn != 0) { op = thread->workload->ops; /* - * Check throttling periodically to avoid taking too - * many time samples. + * Decrement throttle ops and check if we should sleep + * and then get more work to perform. */ - if (thread->workload->throttle != 0 && - throttle_ops++ % THROTTLE_OPS == 0) - worker_throttle(thread->workload->throttle, - &throttle_ops, &interval); + if (--thread->throttle_cfg.ops_count == 0) + worker_throttle(thread); } if ((ret = session->close(session, NULL)) != 0) { @@ -917,12 +907,7 @@ populate_thread(void *arg) cursor_config = (cfg->populate_threads == 1 && !cfg->index) ? "bulk" : NULL; /* Create the cursors. */ - cursors = calloc(cfg->table_count, sizeof(WT_CURSOR *)); - if (cursors == NULL) { - lprintf(cfg, ENOMEM, 0, - "worker: couldn't allocate cursor array"); - goto err; - } + cursors = dcalloc(cfg->table_count, sizeof(WT_CURSOR *)); for (i = 0; i < cfg->table_count; i++) { if ((ret = session->open_cursor( session, cfg->uris[i], NULL, @@ -1168,10 +1153,7 @@ monitor(void *arg) /* Open the logging file. */ len = strlen(cfg->monitor_dir) + 100; - if ((path = malloc(len)) == NULL) { - (void)enomem(cfg); - goto err; - } + path = dmalloc(len); snprintf(path, len, "%s/monitor", cfg->monitor_dir); if ((fp = fopen(path, "w")) == NULL) { lprintf(cfg, errno, 0, "%s", path); @@ -1378,6 +1360,7 @@ execute_populate(CONFIG *cfg) struct timespec start, stop; CONFIG_THREAD *popth; WT_ASYNC_OP *asyncop; + pthread_t idle_table_cycle_thread; size_t i; uint64_t last_ops, msecs, print_ops_sec; uint32_t interval, tables; @@ -1390,11 +1373,13 @@ execute_populate(CONFIG *cfg) " populate thread(s) for %" PRIu32 " items", cfg->populate_threads, cfg->icount); + /* Start cycling idle tables if configured. */ + if ((ret = start_idle_table_cycle(cfg, &idle_table_cycle_thread)) != 0) + return (ret); + cfg->insert_key = 0; - if ((cfg->popthreads = - calloc(cfg->populate_threads, sizeof(CONFIG_THREAD))) == NULL) - return (enomem(cfg)); + cfg->popthreads = dcalloc(cfg->populate_threads, sizeof(CONFIG_THREAD)); if (cfg->use_asyncops > 0) { lprintf(cfg, 0, 1, "Starting %" PRIu32 " async thread(s)", cfg->async_threads); @@ -1519,6 +1504,11 @@ execute_populate(CONFIG *cfg) (uint64_t)(WT_TIMEDIFF_SEC(stop, start))); assert(tables == 0); } + + /* Stop cycling idle tables. */ + if ((ret = stop_idle_table_cycle(cfg, idle_table_cycle_thread)) != 0) + return (ret); + return (0); } @@ -1568,6 +1558,7 @@ execute_workload(CONFIG *cfg) { CONFIG_THREAD *threads; WORKLOAD *workp; + pthread_t idle_table_cycle_thread; uint64_t last_ckpts, last_inserts, last_reads, last_truncates; uint64_t last_updates; uint32_t interval, run_ops, run_time; @@ -1583,15 +1574,15 @@ execute_workload(CONFIG *cfg) last_updates = 0; ret = 0; + /* Start cycling idle tables. */ + if ((ret = start_idle_table_cycle(cfg, &idle_table_cycle_thread)) != 0) + return (ret); + if (cfg->warmup != 0) cfg->in_warmup = 1; /* Allocate memory for the worker threads. */ - if ((cfg->workers = - calloc((size_t)cfg->workers_cnt, sizeof(CONFIG_THREAD))) == NULL) { - ret = enomem(cfg); - goto err; - } + cfg->workers = dcalloc((size_t)cfg->workers_cnt, sizeof(CONFIG_THREAD)); if (cfg->use_asyncops > 0) { lprintf(cfg, 0, 1, "Starting %" PRIu32 " async thread(s)", @@ -1682,6 +1673,10 @@ execute_workload(CONFIG *cfg) /* Notify the worker threads they are done. */ err: cfg->stop = 1; + /* Stop cycling idle tables. */ + if ((ret = stop_idle_table_cycle(cfg, idle_table_cycle_thread)) != 0) + return (ret); + if ((t_ret = stop_threads( cfg, (u_int)cfg->workers_cnt, cfg->workers)) != 0 && ret == 0) ret = t_ret; @@ -1763,27 +1758,17 @@ out: return (ret); /* * Populate the uri array if more than one table is being used. */ -static int +static void create_uris(CONFIG *cfg) { size_t base_uri_len; uint32_t i; - int ret; char *uri; - ret = 0; base_uri_len = strlen(cfg->base_uri); - cfg->uris = calloc(cfg->table_count, sizeof(char *)); - if (cfg->uris == NULL) { - ret = ENOMEM; - goto err; - } + cfg->uris = dcalloc(cfg->table_count, sizeof(char *)); for (i = 0; i < cfg->table_count; i++) { - uri = cfg->uris[i] = calloc(base_uri_len + 5, 1); - if (uri == NULL) { - ret = ENOMEM; - goto err; - } + uri = cfg->uris[i] = dcalloc(base_uri_len + 5, 1); /* * If there is only one table, just use base name. */ @@ -1792,13 +1777,6 @@ create_uris(CONFIG *cfg) else sprintf(uri, "%s%05d", cfg->base_uri, i); } -err: if (ret != 0 && cfg->uris != NULL) { - for (i = 0; i < cfg->table_count; i++) - free(cfg->uris[i]); - free(cfg->uris); - cfg->uris = NULL; - } - return (ret); } static int @@ -1880,40 +1858,22 @@ start_all_runs(CONFIG *cfg) return (start_run(cfg)); /* Allocate an array to hold our config struct copies. */ - configs = calloc(cfg->database_count, sizeof(CONFIG *)); - if (configs == NULL) - return (ENOMEM); + configs = dcalloc(cfg->database_count, sizeof(CONFIG *)); /* Allocate an array to hold our thread IDs. */ - threads = calloc(cfg->database_count, sizeof(pthread_t)); - if (threads == NULL) { - ret = ENOMEM; - goto err; - } + threads = dcalloc(cfg->database_count, sizeof(pthread_t)); home_len = strlen(cfg->home); cmd_len = (home_len * 2) + 30; /* Add some slop. */ - cmd_buf = calloc(cmd_len, 1); - if (cmd_buf == NULL) { - ret = ENOMEM; - goto err; - } + cmd_buf = dcalloc(cmd_len, 1); for (i = 0; i < cfg->database_count; i++) { - next_cfg = calloc(1, sizeof(CONFIG)); - if (next_cfg == NULL) { - ret = ENOMEM; - goto err; - } + next_cfg = dcalloc(1, sizeof(CONFIG)); configs[i] = next_cfg; if ((ret = config_assign(next_cfg, cfg)) != 0) goto err; /* Setup a unique home directory for each database. */ - new_home = malloc(home_len + 5); - if (new_home == NULL) { - ret = ENOMEM; - goto err; - } + new_home = dmalloc(home_len + 5); snprintf(new_home, home_len + 5, "%s/D%02d", cfg->home, (int)i); next_cfg->home = new_home; @@ -2003,8 +1963,7 @@ start_run(CONFIG *cfg) ret, 0, "Error loading Helium: %s", helium_buf); } - if ((ret = create_uris(cfg)) != 0) - goto err; + create_uris(cfg); if ((ret = create_tables(cfg)) != 0) goto err; @@ -2041,12 +2000,8 @@ start_run(CONFIG *cfg) lprintf(cfg, 0, 1, "Starting %" PRIu32 " checkpoint thread(s)", cfg->checkpoint_threads); - if ((cfg->ckptthreads = - calloc(cfg->checkpoint_threads, - sizeof(CONFIG_THREAD))) == NULL) { - ret = enomem(cfg); - goto err; - } + cfg->ckptthreads = dcalloc( + cfg->checkpoint_threads, sizeof(CONFIG_THREAD)); if (start_threads(cfg, NULL, cfg->ckptthreads, cfg->checkpoint_threads, checkpoint_worker) != 0) goto err; @@ -2165,9 +2120,9 @@ main(int argc, char *argv[]) switch (ch) { case 'C': if (user_cconfig == NULL) - user_cconfig = strdup(__wt_optarg); + user_cconfig = dstrdup(__wt_optarg); else { - user_cconfig = realloc(user_cconfig, + user_cconfig = drealloc(user_cconfig, strlen(user_cconfig) + strlen(__wt_optarg) + 2); strcat(user_cconfig, ","); @@ -2182,9 +2137,9 @@ main(int argc, char *argv[]) break; case 'T': if (user_tconfig == NULL) - user_tconfig = strdup(__wt_optarg); + user_tconfig = dstrdup(__wt_optarg); else { - user_tconfig = realloc(user_tconfig, + user_tconfig = drealloc(user_tconfig, strlen(user_tconfig) + strlen(__wt_optarg) + 2); strcat(user_tconfig, ","); @@ -2255,10 +2210,7 @@ main(int argc, char *argv[]) * to 4096 if needed. */ req_len = strlen(",async=(enabled=true,threads=)") + 4; - if ((cfg->async_config = calloc(req_len, 1)) == NULL) { - ret = enomem(cfg); - goto err; - } + cfg->async_config = dcalloc(req_len, 1); snprintf(cfg->async_config, req_len, ",async=(enabled=true,threads=%d)", cfg->async_threads); @@ -2281,10 +2233,7 @@ main(int argc, char *argv[]) /* Build the URI from the table name. */ req_len = strlen("table:") + strlen(HELIUM_NAME) + strlen(cfg->table_name) + 2; - if ((cfg->base_uri = calloc(req_len, 1)) == NULL) { - ret = enomem(cfg); - goto err; - } + cfg->base_uri = dcalloc(req_len, 1); snprintf(cfg->base_uri, req_len, "table:%s%s%s", cfg->helium_mount == NULL ? "" : HELIUM_NAME, cfg->helium_mount == NULL ? "" : "/", @@ -2303,10 +2252,7 @@ main(int argc, char *argv[]) req_len += strlen(cfg->async_config); if (cfg->compress_ext != NULL) req_len += strlen(cfg->compress_ext); - if ((cc_buf = calloc(req_len, 1)) == NULL) { - ret = enomem(cfg); - goto err; - } + cc_buf = dcalloc(req_len, 1); /* * This is getting hard to parse. */ @@ -2331,10 +2277,7 @@ main(int argc, char *argv[]) req_len += strlen(cfg->compress_table); if (cfg->index) req_len += strlen(INDEX_COL_NAMES); - if ((tc_buf = calloc(req_len, 1)) == NULL) { - ret = enomem(cfg); - goto err; - } + tc_buf = dcalloc(req_len, 1); /* * This is getting hard to parse. */ @@ -2353,10 +2296,7 @@ main(int argc, char *argv[]) if (cfg->log_partial && cfg->table_count > 1) { req_len = strlen(cfg->table_config) + strlen(LOG_PARTIAL_CONFIG) + 1; - if ((cfg->partial_config = calloc(req_len, 1)) == NULL) { - ret = enomem(cfg); - goto err; - } + cfg->partial_config = dcalloc(req_len, 1); snprintf((char *)cfg->partial_config, req_len, "%s%s", (char *)cfg->table_config, LOG_PARTIAL_CONFIG); } @@ -2416,10 +2356,8 @@ start_threads(CONFIG *cfg, * don't, it's not enough memory to bother. These buffers hold * strings: trailing NUL is included in the size. */ - if ((thread->key_buf = calloc(cfg->key_sz, 1)) == NULL) - return (enomem(cfg)); - if ((thread->value_buf = calloc(cfg->value_sz, 1)) == NULL) - return (enomem(cfg)); + thread->key_buf = dcalloc(cfg->key_sz, 1); + thread->value_buf = dcalloc(cfg->value_sz, 1); /* * Initialize and then toss in a bit of random values if needed. */ @@ -2479,40 +2417,6 @@ stop_threads(CONFIG *cfg, u_int num, CONFIG_THREAD *threads) return (0); } -/* - * TODO: Spread the stalls out, so we don't flood at the start of each - * second and then pause. Doing this every 10th of a second is probably enough - */ -static void -worker_throttle(int64_t throttle, int64_t *ops, struct timespec *interval) -{ - struct timespec now; - uint64_t usecs_to_complete; - if (*ops < throttle) - return; - - /* Ignore errors, we don't really care. */ - if (__wt_epoch(NULL, &now) != 0) - return; - - /* - * If we've completed enough operations, reset the counters. - * If we did enough operations in less than a second, sleep for - * the rest of the second. - */ - usecs_to_complete = WT_TIMEDIFF_US(now, *interval); - if (usecs_to_complete < USEC_PER_SEC) - (void)usleep((useconds_t)(USEC_PER_SEC - usecs_to_complete)); - - /* - * After sleeping, set the interval to the current time. - */ - if (__wt_epoch(NULL, &now) != 0) - return; - *ops = 0; - *interval = now; -} - static int drop_all_tables(CONFIG *cfg) { diff --git a/src/third_party/wiredtiger/bench/wtperf/wtperf.h b/src/third_party/wiredtiger/bench/wtperf/wtperf.h index 361b135ced7..7dbe1822a26 100644 --- a/src/third_party/wiredtiger/bench/wtperf/wtperf.h +++ b/src/third_party/wiredtiger/bench/wtperf/wtperf.h @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. @@ -66,6 +66,7 @@ typedef struct __config CONFIG; typedef struct __config_thread CONFIG_THREAD; +typedef struct __truncate_queue_entry TRUNCATE_QUEUE_ENTRY; #define EXT_PFX ",extensions=(" #define EXT_SFX ")" @@ -90,7 +91,7 @@ typedef struct { int64_t insert; /* Insert ratio */ int64_t read; /* Read ratio */ int64_t update; /* Update ratio */ - int64_t throttle; /* Maximum operations/second */ + uint64_t throttle; /* Maximum operations/second */ /* Number of operations per transaction. Zero for autocommit */ int64_t ops_per_txn; int64_t truncate; /* Truncate ratio */ @@ -106,8 +107,7 @@ typedef struct { } WORKLOAD; /* Steering items for the truncate workload */ -typedef struct __truncate_struct TRUNCATE_CONFIG; -struct __truncate_struct { +typedef struct { uint64_t stone_gap; uint64_t needed_stones; uint64_t final_stone_gap; @@ -117,7 +117,7 @@ struct __truncate_struct { uint64_t num_stones; uint64_t last_key; uint64_t catchup_multiplier; -}; +} TRUNCATE_CONFIG; /* Queue entry for use with the Truncate Logic */ struct __truncate_queue_entry { @@ -125,7 +125,6 @@ struct __truncate_queue_entry { uint64_t diff; /* Number of items to be truncated*/ TAILQ_ENTRY(__truncate_queue_entry) q; }; -typedef struct __truncate_queue_entry TRUNCATE_QUEUE_ENTRY; struct __config_queue_entry { char *string; @@ -133,6 +132,14 @@ struct __config_queue_entry { }; typedef struct __config_queue_entry CONFIG_QUEUE_ENTRY; +/* Steering for the throttle configuration */ +typedef struct { + struct timespec last_increment; /* Time that we last added more ops */ + uint64_t ops_count; /* The number of ops this increment */ + uint64_t ops_per_increment; /* Ops to add per increment */ + uint64_t usecs_increment; /* Time interval of each increment */ +} THROTTLE_CONFIG; + #define LOG_PARTIAL_CONFIG ",log=(enabled=false)" /* * NOTE: If you add any fields to this structure here, you must also add @@ -180,6 +187,8 @@ struct __config { /* Configuration structure */ volatile int stop; /* notify threads to stop */ volatile int in_warmup; /* Running warmup phase */ + volatile bool idle_cycle_run; /* Signal for idle cycle thread */ + volatile uint32_t totalsec; /* total seconds running */ u_int has_truncate; /* if there is a truncate workload */ @@ -264,14 +273,16 @@ struct __config_thread { /* Per-thread structure */ WORKLOAD *workload; /* Workload */ + THROTTLE_CONFIG throttle_cfg; /* Throttle configuration */ + + TRUNCATE_CONFIG trunc_cfg; /* Truncate configuration */ + TRACK ckpt; /* Checkpoint operations */ TRACK insert; /* Insert operations */ TRACK read; /* Read operations */ TRACK update; /* Update operations */ TRACK truncate; /* Truncate operations */ TRACK truncate_sleep; /* Truncate sleep operations */ - TRUNCATE_CONFIG trunc_cfg; /* Truncate configuration */ - }; void cleanup_truncate_config(CONFIG *); @@ -289,11 +300,13 @@ void latency_insert(CONFIG *, uint32_t *, uint32_t *, uint32_t *); void latency_read(CONFIG *, uint32_t *, uint32_t *, uint32_t *); void latency_update(CONFIG *, uint32_t *, uint32_t *, uint32_t *); void latency_print(CONFIG *); -int enomem(const CONFIG *); int run_truncate( CONFIG *, CONFIG_THREAD *, WT_CURSOR *, WT_SESSION *, int *); int setup_log_file(CONFIG *); +int setup_throttle(CONFIG_THREAD*); int setup_truncate(CONFIG *, CONFIG_THREAD *, WT_SESSION *); +int start_idle_table_cycle(CONFIG *, pthread_t *); +int stop_idle_table_cycle(CONFIG *, pthread_t); uint64_t sum_ckpt_ops(CONFIG *); uint64_t sum_insert_ops(CONFIG *); uint64_t sum_pop_ops(CONFIG *); @@ -301,6 +314,7 @@ uint64_t sum_read_ops(CONFIG *); uint64_t sum_truncate_ops(CONFIG *); uint64_t sum_update_ops(CONFIG *); void usage(void); +int worker_throttle(CONFIG_THREAD*); void lprintf(const CONFIG *, int err, uint32_t, const char *, ...) #if defined(__GNUC__) @@ -323,4 +337,85 @@ extract_key(char *key_buf, uint64_t *keynop) sscanf(key_buf, "%" SCNu64, keynop); } +/* + * die -- + * Print message and exit on failure. + */ +static inline void +die(int e, const char *str) +{ + fprintf(stderr, "Call to %s failed: %s", str, wiredtiger_strerror(e)); + exit(EXIT_FAILURE); +} + +/* + * dmalloc -- + * Call malloc, dying on failure. + */ +static inline void * +dmalloc(size_t len) +{ + void *p; + + if ((p = malloc(len)) == NULL) + die(errno, "malloc"); + return (p); +} + +/* + * dcalloc -- + * Call calloc, dying on failure. + */ +static inline void * +dcalloc(size_t num, size_t len) +{ + void *p; + + if ((p = calloc(len, num)) == NULL) + die(errno, "calloc"); + return (p); +} + +/* + * drealloc -- + * Call realloc, dying on failure. + */ +static inline void * +drealloc(void *p, size_t len) +{ + void *repl; + + if ((repl = realloc(p, len)) == NULL) + die(errno, "realloc"); + return (repl); +} + +/* + * dstrdup -- + * Call strdup, dying on failure. + */ +static inline char * +dstrdup(const char *str) +{ + char *p; + + if ((p = strdup(str)) == NULL) + die(errno, "strdup"); + return (p); +} + +/* + * dstrndup -- + * Call strndup, dying on failure. + */ +static inline char * +dstrndup(const char *str, const size_t len) +{ + char *p; + + if ((p = strndup(str, len)) == NULL) + die(errno, "strndup"); + return (p); +} + #endif diff --git a/src/third_party/wiredtiger/bench/wtperf/wtperf_opt.i b/src/third_party/wiredtiger/bench/wtperf/wtperf_opt.i index 3c122e4d186..6dc2a6d5569 100644 --- a/src/third_party/wiredtiger/bench/wtperf/wtperf_opt.i +++ b/src/third_party/wiredtiger/bench/wtperf/wtperf_opt.i @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. @@ -110,6 +110,10 @@ DEF_OPT_AS_UINT32(drop_tables, 0, DEF_OPT_AS_UINT32(icount, 5000, "number of records to initially populate. If multiple tables are " "configured the count is spread evenly across all tables.") +DEF_OPT_AS_UINT32(idle_table_cycle, 0, + "Enable regular create and drop of idle tables, value is the maximum " + "number of seconds a create or drop is allowed before flagging an error. " + "Default 0 which means disabled.") DEF_OPT_AS_BOOL(index, 0, "Whether to create an index on the value field.") DEF_OPT_AS_BOOL(insert_rmw, 0, diff --git a/src/third_party/wiredtiger/bench/wtperf/wtperf_throttle.c b/src/third_party/wiredtiger/bench/wtperf/wtperf_throttle.c new file mode 100644 index 00000000000..bba1f629715 --- /dev/null +++ b/src/third_party/wiredtiger/bench/wtperf/wtperf_throttle.c @@ -0,0 +1,121 @@ +/*- + * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "wtperf.h" + +/* + * Put the initial config together for running a throttled workload. + */ +int +setup_throttle(CONFIG_THREAD *thread) +{ + THROTTLE_CONFIG *throttle_cfg; + + throttle_cfg = &thread->throttle_cfg; + + /* + * Setup how the number of operations to run each interval in order to + * meet our desired max throughput. + * - If we have a very small number of them we can do one op + * on a larger increment. Given there is overhead in throttle logic + * we want to avoid running the throttle check regularly. + * - For most workloads, we aim to do 100 ops per interval and adjust + * the sleep period accordingly. + * - For high throughput workloads, we aim to do many ops in 100us + * increments. + */ + + if (thread->workload->throttle < THROTTLE_OPS) { + /* If the interval is very small, we do one operation */ + throttle_cfg->usecs_increment = + USEC_PER_SEC / thread->workload->throttle; + throttle_cfg->ops_per_increment = 1; + } else if (thread->workload->throttle < USEC_PER_SEC / THROTTLE_OPS) { + throttle_cfg->usecs_increment = + USEC_PER_SEC / thread->workload->throttle * THROTTLE_OPS; + throttle_cfg->ops_per_increment = THROTTLE_OPS; + } else { + /* If the interval is large, we do more ops per interval */ + throttle_cfg->usecs_increment = USEC_PER_SEC / THROTTLE_OPS; + throttle_cfg->ops_per_increment = + thread->workload->throttle / THROTTLE_OPS; + } + + /* Give the queue some initial operations to work with */ + throttle_cfg->ops_count = throttle_cfg->ops_per_increment; + + /* Set the first timestamp of when we incremented */ + WT_RET(__wt_epoch(NULL, &throttle_cfg->last_increment)); + return (0); +} + +/* + * Run the throttle function. We will sleep if needed and then reload the + * counter to perform more operations. + */ +int +worker_throttle(CONFIG_THREAD *thread) +{ + THROTTLE_CONFIG *throttle_cfg; + struct timespec now; + uint64_t usecs_delta; + + throttle_cfg = &thread->throttle_cfg; + + WT_RET(__wt_epoch(NULL, &now)); + + /* + * If we did enough operations in the current interval, sleep for + * the rest of the interval. Then add more operations to the queue. + */ + usecs_delta = WT_TIMEDIFF_US(now, throttle_cfg->last_increment); + if (usecs_delta < throttle_cfg->usecs_increment) { + (void)usleep( + (useconds_t)(throttle_cfg->usecs_increment - usecs_delta)); + throttle_cfg->ops_count = + throttle_cfg->ops_per_increment; + /* + * After sleeping, set the interval to the current time. + */ + WT_RET(__wt_epoch(NULL, &throttle_cfg->last_increment)); + } else { + throttle_cfg->ops_count = + (uint64_t) (float)(usecs_delta / + throttle_cfg->usecs_increment) * + (float)throttle_cfg->ops_per_increment; + throttle_cfg->last_increment = now; + } + + /* + * Take the minimum so we don't overfill the queue. + */ + throttle_cfg->ops_count = + WT_MIN(throttle_cfg->ops_count, thread->workload->throttle); + + return (0); +} diff --git a/src/third_party/wiredtiger/bench/wtperf/wtperf_truncate.c b/src/third_party/wiredtiger/bench/wtperf/wtperf_truncate.c index 2aec122875e..11b09c60d5d 100644 --- a/src/third_party/wiredtiger/bench/wtperf/wtperf_truncate.c +++ b/src/third_party/wiredtiger/bench/wtperf/wtperf_truncate.c @@ -1,5 +1,5 @@ /*- - * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2014-2016 MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. @@ -41,7 +41,7 @@ setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) { TRUNCATE_QUEUE_ENTRY *truncate_item; WORKLOAD *workload; WT_CURSOR *cursor; - char *key, *truncate_key; + char *key; int ret; uint64_t end_point, final_stone_gap, i, start_point; @@ -102,23 +102,14 @@ setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) { if (trunc_cfg->stone_gap != 0) { trunc_cfg->expected_total = (end_point - start_point); for (i = 1; i <= trunc_cfg->needed_stones; i++) { - truncate_key = calloc(cfg->key_sz, 1); - if (truncate_key == NULL) { - ret = enomem(cfg); - goto err; - } - truncate_item = calloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1); - if (truncate_item == NULL) { - free(truncate_key); - ret = enomem(cfg); - goto err; - } + truncate_item = + dcalloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1); + truncate_item->key = dcalloc(cfg->key_sz, 1); generate_key( - cfg, truncate_key, trunc_cfg->stone_gap * i); - truncate_item->key = truncate_key; + cfg, truncate_item->key, trunc_cfg->stone_gap * i); truncate_item->diff = (trunc_cfg->stone_gap * i) - trunc_cfg->last_key; - TAILQ_INSERT_TAIL( &cfg->stone_head, truncate_item, q); + TAILQ_INSERT_TAIL(&cfg->stone_head, truncate_item, q); trunc_cfg->last_key = trunc_cfg->stone_gap * i; trunc_cfg->num_stones++; } @@ -137,7 +128,6 @@ run_truncate(CONFIG *cfg, CONFIG_THREAD *thread, TRUNCATE_CONFIG *trunc_cfg; TRUNCATE_QUEUE_ENTRY *truncate_item; - char *truncate_key; int ret, t_ret; uint64_t used_stone_gap; @@ -178,21 +168,9 @@ run_truncate(CONFIG *cfg, CONFIG_THREAD *thread, while (trunc_cfg->num_stones < trunc_cfg->needed_stones) { trunc_cfg->last_key += used_stone_gap; - truncate_key = calloc(cfg->key_sz, 1); - if (truncate_key == NULL) { - lprintf(cfg, ENOMEM, 0, - "truncate: couldn't allocate key array"); - return (ENOMEM); - } - truncate_item = calloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1); - if (truncate_item == NULL) { - free(truncate_key); - lprintf(cfg, ENOMEM, 0, - "truncate: couldn't allocate item"); - return (ENOMEM); - } - generate_key(cfg, truncate_key, trunc_cfg->last_key); - truncate_item->key = truncate_key; + truncate_item = dcalloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1); + truncate_item->key = dcalloc(cfg->key_sz, 1); + generate_key(cfg, truncate_item->key, trunc_cfg->last_key); truncate_item->diff = used_stone_gap; TAILQ_INSERT_TAIL(&cfg->stone_head, truncate_item, q); trunc_cfg->num_stones++; |