summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorAlex Gorrod <agorrod@wiredtiger.com>2012-10-05 08:12:10 +0000
committerAlex Gorrod <agorrod@wiredtiger.com>2012-10-05 08:12:10 +0000
commitf1ec85020ad4a32ec509309511e4f4ef43d39afd (patch)
treef7aa3337eedbe0d60aa8586915d0e1e332988765 /examples
parent24202a6321035b2714e74a1065e4a01e41f142a0 (diff)
downloadmongo-f1ec85020ad4a32ec509309511e4f4ef43d39afd.tar.gz
Add example program to test basic LSM usage.
Diffstat (limited to 'examples')
-rw-r--r--examples/c/Makefile.am1
-rw-r--r--examples/c/ex_test_perf.c357
2 files changed, 358 insertions, 0 deletions
diff --git a/examples/c/Makefile.am b/examples/c/Makefile.am
index 2bca8422a91..6f26d01a35c 100644
--- a/examples/c/Makefile.am
+++ b/examples/c/Makefile.am
@@ -13,6 +13,7 @@ noinst_PROGRAMS = \
ex_process \
ex_schema \
ex_stat \
+ ex_test_perf \
ex_thread
# The examples can be run with no arguments as simple smoke tests
diff --git a/examples/c/ex_test_perf.c b/examples/c/ex_test_perf.c
new file mode 100644
index 00000000000..ef77cd5ef57
--- /dev/null
+++ b/examples/c/ex_test_perf.c
@@ -0,0 +1,357 @@
+/*-
+ * Public Domain 2008-2012 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.
+ *
+ * ex_test_perf.c
+ * This is an application that executes parallel random read workload.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <wiredtiger.h>
+
+typedef struct {
+ const char *home;
+ const char *uri;
+ const char *conn_config;
+ const char *table_config;
+ uint32_t create; /* Whether to populate for this run. */
+ uint32_t rand_seed;
+ uint32_t icount; /* Items to insert. */
+ uint32_t data_sz;
+ uint32_t key_sz;
+ uint32_t report_interval;
+ uint32_t read_time;
+ uint32_t read_threads; /* Number of read threads. */
+ uint32_t verbose;
+ WT_CONNECTION *conn;
+} CONFIG;
+
+/* Forward function definitions. */
+int populate(CONFIG *);
+void print_config(CONFIG *cfg);
+void *read_thread(void *arg);
+void usage(void);
+
+/* Default values - these are small, we want the basic run to be fast. */
+CONFIG default_cfg = {
+ "WT_TEST", /* home */
+ "lsm:test", /* uri */
+ "create,cache_size=2GB", /* conn_config */
+ "key_format=S,value_format=S,lsm_chunk_size=20MB,"
+ "leaf_page_max=16k,internal_page_max=16kb", /* table_config */
+ 1, /* create */
+ 14023954, /* rand_seed */
+ 500000, /* icount */
+ 100, /* data_sz */
+ 20, /* key_sz */
+ 20, /* report_interval */
+ 10, /* read_time */
+ 16, /* read_threads */
+ 0, /* verbose */
+ NULL
+};
+
+const char *debug_cconfig = "verbose=[lsm]";
+const char *debug_tconfig = "";
+
+/* Global values shared by threads. */
+uint64_t nops;
+int running;
+
+void *
+read_thread(void *arg)
+{
+ CONFIG *cfg;
+ WT_CONNECTION *conn;
+ WT_SESSION *session;
+ WT_CURSOR *cursor;
+ char *key_buf;
+ int ret;
+
+ cfg = (CONFIG *)arg;
+ conn = cfg->conn;
+ key_buf = calloc(cfg->key_sz, 1);
+ if (key_buf == NULL)
+ return (arg);
+
+ if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) {
+ fprintf(stderr,
+ "open_session failed in read thread: %d\n", ret);
+ return (NULL);
+ }
+ if ((ret = session->open_cursor(session, cfg->uri,
+ NULL, NULL, &cursor)) != 0) {
+ fprintf(stderr, "open_cursor failed in read thread: %d\n", ret);
+ return (NULL);
+ }
+
+ while (running) {
+ ++nops;
+ sprintf(key_buf, "%d", rand() % cfg->icount);
+ cursor->set_key(cursor, key_buf);
+ cursor->search(cursor);
+ }
+ session->close(session, NULL);
+ return (arg);
+}
+
+int populate(CONFIG *cfg)
+{
+ WT_CONNECTION *conn;
+ WT_CURSOR *cursor;
+ WT_SESSION *session;
+ char *data_buf, *key_buf;
+ int ret;
+ uint32_t i;
+
+ conn = cfg->conn;
+
+ data_buf = calloc(cfg->data_sz, 1);
+ if (data_buf == NULL)
+ return (ENOMEM);
+ key_buf = calloc(cfg->key_sz, 1);
+ if (key_buf == NULL)
+ return (ENOMEM);
+
+ /* Open a session for the current thread's work. */
+ if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
+ fprintf(stderr, "Error opening a session on %s: %s\n",
+ cfg->home, wiredtiger_strerror(ret));
+
+ ret = session->create(session, cfg->uri, cfg->table_config);
+
+ ret = session->open_cursor(
+ session, cfg->uri, NULL, "bulk", &cursor);
+
+ memset(data_buf, 'a', cfg->data_sz - 1);
+ cursor->set_value(cursor, data_buf);
+ /* Populate the database. */
+ for (i = 0; i < cfg->icount; i++) {
+ if (cfg->verbose > 0) {
+ if (i % 1000000 == 0)
+ printf(".");
+ if (i % 50000000 == 0)
+ printf("\n");
+ }
+ sprintf(key_buf, "%d", i);
+ cursor->set_key(cursor, key_buf);
+ if ((ret = cursor->insert(cursor)) != 0) {
+ fprintf(stderr, "Failed inserting with: %d\n", ret);
+ return (1);
+ }
+ }
+ cursor->close(cursor);
+ session->close(session, NULL);
+ if (cfg->verbose > 0)
+ printf("Finished bulk load of %d items\n", cfg->icount);
+
+ free(data_buf);
+ free(key_buf);
+ return (ret);
+}
+
+int main(int argc, char **argv)
+{
+ CONFIG cfg;
+ WT_CONNECTION *conn;
+ const char *user_cconfig, *user_tconfig;
+ char *cc_buf, *tc_buf;
+ int ch, debug, ret;
+ pthread_t *read_threads;
+ uint32_t i, last_ops, req_len, slept;
+
+ /* Setup the default configuration values. */
+ memcpy(&cfg, &default_cfg, sizeof(cfg));
+ debug = 0;
+ cc_buf = tc_buf = NULL;
+ while ((ch = getopt(argc, argv, "C:DR:T:d:eh:i:k:r:s:u:v:")) != EOF)
+ switch (ch) {
+ case 'd':
+ cfg.data_sz = atoi(optarg);
+ break;
+ case 'e':
+ cfg.create = 0;
+ break;
+ case 'h':
+ cfg.home = optarg;
+ break;
+ case 'i':
+ cfg.icount = atoi(optarg) * 1000;
+ break;
+ case 'k':
+ cfg.key_sz = atoi(optarg);
+ break;
+ case 'r':
+ cfg.read_time = atoi(optarg);
+ break;
+ case 's':
+ cfg.rand_seed = atoi(optarg);
+ break;
+ case 'u':
+ cfg.uri = optarg;
+ break;
+ case 'v':
+ cfg.verbose = atoi(optarg);
+ break;
+ case 'C':
+ user_cconfig = optarg;
+ break;
+ case 'D':
+ debug = 1;
+ break;
+ case 'R':
+ cfg.read_threads = atoi(optarg);
+ break;
+ case 'T':
+ user_tconfig = optarg;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "Invalid option\n");
+ usage();
+ return (EINVAL);
+ }
+
+ /* Handle non-const configuration strings. */
+ if (debug || user_cconfig) {
+ req_len = strlen(cfg.conn_config) + strlen(debug_cconfig) +
+ strlen(user_cconfig);
+ cc_buf = calloc(req_len, 1);
+ if (cc_buf == NULL)
+ exit(ENOMEM);
+ snprintf(cc_buf, req_len, "%s%s%s%s%s",
+ cfg.conn_config,
+ debug ? "," : "", debug ? debug_cconfig : "",
+ user_cconfig ? "," : "", user_cconfig ? user_cconfig : "");
+ cfg.conn_config = cc_buf;
+ }
+ if (debug || user_tconfig) {
+ req_len = strlen(cfg.table_config) + strlen(debug_tconfig) +
+ strlen(user_tconfig);
+ tc_buf = calloc(req_len, 1);
+ if (tc_buf == NULL)
+ exit(ENOMEM);
+ snprintf(tc_buf, req_len, "%s%s%s%s%s",
+ cfg.table_config,
+ debug ? "," : "", debug ? debug_tconfig : "",
+ user_tconfig ? "," : "", user_tconfig ? user_tconfig : "");
+ cfg.table_config = tc_buf;
+ }
+
+ srand(cfg.rand_seed);
+
+ if (cfg.verbose > 1)
+ print_config(&cfg);
+
+ /* Open a connection to the database, creating it if necessary. */
+ if ((ret = wiredtiger_open(
+ cfg.home, NULL, cfg.conn_config, &conn)) != 0)
+ fprintf(stderr, "Error connecting to %s: %s\n",
+ cfg.home, wiredtiger_strerror(ret));
+
+ cfg.conn = conn;
+ if (cfg.create)
+ populate(&cfg);
+
+ if (cfg.verbose > 0)
+ printf("Starting read threads\n");
+ running = 1;
+ nops = 0;
+ read_threads = calloc(cfg.read_threads, sizeof(pthread_t *));
+ if (read_threads == NULL)
+ exit(ENOMEM);
+ for (i = 0; i < cfg.read_threads; i++)
+ ret = pthread_create(&read_threads[i], NULL, read_thread, &cfg);
+
+ if (cfg.report_interval > cfg.read_time)
+ cfg.report_interval = cfg.read_time;
+ for (slept = last_ops = 0; slept < cfg.read_time;
+ slept += cfg.report_interval) {
+ sleep(cfg.report_interval);
+ if (cfg.verbose > 0) {
+ printf("%" PRIu64 " ops in %d secs\n",
+ nops - last_ops, cfg.report_interval);
+ fflush(stdout);
+ }
+ last_ops = nops;
+ }
+ running = 0;
+
+ for (i = 0; i < cfg.read_threads; i++)
+ ret = pthread_join(read_threads[i], NULL);
+
+ /* Note: closing the connection implicitly closes open session(s). */
+ if ((ret = conn->close(conn, NULL)) != 0)
+ fprintf(stderr, "Error connecting to %s: %s\n",
+ cfg.home, wiredtiger_strerror(ret));
+
+ printf("Ran performance test example with %d threads for %d seconds.\n",
+ cfg.read_threads, cfg.read_time);
+ printf("Executed %" PRIu64 " read operations\n", nops);
+ return (ret);
+}
+
+void print_config(CONFIG *cfg)
+{
+ printf("Workload configuration:\n");
+ printf("\t home: %s\n", cfg->home);
+ printf("\t uri: %s\n", cfg->uri);
+ printf("\t Connection configuration: %s\n", cfg->conn_config);
+ printf("\t Table configuration: %s\n", cfg->table_config);
+ printf("\t %s\n", cfg->create ? "Creating" : "Using existing");
+ printf("\t Random seed: %d\n", cfg->rand_seed);
+ if (cfg->create)
+ printf("\tInsert count: %d\n", cfg->icount);
+ printf("\t key size: %d data size: %d\n", cfg->key_sz, cfg->data_sz);
+ printf("\t Reporting interval: %d\n", cfg->report_interval);
+ printf("\t Read workload period: %d\n", cfg->read_time);
+ printf("\t Number read threads: %d\n", cfg->read_threads);
+ printf("\t Verbosity: %d\n", cfg->verbose);
+}
+
+void usage(void)
+{
+ printf("ex_perf_test [-CDRTdehikrsuv]\n");
+ printf("\t-C <string> additional connection configuration\n");
+ printf("\t-D debug configuration\n");
+ printf("\t-R <int> number of read threads\n");
+ printf("\t-T <string> additional table configuration\n");
+ printf("\t-d <int> data item size\n");
+ printf("\t-e use existing database (skip population phase)\n");
+ printf("\t-h <string> Wired Tiger home must exist, default WT_TEST \n");
+ printf("\t-i <int> number of records to insert\n");
+ printf("\t-k <int> key item size\n");
+ printf("\t-r <int> number of seconds to run read phase\n");
+ printf("\t-s <int> seed for random number generator\n");
+ printf("\t-u <string> table uri, default lsm:test\n");
+ printf("\t-v <int> verbosity\n");
+}