summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/bench/wtperf
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/bench/wtperf')
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/Makefile.am3
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/config.c79
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/config_opt.h2
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/doxy.c2
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/idle_table_cycle.c192
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/misc.c20
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/runners/checkpoint_stress_schema_ops.wtperf19
-rwxr-xr-xsrc/third_party/wiredtiger/bench/wtperf/runners/get_ckpt.py2
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/track.c2
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/wtperf.c208
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/wtperf.h113
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/wtperf_opt.i6
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/wtperf_throttle.c121
-rw-r--r--src/third_party/wiredtiger/bench/wtperf/wtperf_truncate.c42
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++;