Merge in old and new memslap.
authorBrian Aker <brian@tangent.org>
Tue, 5 Apr 2011 02:18:34 +0000 (19:18 -0700)
committerBrian Aker <brian@tangent.org>
Tue, 5 Apr 2011 02:18:34 +0000 (19:18 -0700)
.bzrignore
clients/include.am
clients/memaslap.c [new file with mode: 0644]
clients/memslap.c
docs/Makefile.am
docs/memaslap.pod [new file with mode: 0644]
docs/memslap.pod

index 6d1eabf5ea876b99d34ca43fe7096c728e97c2aa..1fe320b9ad0517d2e267e4a210d81fd70b274667 100644 (file)
@@ -20,6 +20,7 @@ Makefile.in
 TAGS
 aclocal.m4
 autom4te.cache
+clients/memaslap
 clients/memcapable
 clients/memcat
 clients/memcp
index f7503754649028eb6ae48ef96911e808dcb2bade..07d49a709b4b0d8b434aa45c682a48661d9882b8 100644 (file)
@@ -20,11 +20,12 @@ bin_PROGRAMS+= \
        clients/memflush \
        clients/memparse \
        clients/memrm \
+       clients/memslap \
        clients/memstat
 
 if HAVE_LIBEVENT
 if !BUILD_WIN32_WRAPPERS
-  bin_PROGRAMS+= clients/memslap
+  bin_PROGRAMS+= clients/memaslap
 endif
 endif
 
@@ -72,15 +73,18 @@ clients_memflush_LDADD= $(CLIENTS_LDADDS)
 clients_memerror_SOURCES= clients/memerror.c
 clients_memerror_LDADD= $(CLIENTS_LDADDS)
 
-clients_memslap_SOURCES= \
-               clients/memslap.c \
+clients_memslap_SOURCES = clients/memslap.c
+clients_memslap_LDADD = $(PTHREAD_LIBS) clients/libgenexec.la $(CLIENTS_LDADDS)
+
+clients_memaslap_SOURCES= \
+               clients/memaslap.c \
                clients/ms_conn.c \
                clients/ms_setting.c \
                clients/ms_sigsegv.c \
                clients/ms_stats.c \
                clients/ms_task.c \
                clients/ms_thread.c
-clients_memslap_LDADD= $(LTLIBEVENT) clients/libgenexec.la $(CLIENTS_LDADDS)
+clients_memaslap_LDADD= $(LTLIBEVENT) clients/libgenexec.la $(CLIENTS_LDADDS)
 
 clients_memcapable_SOURCES= clients/memcapable.c
 clients_memcapable_LDADD= $(CLIENTS_LDADDS)
@@ -94,19 +98,19 @@ test-start-server:
        clients/memcat --servers=localhost /etc/services
        clients/memrm --servers=localhost /etc/services
        clients/memstat --servers=localhost
-       clients/memslap --servers=localhost
-       clients/memslap --servers=localhost --concurrency=10
-       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000
-       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10
-       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=get
-       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set
-       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set --non-blocking
+       clients/memaslap --servers=localhost
+       clients/memaslap --servers=localhost --concurrency=10
+       clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000
+       clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10
+       clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=get
+       clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set
+       clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set --non-blocking
 
 client-valgrind:
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=get
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set --non-blocking
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memaslap --servers=localhost
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memaslap --servers=localhost --concurrency=10
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=get
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memaslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set --non-blocking
diff --git a/clients/memaslap.c b/clients/memaslap.c
new file mode 100644 (file)
index 0000000..37e93ec
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ *  memslap
+ *
+ *  (c) Copyright 2009, Schooner Information Technology, Inc.
+ *  All rights reserved.
+ *  http://www.schoonerinfotech.com/
+ *
+ *  Use and distribution licensed under the BSD license.  See
+ *  the COPYING file for full text.
+ *
+ *  Authors:
+ *      Brian Aker
+ *      Mingqiang Zhuang <mingqiangzhuang@hengtiansoft.com>
+ *
+ */
+#include "config.h"
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <limits.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+
+#include "ms_sigsegv.h"
+#include "ms_setting.h"
+#include "ms_thread.h"
+
+#define PROGRAM_NAME    "memslap"
+#define PROGRAM_DESCRIPTION \
+                        "Generates workload against memcached servers."
+
+#ifdef __sun
+  /* For some odd reason the option struct on solaris defines the argument
+   * as char* and not const char*
+   */
+#define OPTIONSTRING char*
+#else
+#define OPTIONSTRING const char*
+#endif
+
+/* options */
+static struct option long_options[]=
+{
+  { (OPTIONSTRING)"servers",        required_argument,            NULL,
+    OPT_SERVERS            },
+  { (OPTIONSTRING)"threads",        required_argument,            NULL,
+    OPT_THREAD_NUMBER      },
+  { (OPTIONSTRING)"concurrency",    required_argument,            NULL,
+    OPT_CONCURRENCY        },
+  { (OPTIONSTRING)"conn_sock",      required_argument,            NULL,
+    OPT_SOCK_PER_CONN      },
+  { (OPTIONSTRING)"execute_number", required_argument,            NULL,
+    OPT_EXECUTE_NUMBER     },
+  { (OPTIONSTRING)"time",           required_argument,            NULL,
+    OPT_TIME               },
+  { (OPTIONSTRING)"cfg_cmd",        required_argument,            NULL,
+    OPT_CONFIG_CMD         },
+  { (OPTIONSTRING)"win_size",       required_argument,            NULL,
+    OPT_WINDOW_SIZE        },
+  { (OPTIONSTRING)"fixed_size",     required_argument,            NULL,
+    OPT_FIXED_LTH          },
+  { (OPTIONSTRING)"verify",         required_argument,            NULL,
+    OPT_VERIFY             },
+  { (OPTIONSTRING)"division",       required_argument,            NULL,
+    OPT_GETS_DIVISION      },
+  { (OPTIONSTRING)"stat_freq",      required_argument,            NULL,
+    OPT_STAT_FREQ          },
+  { (OPTIONSTRING)"exp_verify",     required_argument,            NULL,
+    OPT_EXPIRE             },
+  { (OPTIONSTRING)"overwrite",      required_argument,            NULL,
+    OPT_OVERWRITE          },
+  { (OPTIONSTRING)"reconnect",      no_argument,                  NULL,
+    OPT_RECONNECT          },
+  { (OPTIONSTRING)"udp",            no_argument,                  NULL,
+    OPT_UDP                },
+  { (OPTIONSTRING)"facebook",       no_argument,                  NULL,
+    OPT_FACEBOOK_TEST      },
+  { (OPTIONSTRING)"binary",         no_argument,                  NULL,
+    OPT_BINARY_PROTOCOL    },
+  { (OPTIONSTRING)"tps",            required_argument,            NULL,
+    OPT_TPS                },
+  { (OPTIONSTRING)"rep_write",      required_argument,            NULL,
+    OPT_REP_WRITE_SRV      },
+  { (OPTIONSTRING)"verbose",        no_argument,                  NULL,
+    OPT_VERBOSE            },
+  { (OPTIONSTRING)"help",           no_argument,                  NULL,
+    OPT_HELP               },
+  { (OPTIONSTRING)"version",        no_argument,                  NULL,
+    OPT_VERSION            },
+  { 0, 0, 0, 0 },
+};
+
+/* Prototypes */
+static void ms_sync_lock_init(void);
+static void ms_sync_lock_destroy(void);
+static void ms_global_struct_init(void);
+static void ms_global_struct_destroy(void);
+static void ms_version_command(const char *command_name);
+static const char *ms_lookup_help(ms_options_t option);
+static int64_t ms_parse_time(void);
+static int64_t ms_parse_size(void);
+static void ms_options_parse(int argc, char *argv[]);
+static int ms_check_para(void);
+static void ms_statistic_init(void);
+static void ms_stats_init(void);
+static void ms_print_statistics(int in_time);
+static void ms_print_memslap_stats(struct timeval *start_time,
+                                   struct timeval *end_time);
+static void ms_monitor_slap_mode(void);
+void ms_help_command(const char *command_name, const char *description);
+
+
+/* initialize the global locks */
+static void ms_sync_lock_init()
+{
+  ms_global.init_lock.count= 0;
+  pthread_mutex_init(&ms_global.init_lock.lock, NULL);
+  pthread_cond_init(&ms_global.init_lock.cond, NULL);
+
+  ms_global.warmup_lock.count = 0;
+  pthread_mutex_init(&ms_global.warmup_lock.lock, NULL);
+  pthread_cond_init(&ms_global.warmup_lock.cond, NULL);
+
+  ms_global.run_lock.count= 0;
+  pthread_mutex_init(&ms_global.run_lock.lock, NULL);
+  pthread_cond_init(&ms_global.run_lock.cond, NULL);
+
+  pthread_mutex_init(&ms_global.quit_mutex, NULL);
+  pthread_mutex_init(&ms_global.seq_mutex, NULL);
+} /* ms_sync_lock_init */
+
+
+/* destroy the global locks */
+static void ms_sync_lock_destroy()
+{
+  pthread_mutex_destroy(&ms_global.init_lock.lock);
+  pthread_cond_destroy(&ms_global.init_lock.cond);
+
+  pthread_mutex_destroy(&ms_global.warmup_lock.lock);
+  pthread_cond_destroy(&ms_global.warmup_lock.cond);
+
+  pthread_mutex_destroy(&ms_global.run_lock.lock);
+  pthread_cond_destroy(&ms_global.run_lock.cond);
+
+  pthread_mutex_destroy(&ms_global.quit_mutex);
+  pthread_mutex_destroy(&ms_global.seq_mutex);
+
+  if (ms_setting.stat_freq > 0)
+  {
+    pthread_mutex_destroy(&ms_statistic.stat_mutex);
+  }
+} /* ms_sync_lock_destroy */
+
+
+/* initialize the global structure */
+static void ms_global_struct_init()
+{
+  ms_sync_lock_init();
+  ms_global.finish_warmup= false;
+  ms_global.time_out= false;
+}
+
+
+/* destroy the global structure */
+static void ms_global_struct_destroy()
+{
+  ms_sync_lock_destroy();
+}
+
+
+/**
+ * output the version information
+ *
+ * @param command_name, the string of this process
+ */
+static void ms_version_command(const char *command_name)
+{
+  printf("%s v%u.%u\n", command_name, 1U, 0U);
+  exit(0);
+}
+
+
+/**
+ * get the description of the option
+ *
+ * @param option, option of command line
+ *
+ * @return char*, description of the command option
+ */
+static const char *ms_lookup_help(ms_options_t option)
+{
+  switch (option)
+  {
+  case OPT_SERVERS:
+    return
+      "List one or more servers to connect. Servers count must be less than\n"
+      "        threads count. e.g.: --servers=localhost:1234,localhost:11211";
+
+  case OPT_VERSION:
+    return "Display the version of the application and then exit.";
+
+  case OPT_HELP:
+    return "Display this message and then exit.";
+
+  case OPT_EXECUTE_NUMBER:
+    return "Number of operations(get and set) to execute for the\n"
+           "        given test. Default 1000000.";
+
+  case OPT_THREAD_NUMBER:
+    return
+      "Number of threads to startup, better equal to CPU numbers. Default 8.";
+
+  case OPT_CONCURRENCY:
+    return "Number of concurrency to simulate with load. Default 128.";
+
+  case OPT_FIXED_LTH:
+    return "Fixed length of value.";
+
+  case OPT_VERIFY:
+    return "The proportion of date verification, e.g.: --verify=0.01";
+
+  case OPT_GETS_DIVISION:
+    return "Number of keys to multi-get once. Default 1, means single get.";
+
+  case OPT_TIME:
+    return
+      "How long the test to run, suffix: s-seconds, m-minutes, h-hours,\n"
+      "        d-days e.g.: --time=2h.";
+
+  case OPT_CONFIG_CMD:
+    return
+      "Load the configure file to get command,key and value distribution list.";
+
+  case OPT_WINDOW_SIZE:
+    return
+      "Task window size of each concurrency, suffix: K, M e.g.: --win_size=10k.\n"
+      "        Default 10k.";
+
+  case OPT_UDP:
+    return
+      "UDP support, default memslap uses TCP, TCP port and UDP port of\n"
+      "        server must be same.";
+
+  case OPT_EXPIRE:
+    return
+      "The proportion of objects with expire time, e.g.: --exp_verify=0.01.\n"
+      "        Default no object with expire time";
+
+  case OPT_OVERWRITE:
+    return
+      "The proportion of objects need overwrite, e.g.: --overwrite=0.01.\n"
+      "        Default never overwrite object.";
+
+  case OPT_STAT_FREQ:
+    return
+      "Frequency of dumping statistic information. suffix: s-seconds,\n"
+      "        m-minutes, e.g.: --resp_freq=10s.";
+
+  case OPT_SOCK_PER_CONN:
+    return "Number of TCP socks per concurrency. Default 1.";
+
+  case OPT_RECONNECT:
+    return
+      "Reconnect support, when connection is closed it will be reconnected.";
+
+  case OPT_VERBOSE:
+    return
+      "Whether it outputs detailed information when verification fails.";
+
+  case OPT_FACEBOOK_TEST:
+    return
+      "Whether it enables facebook test feature, set with TCP and multi-get with UDP.";
+
+  case OPT_BINARY_PROTOCOL:
+    return
+      "Whether it enables binary protocol. Default with ASCII protocol.";
+
+  case OPT_TPS:
+    return "Expected throughput, suffix: K, e.g.: --tps=10k.";
+
+  case OPT_REP_WRITE_SRV:
+    return "The first nth servers can write data, e.g.: --rep_write=2.";
+
+  default:
+    return "Forgot to document this option :)";
+  } /* switch */
+} /* ms_lookup_help */
+
+
+/**
+ * output the help information
+ *
+ * @param command_name, the string of this process
+ * @param description, description of this process
+ * @param long_options, global options array
+ */
+void ms_help_command(const char *command_name, const char *description)
+{
+  char *help_message= NULL;
+
+  printf("%s v%u.%u\n", command_name, 1U, 0U);
+  printf("    %s\n\n", description);
+  printf(
+    "Usage:\n"
+    "    memslap -hV | -s servers [-F config_file] [-t time | -x exe_num] [...]\n\n"
+    "Options:\n");
+
+  for (int x= 0; long_options[x].name; x++)
+  {
+    printf("    -%c, --%s%c\n", long_options[x].val, long_options[x].name,
+           long_options[x].has_arg ? '=' : ' ');
+
+    if ((help_message= (char *)ms_lookup_help(long_options[x].val)) != NULL)
+    {
+      printf("        %s\n", help_message);
+    }
+  }
+
+  printf(
+    "\nExamples:\n"
+    "    memslap -s 127.0.0.1:11211 -S 5s\n"
+    "    memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b\n"
+    "    memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2\n"
+    "    memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k\n"
+    "    memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40\n"
+    "    memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m\n"
+    "    memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2\n\n");
+
+  exit(0);
+} /* ms_help_command */
+
+
+/* used to parse the time string  */
+static int64_t ms_parse_time()
+{
+  int64_t ret= 0;
+  char unit= optarg[strlen(optarg) - 1];
+
+  optarg[strlen(optarg) - 1]= '\0';
+  ret= atoi(optarg);
+
+  switch (unit)
+  {
+  case 'd':
+  case 'D':
+    ret*= 24;
+
+  case 'h':
+  case 'H':
+    ret*= 60;
+
+  case 'm':
+  case 'M':
+    ret*= 60;
+
+  case 's':
+  case 'S':
+    break;
+
+  default:
+    ret= -1;
+    break;
+  } /* switch */
+
+  return ret;
+} /* ms_parse_time */
+
+
+/* used to parse the size string */
+static int64_t ms_parse_size()
+{
+  int64_t ret= -1;
+  char unit= optarg[strlen(optarg) - 1];
+
+  optarg[strlen(optarg) - 1]= '\0';
+  ret= strtoll(optarg, (char **)NULL, 10);
+
+  switch (unit)
+  {
+  case 'k':
+  case 'K':
+    ret*= 1024;
+    break;
+
+  case 'm':
+  case 'M':
+    ret*= 1024 * 1024;
+    break;
+
+  case 'g':
+  case 'G':
+    ret*= 1024 * 1024 * 1024;
+    break;
+
+  default:
+    ret= -1;
+    break;
+  } /* switch */
+
+  return ret;
+} /* ms_parse_size */
+
+
+/* used to parse the options of command line */
+static void ms_options_parse(int argc, char *argv[])
+{
+  int option_index= 0;
+  int option_rv;
+
+  while ((option_rv= getopt_long(argc, argv, "VhURbaBs:x:T:c:X:v:d:"
+                                             "t:S:F:w:e:o:n:P:p:",
+                                 long_options, &option_index)) != -1)
+  {
+    switch (option_rv)
+    {
+    case 0:
+      break;
+
+    case OPT_VERSION:     /* --version or -V */
+      ms_version_command(PROGRAM_NAME);
+      break;
+
+    case OPT_HELP:     /* --help or -h */
+      ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
+      break;
+
+    case OPT_SERVERS:     /* --servers or -s */
+      ms_setting.srv_str= strdup(optarg);
+      break;
+
+    case OPT_CONCURRENCY:       /* --concurrency or -c */
+      ms_setting.nconns= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+      if (ms_setting.nconns <= 0)
+      {
+        fprintf(stderr, "Concurrency must be greater than 0.:-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_EXECUTE_NUMBER:        /* --execute_number or -x */
+      ms_setting.exec_num= (int)strtol(optarg, (char **) NULL, 10);
+      if (ms_setting.exec_num <= 0)
+      {
+        fprintf(stderr, "Execute number must be greater than 0.:-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_THREAD_NUMBER:     /* --threads or -T */
+      ms_setting.nthreads= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+      if (ms_setting.nthreads <= 0)
+      {
+        fprintf(stderr, "Threads number must be greater than 0.:-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_FIXED_LTH:         /* --fixed_size or -X */
+      ms_setting.fixed_value_size= (size_t)strtoull(optarg, (char **) NULL, 10);
+      if ((ms_setting.fixed_value_size <= 0)
+          || (ms_setting.fixed_value_size > MAX_VALUE_SIZE))
+      {
+        fprintf(stderr, "Value size must be between 0 and 1M.:-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_VERIFY:        /* --verify or -v */
+      ms_setting.verify_percent= atof(optarg);
+      if ((ms_setting.verify_percent <= 0)
+          || (ms_setting.verify_percent > 1.0))
+      {
+        fprintf(stderr, "Data verification rate must be "
+                        "greater than 0 and less than 1.0. :-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_GETS_DIVISION:         /* --division or -d */
+      ms_setting.mult_key_num= (int)strtol(optarg, (char **) NULL, 10);
+      if (ms_setting.mult_key_num <= 0)
+      {
+        fprintf(stderr, "Multi-get key number must be greater than 0.:-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_TIME:      /* --time or -t */
+      ms_setting.run_time= (int)ms_parse_time();
+      if (ms_setting.run_time == -1)
+      {
+        fprintf(stderr, "Please specify the run time. :-)\n"
+                        "'s' for second, 'm' for minute, 'h' for hour, "
+                        "'d' for day. e.g.: --time=24h (means 24 hours).\n");
+        exit(1);
+      }
+
+      if (ms_setting.run_time == 0)
+      {
+        fprintf(stderr, "Running time can not be 0. :-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_CONFIG_CMD:        /* --cfg_cmd or -F */
+      ms_setting.cfg_file= strdup(optarg);
+      break;
+
+    case OPT_WINDOW_SIZE:       /* --win_size or -w */
+      ms_setting.win_size= (size_t)ms_parse_size();
+      if (ms_setting.win_size == (size_t)-1)
+      {
+        fprintf(
+          stderr,
+          "Please specify the item window size. :-)\n"
+          "e.g.: --win_size=10k (means 10k task window size).\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_UDP:       /* --udp or -U*/
+      ms_setting.udp= true;
+      break;
+
+    case OPT_EXPIRE:        /* --exp_verify or -e */
+      ms_setting.exp_ver_per= atof(optarg);
+      if ((ms_setting.exp_ver_per <= 0) || (ms_setting.exp_ver_per > 1.0))
+      {
+        fprintf(stderr, "Expire time verification rate must be "
+                        "greater than 0 and less than 1.0. :-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_OVERWRITE:         /* --overwrite or -o */
+      ms_setting.overwrite_percent= atof(optarg);
+      if ((ms_setting.overwrite_percent <= 0)
+          || (ms_setting.overwrite_percent > 1.0))
+      {
+        fprintf(stderr, "Objects overwrite rate must be "
+                        "greater than 0 and less than 1.0. :-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_STAT_FREQ:         /* --stat_freq or -S */
+      ms_setting.stat_freq= (int)ms_parse_time();
+      if (ms_setting.stat_freq == -1)
+      {
+        fprintf(stderr, "Please specify the frequency of dumping "
+                        "statistic information. :-)\n"
+                        "'s' for second, 'm' for minute, 'h' for hour, "
+                        "'d' for day. e.g.: --time=24h (means 24 hours).\n");
+        exit(1);
+      }
+
+      if (ms_setting.stat_freq == 0)
+      {
+        fprintf(stderr, "The frequency of dumping statistic information "
+                        "can not be 0. :-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_SOCK_PER_CONN:         /* --conn_sock or -n */
+      ms_setting.sock_per_conn= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+      if (ms_setting.sock_per_conn <= 0)
+      {
+        fprintf(stderr, "Number of socks of each concurrency "
+                        "must be greater than 0.:-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_RECONNECT:     /* --reconnect or -R */
+      ms_setting.reconnect= true;
+      break;
+
+    case OPT_VERBOSE:       /* --verbose or -b */
+      ms_setting.verbose= true;
+      break;
+
+    case OPT_FACEBOOK_TEST:         /* --facebook or -a */
+      ms_setting.facebook_test= true;
+      break;
+
+    case OPT_BINARY_PROTOCOL:       /* --binary or -B */
+      ms_setting.binary_prot= true;
+      break;
+
+    case OPT_TPS:       /* --tps or -P */
+      ms_setting.expected_tps= (int)ms_parse_size();
+      if (ms_setting.expected_tps == -1)
+      {
+        fprintf(stderr,
+                "Please specify the item expected throughput. :-)\n"
+                "e.g.: --tps=10k (means 10k throughput).\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_REP_WRITE_SRV:         /* --rep_write or -p */
+      ms_setting.rep_write_srv= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+      if (ms_setting.rep_write_srv <= 0)
+      {
+        fprintf(stderr,
+                "Number of replication writing server must be greater "
+                "than 0.:-)\n");
+        exit(1);
+      }
+      break;
+
+    case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+
+    default:
+      abort();
+    } /* switch */
+  }
+} /* ms_options_parse */
+
+
+static int ms_check_para()
+{
+  if (ms_setting.srv_str == NULL)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+    {
+      ms_setting.srv_str= strdup(temp);
+    }
+    else
+    {
+      fprintf(stderr, "No Servers provided\n\n");
+      return -1;
+    }
+  }
+
+  if (ms_setting.nconns % (uint32_t)ms_setting.nthreads != 0)
+  {
+    fprintf(stderr, "Concurrency must be the multiples of threads count.\n");
+    return -1;
+  }
+
+  if (ms_setting.win_size % UNIT_ITEMS_COUNT != 0)
+  {
+    fprintf(stderr, "Window size must be the multiples of 1024.\n\n");
+    return -1;
+  }
+
+  return EXIT_SUCCESS;
+} /* ms_check_para */
+
+
+/* initialize the statistic structure */
+static void ms_statistic_init()
+{
+  pthread_mutex_init(&ms_statistic.stat_mutex, NULL);
+  ms_init_stats(&ms_statistic.get_stat, "Get");
+  ms_init_stats(&ms_statistic.set_stat, "Set");
+  ms_init_stats(&ms_statistic.total_stat, "Total");
+} /* ms_statistic_init */
+
+
+/* initialize the global state structure */
+static void ms_stats_init()
+{
+  memset(&ms_stats, 0, sizeof(ms_stats_t));
+  if (ms_setting.stat_freq > 0)
+  {
+    ms_statistic_init();
+  }
+} /* ms_stats_init */
+
+
+/* use to output the statistic */
+static void ms_print_statistics(int in_time)
+{
+  int obj_size= (int)(ms_setting.avg_key_size + ms_setting.avg_val_size);
+
+  printf("\033[1;1H\033[2J\n");
+  ms_dump_format_stats(&ms_statistic.get_stat, in_time,
+                       ms_setting.stat_freq, obj_size);
+  ms_dump_format_stats(&ms_statistic.set_stat, in_time,
+                       ms_setting.stat_freq, obj_size);
+  ms_dump_format_stats(&ms_statistic.total_stat, in_time,
+                       ms_setting.stat_freq, obj_size);
+} /* ms_print_statistics */
+
+
+/* used to print the states of memslap */
+static void ms_print_memslap_stats(struct timeval *start_time,
+                                   struct timeval *end_time)
+{
+  char buf[1024];
+  char *pos= buf;
+
+  pos+= snprintf(pos,
+                 sizeof(buf), "cmd_get: %lu\n",
+                 (unsigned long) ms_stats.cmd_get);
+  pos+= snprintf(pos,
+                 sizeof(buf) - (size_t)(pos -buf),
+                 "cmd_set: %lu\n",
+                 (unsigned long) ms_stats.cmd_set);
+  pos+= snprintf(pos,
+                 sizeof(buf) - (size_t)(pos -buf),
+                 "get_misses: %lu\n",
+                 (unsigned long) ms_stats.get_misses);
+
+  if (ms_setting.verify_percent > 0)
+  {
+    pos+= snprintf(pos,
+                   sizeof(buf) - (size_t)(pos -buf),
+                   "verify_misses: %lu\n",
+                   (unsigned long) ms_stats.vef_miss);
+    pos+= snprintf(pos,
+                   sizeof(buf) - (size_t)(pos -buf),
+                   "verify_failed: %lu\n",
+                   (unsigned long) ms_stats.vef_failed);
+  }
+
+  if (ms_setting.exp_ver_per > 0)
+  {
+    pos+= snprintf(pos,
+                   sizeof(buf) - (size_t)(pos -buf),
+                   "expired_get: %lu\n",
+                   (unsigned long) ms_stats.exp_get);
+    pos+= snprintf(pos,
+                   sizeof(buf) - (size_t)(pos -buf),
+                   "unexpired_unget: %lu\n",
+                   (unsigned long) ms_stats.unexp_unget);
+  }
+
+  pos+= snprintf(pos,
+                 sizeof(buf) - (size_t)(pos -buf),
+                 "written_bytes: %lu\n",
+                 (unsigned long) ms_stats.bytes_written);
+  pos+= snprintf(pos,
+                 sizeof(buf) - (size_t)(pos -buf),
+                 "read_bytes: %lu\n",
+                 (unsigned long) ms_stats.bytes_read);
+  pos+= snprintf(pos,
+                 sizeof(buf) - (size_t)(pos -buf),
+                 "object_bytes: %lu\n",
+                 (unsigned long) ms_stats.obj_bytes);
+
+  if (ms_setting.udp || ms_setting.facebook_test)
+  {
+    pos+= snprintf(pos,
+                   sizeof(buf) - (size_t)(pos -buf),
+                   "packet_disorder: %lu\n",
+                   (unsigned long) ms_stats.pkt_disorder);
+    pos+= snprintf(pos,
+                   sizeof(buf) - (size_t)(pos -buf),
+                   "packet_drop: %lu\n",
+                   (unsigned long)ms_stats.pkt_drop);
+    pos+= snprintf(pos,
+                   sizeof(buf) - (size_t)(pos -buf),
+                   "udp_timeout: %lu\n",
+                   (unsigned long)ms_stats.udp_timeout);
+  }
+
+  if (ms_setting.stat_freq > 0)
+  {
+    ms_dump_stats(&ms_statistic.get_stat);
+    ms_dump_stats(&ms_statistic.set_stat);
+    ms_dump_stats(&ms_statistic.total_stat);
+  }
+
+  int64_t time_diff= ms_time_diff(start_time, end_time);
+  pos+= snprintf(pos,
+                 sizeof(buf) - (size_t)(pos -buf),
+                 "\nRun time: %.1fs Ops: %llu TPS: %.0Lf Net_rate: %.1fM/s\n",
+                 (double)time_diff / 1000000,
+                 (unsigned long long)(ms_stats.cmd_get + ms_stats.cmd_set),
+                 (ms_stats.cmd_get
+                  + ms_stats.cmd_set) / ((long double)time_diff / 1000000),
+                 (double)(
+                          ms_stats.bytes_written
+                          + ms_stats.bytes_read) / 1024 / 1024
+                 / ((double)time_diff / 1000000));
+  assert(pos <= buf);
+
+  fprintf(stdout, "%s", buf);
+  fflush(stdout);
+} /* ms_print_memslap_stats */
+
+
+/* the loop of the main thread, wait the work threads to complete */
+static void ms_monitor_slap_mode()
+{
+  int second= 0;
+  struct timeval start_time, end_time;
+
+  /* Wait all the threads complete initialization. */
+  pthread_mutex_lock(&ms_global.init_lock.lock);
+  while (ms_global.init_lock.count < ms_setting.nthreads)
+  {
+    pthread_cond_wait(&ms_global.init_lock.cond,
+                      &ms_global.init_lock.lock);
+  }
+  pthread_mutex_unlock(&ms_global.init_lock.lock);
+
+  /* only when there is no set operation it need warm up */
+  if (ms_setting.cmd_distr[CMD_SET].cmd_prop < PROP_ERROR)
+  {
+    /* Wait all the connects complete warm up. */
+    pthread_mutex_lock(&ms_global.warmup_lock.lock);
+    while (ms_global.warmup_lock.count < ms_setting.nconns)
+    {
+      pthread_cond_wait(&ms_global.warmup_lock.cond, &ms_global.warmup_lock.lock);
+    }
+    pthread_mutex_unlock(&ms_global.warmup_lock.lock);
+  }
+  ms_global.finish_warmup= true;
+
+  /* running in "run time" mode, user specify run time */
+  if (ms_setting.run_time > 0)
+  {
+    gettimeofday(&start_time, NULL);
+    while (1)
+    {
+      sleep(1);
+      second++;
+
+      if ((ms_setting.stat_freq > 0) && (second % ms_setting.stat_freq == 0)
+          && (ms_stats.active_conns >= ms_setting.nconns)
+          && (ms_stats.active_conns <= INT_MAX))
+      {
+        ms_print_statistics(second);
+      }
+
+      if (ms_setting.run_time <= second)
+      {
+        ms_global.time_out= true;
+        break;
+      }
+
+      /* all connections disconnect */
+      if ((second > 5) && (ms_stats.active_conns == 0))
+      {
+        break;
+      }
+    }
+    gettimeofday(&end_time, NULL);
+    sleep(1);       /* wait all threads clean up */
+  }
+  else
+  {
+    /* running in "execute number" mode, user specify execute number */
+    gettimeofday(&start_time, NULL);
+
+    /*
+     * We loop until we know that all connects have cleaned up.
+     */
+    pthread_mutex_lock(&ms_global.run_lock.lock);
+    while (ms_global.run_lock.count < ms_setting.nconns)
+    {
+      pthread_cond_wait(&ms_global.run_lock.cond, &ms_global.run_lock.lock);
+    }
+    pthread_mutex_unlock(&ms_global.run_lock.lock);
+
+    gettimeofday(&end_time, NULL);
+  }
+
+  ms_print_memslap_stats(&start_time, &end_time);
+} /* ms_monitor_slap_mode */
+
+
+/* the main function */
+int main(int argc, char *argv[])
+{
+  srandom((unsigned int)time(NULL));
+  ms_global_struct_init();
+
+  /* initialization */
+  ms_setting_init_pre();
+  ms_options_parse(argc, argv);
+  if (ms_check_para())
+  {
+    ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
+    exit(1);
+  }
+  ms_setting_init_post();
+  ms_stats_init();
+  ms_thread_init();
+
+  /* waiting work thread complete its task */
+  ms_monitor_slap_mode();
+
+  /* clean up */
+  ms_thread_cleanup();
+  ms_global_struct_destroy();
+  ms_setting_cleanup();
+
+  return EXIT_SUCCESS;
+} /* main */
index 37e93ec3f9efa3eb15c42ff6b6c0be402982062c..0d77fd6e172be763f923752a1dc5b243e348c360 100644 (file)
-/*
- *  memslap
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- *  (c) Copyright 2009, Schooner Information Technology, Inc.
- *  All rights reserved.
- *  http://www.schoonerinfotech.com/
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
  *
- *  Use and distribution licensed under the BSD license.  See
- *  the COPYING file for full text.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
  *
- *  Authors:
- *      Brian Aker
- *      Mingqiang Zhuang <mingqiangzhuang@hengtiansoft.com>
+ *      * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ *      * Redistributions in binary form must reproduce the above
+ *  copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ *      * The names of its contributors may not be used to endorse or
+ *  promote products derived from this software without specific prior
+ *  written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-#include "config.h"
 
+
+#include <config.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/time.h>
 #include <getopt.h>
-#include <limits.h>
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif
-#endif
-
-
-#include "ms_sigsegv.h"
-#include "ms_setting.h"
-#include "ms_thread.h"
-
-#define PROGRAM_NAME    "memslap"
-#define PROGRAM_DESCRIPTION \
-                        "Generates workload against memcached servers."
-
-#ifdef __sun
-  /* For some odd reason the option struct on solaris defines the argument
-   * as char* and not const char*
-   */
-#define OPTIONSTRING char*
-#else
-#define OPTIONSTRING const char*
-#endif
+#include <pthread.h>
+#include <assert.h>
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+#include "generator.h"
+#include "execute.h"
+
+#define DEFAULT_INITIAL_LOAD 10000
+#define DEFAULT_EXECUTE_NUMBER 10000
+#define DEFAULT_CONCURRENCY 1
+
+#define PROGRAM_NAME "memslap"
+#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
+
+/* Global Thread counter */
+volatile unsigned int thread_counter;
+pthread_mutex_t counter_mutex;
+pthread_cond_t count_threshhold;
+volatile unsigned int master_wakeup;
+pthread_mutex_t sleeper_mutex;
+pthread_cond_t sleep_threshhold;
+
+void *run_task(void *p);
+
+/* Types */
+typedef struct conclusions_st conclusions_st;
+typedef struct thread_context_st thread_context_st;
+typedef enum {
+  SET_TEST,
+  GET_TEST,
+  MGET_TEST
+} test_type;
+
+struct thread_context_st {
+  unsigned int key_count;
+  pairs_st *initial_pairs;
+  unsigned int initial_number;
+  pairs_st *execute_pairs;
+  unsigned int execute_number;
+  char **keys;
+  size_t *key_lengths;
+  test_type test;
+  memcached_st *memc;
+};
 
-/* options */
-static struct option long_options[]=
-{
-  { (OPTIONSTRING)"servers",        required_argument,            NULL,
-    OPT_SERVERS            },
-  { (OPTIONSTRING)"threads",        required_argument,            NULL,
-    OPT_THREAD_NUMBER      },
-  { (OPTIONSTRING)"concurrency",    required_argument,            NULL,
-    OPT_CONCURRENCY        },
-  { (OPTIONSTRING)"conn_sock",      required_argument,            NULL,
-    OPT_SOCK_PER_CONN      },
-  { (OPTIONSTRING)"execute_number", required_argument,            NULL,
-    OPT_EXECUTE_NUMBER     },
-  { (OPTIONSTRING)"time",           required_argument,            NULL,
-    OPT_TIME               },
-  { (OPTIONSTRING)"cfg_cmd",        required_argument,            NULL,
-    OPT_CONFIG_CMD         },
-  { (OPTIONSTRING)"win_size",       required_argument,            NULL,
-    OPT_WINDOW_SIZE        },
-  { (OPTIONSTRING)"fixed_size",     required_argument,            NULL,
-    OPT_FIXED_LTH          },
-  { (OPTIONSTRING)"verify",         required_argument,            NULL,
-    OPT_VERIFY             },
-  { (OPTIONSTRING)"division",       required_argument,            NULL,
-    OPT_GETS_DIVISION      },
-  { (OPTIONSTRING)"stat_freq",      required_argument,            NULL,
-    OPT_STAT_FREQ          },
-  { (OPTIONSTRING)"exp_verify",     required_argument,            NULL,
-    OPT_EXPIRE             },
-  { (OPTIONSTRING)"overwrite",      required_argument,            NULL,
-    OPT_OVERWRITE          },
-  { (OPTIONSTRING)"reconnect",      no_argument,                  NULL,
-    OPT_RECONNECT          },
-  { (OPTIONSTRING)"udp",            no_argument,                  NULL,
-    OPT_UDP                },
-  { (OPTIONSTRING)"facebook",       no_argument,                  NULL,
-    OPT_FACEBOOK_TEST      },
-  { (OPTIONSTRING)"binary",         no_argument,                  NULL,
-    OPT_BINARY_PROTOCOL    },
-  { (OPTIONSTRING)"tps",            required_argument,            NULL,
-    OPT_TPS                },
-  { (OPTIONSTRING)"rep_write",      required_argument,            NULL,
-    OPT_REP_WRITE_SRV      },
-  { (OPTIONSTRING)"verbose",        no_argument,                  NULL,
-    OPT_VERBOSE            },
-  { (OPTIONSTRING)"help",           no_argument,                  NULL,
-    OPT_HELP               },
-  { (OPTIONSTRING)"version",        no_argument,                  NULL,
-    OPT_VERSION            },
-  { 0, 0, 0, 0 },
+struct conclusions_st {
+  long int load_time;
+  long int read_time;
+  unsigned int rows_loaded;
+  unsigned int rows_read;
 };
 
 /* Prototypes */
-static void ms_sync_lock_init(void);
-static void ms_sync_lock_destroy(void);
-static void ms_global_struct_init(void);
-static void ms_global_struct_destroy(void);
-static void ms_version_command(const char *command_name);
-static const char *ms_lookup_help(ms_options_t option);
-static int64_t ms_parse_time(void);
-static int64_t ms_parse_size(void);
-static void ms_options_parse(int argc, char *argv[]);
-static int ms_check_para(void);
-static void ms_statistic_init(void);
-static void ms_stats_init(void);
-static void ms_print_statistics(int in_time);
-static void ms_print_memslap_stats(struct timeval *start_time,
-                                   struct timeval *end_time);
-static void ms_monitor_slap_mode(void);
-void ms_help_command(const char *command_name, const char *description);
-
-
-/* initialize the global locks */
-static void ms_sync_lock_init()
-{
-  ms_global.init_lock.count= 0;
-  pthread_mutex_init(&ms_global.init_lock.lock, NULL);
-  pthread_cond_init(&ms_global.init_lock.cond, NULL);
-
-  ms_global.warmup_lock.count = 0;
-  pthread_mutex_init(&ms_global.warmup_lock.lock, NULL);
-  pthread_cond_init(&ms_global.warmup_lock.cond, NULL);
-
-  ms_global.run_lock.count= 0;
-  pthread_mutex_init(&ms_global.run_lock.lock, NULL);
-  pthread_cond_init(&ms_global.run_lock.cond, NULL);
-
-  pthread_mutex_init(&ms_global.quit_mutex, NULL);
-  pthread_mutex_init(&ms_global.seq_mutex, NULL);
-} /* ms_sync_lock_init */
+void options_parse(int argc, char *argv[]);
+void conclusions_print(conclusions_st *conclusion);
+void scheduler(memcached_server_st *servers, conclusions_st *conclusion);
+pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
+                           unsigned int *actual_loaded);
+void flush_all(memcached_st *memc);
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static int opt_flush= 0;
+static int opt_non_blocking_io= 0;
+static int opt_tcp_nodelay= 0;
+static unsigned int opt_execute_number= 0;
+static unsigned int opt_createial_load= 0;
+static unsigned int opt_concurrency= 0;
+static int opt_displayflag= 0;
+static char *opt_servers= NULL;
+static int opt_udp_io= 0;
+test_type opt_test= SET_TEST;
 
-
-/* destroy the global locks */
-static void ms_sync_lock_destroy()
+int main(int argc, char *argv[])
 {
-  pthread_mutex_destroy(&ms_global.init_lock.lock);
-  pthread_cond_destroy(&ms_global.init_lock.cond);
+  conclusions_st conclusion;
+  memcached_server_st *servers;
 
-  pthread_mutex_destroy(&ms_global.warmup_lock.lock);
-  pthread_cond_destroy(&ms_global.warmup_lock.cond);
+  memset(&conclusion, 0, sizeof(conclusions_st));
 
-  pthread_mutex_destroy(&ms_global.run_lock.lock);
-  pthread_cond_destroy(&ms_global.run_lock.cond);
-
-  pthread_mutex_destroy(&ms_global.quit_mutex);
-  pthread_mutex_destroy(&ms_global.seq_mutex);
+  srandom((unsigned int)time(NULL));
+  options_parse(argc, argv);
 
-  if (ms_setting.stat_freq > 0)
+  if (!opt_servers)
   {
-    pthread_mutex_destroy(&ms_statistic.stat_mutex);
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+      opt_servers= strdup(temp);
+    else
+    {
+      fprintf(stderr, "No Servers provided\n");
+      exit(1);
+    }
   }
-} /* ms_sync_lock_destroy */
 
+  servers= memcached_servers_parse(opt_servers);
 
-/* initialize the global structure */
-static void ms_global_struct_init()
-{
-  ms_sync_lock_init();
-  ms_global.finish_warmup= false;
-  ms_global.time_out= false;
-}
+  pthread_mutex_init(&counter_mutex, NULL);
+  pthread_cond_init(&count_threshhold, NULL);
+  pthread_mutex_init(&sleeper_mutex, NULL);
+  pthread_cond_init(&sleep_threshhold, NULL);
 
+  scheduler(servers, &conclusion);
 
-/* destroy the global structure */
-static void ms_global_struct_destroy()
-{
-  ms_sync_lock_destroy();
-}
+  free(opt_servers);
 
+  (void)pthread_mutex_destroy(&counter_mutex);
+  (void)pthread_cond_destroy(&count_threshhold);
+  (void)pthread_mutex_destroy(&sleeper_mutex);
+  (void)pthread_cond_destroy(&sleep_threshhold);
+  conclusions_print(&conclusion);
+  memcached_server_list_free(servers);
 
-/**
- * output the version information
- *
- * @param command_name, the string of this process
- */
-static void ms_version_command(const char *command_name)
-{
-  printf("%s v%u.%u\n", command_name, 1U, 0U);
-  exit(0);
+  return 0;
 }
 
-
-/**
- * get the description of the option
- *
- * @param option, option of command line
- *
- * @return char*, description of the command option
- */
-static const char *ms_lookup_help(ms_options_t option)
+void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
 {
-  switch (option)
-  {
-  case OPT_SERVERS:
-    return
-      "List one or more servers to connect. Servers count must be less than\n"
-      "        threads count. e.g.: --servers=localhost:1234,localhost:11211";
-
-  case OPT_VERSION:
-    return "Display the version of the application and then exit.";
-
-  case OPT_HELP:
-    return "Display this message and then exit.";
-
-  case OPT_EXECUTE_NUMBER:
-    return "Number of operations(get and set) to execute for the\n"
-           "        given test. Default 1000000.";
-
-  case OPT_THREAD_NUMBER:
-    return
-      "Number of threads to startup, better equal to CPU numbers. Default 8.";
-
-  case OPT_CONCURRENCY:
-    return "Number of concurrency to simulate with load. Default 128.";
-
-  case OPT_FIXED_LTH:
-    return "Fixed length of value.";
-
-  case OPT_VERIFY:
-    return "The proportion of date verification, e.g.: --verify=0.01";
-
-  case OPT_GETS_DIVISION:
-    return "Number of keys to multi-get once. Default 1, means single get.";
-
-  case OPT_TIME:
-    return
-      "How long the test to run, suffix: s-seconds, m-minutes, h-hours,\n"
-      "        d-days e.g.: --time=2h.";
+  unsigned int actual_loaded= 0; /* Fix warning */
+  memcached_st *memc;
 
-  case OPT_CONFIG_CMD:
-    return
-      "Load the configure file to get command,key and value distribution list.";
-
-  case OPT_WINDOW_SIZE:
-    return
-      "Task window size of each concurrency, suffix: K, M e.g.: --win_size=10k.\n"
-      "        Default 10k.";
-
-  case OPT_UDP:
-    return
-      "UDP support, default memslap uses TCP, TCP port and UDP port of\n"
-      "        server must be same.";
-
-  case OPT_EXPIRE:
-    return
-      "The proportion of objects with expire time, e.g.: --exp_verify=0.01.\n"
-      "        Default no object with expire time";
-
-  case OPT_OVERWRITE:
-    return
-      "The proportion of objects need overwrite, e.g.: --overwrite=0.01.\n"
-      "        Default never overwrite object.";
-
-  case OPT_STAT_FREQ:
-    return
-      "Frequency of dumping statistic information. suffix: s-seconds,\n"
-      "        m-minutes, e.g.: --resp_freq=10s.";
-
-  case OPT_SOCK_PER_CONN:
-    return "Number of TCP socks per concurrency. Default 1.";
-
-  case OPT_RECONNECT:
-    return
-      "Reconnect support, when connection is closed it will be reconnected.";
-
-  case OPT_VERBOSE:
-    return
-      "Whether it outputs detailed information when verification fails.";
-
-  case OPT_FACEBOOK_TEST:
-    return
-      "Whether it enables facebook test feature, set with TCP and multi-get with UDP.";
-
-  case OPT_BINARY_PROTOCOL:
-    return
-      "Whether it enables binary protocol. Default with ASCII protocol.";
+  struct timeval start_time, end_time;
+  pthread_t mainthread;            /* Thread descriptor */
+  pthread_attr_t attr;          /* Thread attributes */
+  pairs_st *pairs= NULL;
 
-  case OPT_TPS:
-    return "Expected throughput, suffix: K, e.g.: --tps=10k.";
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr,
+                              PTHREAD_CREATE_DETACHED);
 
-  case OPT_REP_WRITE_SRV:
-    return "The first nth servers can write data, e.g.: --rep_write=2.";
+  memc= memcached_create(NULL);
 
-  default:
-    return "Forgot to document this option :)";
-  } /* switch */
-} /* ms_lookup_help */
+  /* We need to set udp behavior before adding servers to the client */
+  if (opt_udp_io)
+  {
+    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP,
+                           (uint64_t)opt_udp_io);
+    for (uint32_t x= 0; x < memcached_server_list_count(servers); x++ )
+    {
+      servers[x].type= MEMCACHED_CONNECTION_UDP;
+    }
+  }
+  memcached_server_push(memc, servers);
 
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+                         (uint64_t)opt_binary);
 
-/**
- * output the help information
- *
- * @param command_name, the string of this process
- * @param description, description of this process
- * @param long_options, global options array
- */
-void ms_help_command(const char *command_name, const char *description)
-{
-  char *help_message= NULL;
+  if (opt_flush)
+    flush_all(memc);
+  if (opt_createial_load)
+    pairs= load_create_data(memc, opt_createial_load, &actual_loaded);
 
-  printf("%s v%u.%u\n", command_name, 1U, 0U);
-  printf("    %s\n\n", description);
-  printf(
-    "Usage:\n"
-    "    memslap -hV | -s servers [-F config_file] [-t time | -x exe_num] [...]\n\n"
-    "Options:\n");
+  char **keys= calloc(actual_loaded, sizeof(char*));
+  size_t *key_lengths= calloc(actual_loaded, sizeof(size_t));
 
-  for (int x= 0; long_options[x].name; x++)
+  if (keys == NULL || key_lengths == NULL)
   {
-    printf("    -%c, --%s%c\n", long_options[x].val, long_options[x].name,
-           long_options[x].has_arg ? '=' : ' ');
-
-    if ((help_message= (char *)ms_lookup_help(long_options[x].val)) != NULL)
+    free(keys);
+    free(key_lengths);
+    keys= NULL;
+    key_lengths= NULL;
+  }
+  else
+  {
+    for (uint32_t x= 0; x < actual_loaded; ++x)
     {
-      printf("        %s\n", help_message);
+      keys[x]= pairs[x].key;
+      key_lengths[x]= pairs[x].key_length;
     }
   }
 
-  printf(
-    "\nExamples:\n"
-    "    memslap -s 127.0.0.1:11211 -S 5s\n"
-    "    memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b\n"
-    "    memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2\n"
-    "    memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k\n"
-    "    memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40\n"
-    "    memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m\n"
-    "    memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2\n\n");
-
-  exit(0);
-} /* ms_help_command */
-
+  /* We set this after we have loaded */
+  {
+    if (opt_non_blocking_io)
+      memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
+    if (opt_tcp_nodelay)
+      memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
+  }
 
-/* used to parse the time string  */
-static int64_t ms_parse_time()
-{
-  int64_t ret= 0;
-  char unit= optarg[strlen(optarg) - 1];
+  pthread_mutex_lock(&counter_mutex);
+  thread_counter= 0;
 
-  optarg[strlen(optarg) - 1]= '\0';
-  ret= atoi(optarg);
+  pthread_mutex_lock(&sleeper_mutex);
+  master_wakeup= 1;
+  pthread_mutex_unlock(&sleeper_mutex);
 
-  switch (unit)
+  for (uint32_t x= 0; x < opt_concurrency; x++)
   {
-  case 'd':
-  case 'D':
-    ret*= 24;
-
-  case 'h':
-  case 'H':
-    ret*= 60;
+    thread_context_st *context;
+    context= (thread_context_st *)calloc(1, sizeof(thread_context_st));
 
-  case 'm':
-  case 'M':
-    ret*= 60;
+    context->memc= memcached_clone(NULL, memc);
+    context->test= opt_test;
 
-  case 's':
-  case 'S':
-    break;
+    context->initial_pairs= pairs;
+    context->initial_number= actual_loaded;
+    context->keys= keys;
+    context->key_lengths= key_lengths;
 
-  default:
-    ret= -1;
-    break;
-  } /* switch */
+    if (opt_test == SET_TEST)
+    {
+      context->execute_pairs= pairs_generate(opt_execute_number, 400);
+      context->execute_number= opt_execute_number;
+    }
 
-  return ret;
-} /* ms_parse_time */
+    /* now you create the thread */
+    if (pthread_create(&mainthread, &attr, run_task,
+                       (void *)context) != 0)
+    {
+      fprintf(stderr,"Could not create thread\n");
+      exit(1);
+    }
+    thread_counter++;
+  }
 
+  pthread_mutex_unlock(&counter_mutex);
+  pthread_attr_destroy(&attr);
+
+  pthread_mutex_lock(&sleeper_mutex);
+  master_wakeup= 0;
+  pthread_mutex_unlock(&sleeper_mutex);
+  pthread_cond_broadcast(&sleep_threshhold);
+
+  gettimeofday(&start_time, NULL);
+  /*
+    We loop until we know that all children have cleaned up.
+  */
+  pthread_mutex_lock(&counter_mutex);
+  while (thread_counter)
+    pthread_cond_wait(&count_threshhold, &counter_mutex);
+  pthread_mutex_unlock(&counter_mutex);
+
+  gettimeofday(&end_time, NULL);
+
+  conclusion->load_time= timedif(end_time, start_time);
+  conclusion->read_time= timedif(end_time, start_time);
+  free(keys);
+  free(key_lengths);
+  pairs_free(pairs);
+  memcached_free(memc);
+}
 
-/* used to parse the size string */
-static int64_t ms_parse_size()
+void options_parse(int argc, char *argv[])
 {
-  int64_t ret= -1;
-  char unit= optarg[strlen(optarg) - 1];
-
-  optarg[strlen(optarg) - 1]= '\0';
-  ret= strtoll(optarg, (char **)NULL, 10);
-
-  switch (unit)
+  memcached_programs_help_st help_options[]=
   {
-  case 'k':
-  case 'K':
-    ret*= 1024;
-    break;
-
-  case 'm':
-  case 'M':
-    ret*= 1024 * 1024;
-    break;
-
-  case 'g':
-  case 'G':
-    ret*= 1024 * 1024 * 1024;
-    break;
-
-  default:
-    ret= -1;
-    break;
-  } /* switch */
-
-  return ret;
-} /* ms_parse_size */
+    {0},
+  };
 
+  static struct option long_options[]=
+    {
+      {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY},
+      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+      {(OPTIONSTRING)"execute-number", required_argument, NULL, OPT_SLAP_EXECUTE_NUMBER},
+      {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
+      {(OPTIONSTRING)"flush", no_argument, &opt_flush, OPT_FLUSH},
+      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+      {(OPTIONSTRING)"initial-load", required_argument, NULL, OPT_SLAP_INITIAL_LOAD}, /* Number to load initially */
+      {(OPTIONSTRING)"non-blocking", no_argument, &opt_non_blocking_io, OPT_SLAP_NON_BLOCK},
+      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+      {(OPTIONSTRING)"tcp-nodelay", no_argument, &opt_tcp_nodelay, OPT_SLAP_TCP_NODELAY},
+      {(OPTIONSTRING)"test", required_argument, NULL, OPT_SLAP_TEST},
+      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+      {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP},
+      {0, 0, 0, 0},
+    };
 
-/* used to parse the options of command line */
-static void ms_options_parse(int argc, char *argv[])
-{
   int option_index= 0;
   int option_rv;
 
-  while ((option_rv= getopt_long(argc, argv, "VhURbaBs:x:T:c:X:v:d:"
-                                             "t:S:F:w:e:o:n:P:p:",
-                                 long_options, &option_index)) != -1)
+  while (1)
   {
+    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+    if (option_rv == -1) break;
     switch (option_rv)
     {
     case 0:
       break;
-
-    case OPT_VERSION:     /* --version or -V */
-      ms_version_command(PROGRAM_NAME);
-      break;
-
-    case OPT_HELP:     /* --help or -h */
-      ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
-      break;
-
-    case OPT_SERVERS:     /* --servers or -s */
-      ms_setting.srv_str= strdup(optarg);
-      break;
-
-    case OPT_CONCURRENCY:       /* --concurrency or -c */
-      ms_setting.nconns= (uint32_t)strtoul(optarg, (char **) NULL, 10);
-      if (ms_setting.nconns <= 0)
-      {
-        fprintf(stderr, "Concurrency must be greater than 0.:-)\n");
-        exit(1);
-      }
-      break;
-
-    case OPT_EXECUTE_NUMBER:        /* --execute_number or -x */
-      ms_setting.exec_num= (int)strtol(optarg, (char **) NULL, 10);
-      if (ms_setting.exec_num <= 0)
-      {
-        fprintf(stderr, "Execute number must be greater than 0.:-)\n");
-        exit(1);
-      }
-      break;
-
-    case OPT_THREAD_NUMBER:     /* --threads or -T */
-      ms_setting.nthreads= (uint32_t)strtoul(optarg, (char **) NULL, 10);
-      if (ms_setting.nthreads <= 0)
-      {
-        fprintf(stderr, "Threads number must be greater than 0.:-)\n");
-        exit(1);
-      }
-      break;
-
-    case OPT_FIXED_LTH:         /* --fixed_size or -X */
-      ms_setting.fixed_value_size= (size_t)strtoull(optarg, (char **) NULL, 10);
-      if ((ms_setting.fixed_value_size <= 0)
-          || (ms_setting.fixed_value_size > MAX_VALUE_SIZE))
-      {
-        fprintf(stderr, "Value size must be between 0 and 1M.:-)\n");
-        exit(1);
-      }
-      break;
-
-    case OPT_VERIFY:        /* --verify or -v */
-      ms_setting.verify_percent= atof(optarg);
-      if ((ms_setting.verify_percent <= 0)
-          || (ms_setting.verify_percent > 1.0))
+    case OPT_UDP:
+      if (opt_test == GET_TEST)
       {
-        fprintf(stderr, "Data verification rate must be "
-                        "greater than 0 and less than 1.0. :-)\n");
+        fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
+                  "does not currently support get ops.\n");
         exit(1);
       }
+      opt_udp_io= 1;
       break;
-
-    case OPT_GETS_DIVISION:         /* --division or -d */
-      ms_setting.mult_key_num= (int)strtol(optarg, (char **) NULL, 10);
-      if (ms_setting.mult_key_num <= 0)
-      {
-        fprintf(stderr, "Multi-get key number must be greater than 0.:-)\n");
-        exit(1);
-      }
+    case OPT_BINARY:
+      opt_binary = 1;
       break;
-
-    case OPT_TIME:      /* --time or -t */
-      ms_setting.run_time= (int)ms_parse_time();
-      if (ms_setting.run_time == -1)
-      {
-        fprintf(stderr, "Please specify the run time. :-)\n"
-                        "'s' for second, 'm' for minute, 'h' for hour, "
-                        "'d' for day. e.g.: --time=24h (means 24 hours).\n");
-        exit(1);
-      }
-
-      if (ms_setting.run_time == 0)
-      {
-        fprintf(stderr, "Running time can not be 0. :-)\n");
-        exit(1);
-      }
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
       break;
-
-    case OPT_CONFIG_CMD:        /* --cfg_cmd or -F */
-      ms_setting.cfg_file= strdup(optarg);
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
       break;
-
-    case OPT_WINDOW_SIZE:       /* --win_size or -w */
-      ms_setting.win_size= (size_t)ms_parse_size();
-      if (ms_setting.win_size == (size_t)-1)
-      {
-        fprintf(
-          stderr,
-          "Please specify the item window size. :-)\n"
-          "e.g.: --win_size=10k (means 10k task window size).\n");
-        exit(1);
-      }
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
       break;
-
-    case OPT_UDP:       /* --udp or -U*/
-      ms_setting.udp= true;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
       break;
-
-    case OPT_EXPIRE:        /* --exp_verify or -e */
-      ms_setting.exp_ver_per= atof(optarg);
-      if ((ms_setting.exp_ver_per <= 0) || (ms_setting.exp_ver_per > 1.0))
-      {
-        fprintf(stderr, "Expire time verification rate must be "
-                        "greater than 0 and less than 1.0. :-)\n");
-        exit(1);
-      }
+    case OPT_SERVERS: /* --servers or -s */
+      opt_servers= strdup(optarg);
       break;
-
-    case OPT_OVERWRITE:         /* --overwrite or -o */
-      ms_setting.overwrite_percent= atof(optarg);
-      if ((ms_setting.overwrite_percent <= 0)
-          || (ms_setting.overwrite_percent > 1.0))
+    case OPT_SLAP_TEST:
+      if (!strcmp(optarg, "get"))
       {
-        fprintf(stderr, "Objects overwrite rate must be "
-                        "greater than 0 and less than 1.0. :-)\n");
-        exit(1);
+        if (opt_udp_io == 1)
+        {
+          fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
+                  "does not currently support get ops.\n");
+          exit(1);
+        }
+        opt_test= GET_TEST ;
       }
-      break;
-
-    case OPT_STAT_FREQ:         /* --stat_freq or -S */
-      ms_setting.stat_freq= (int)ms_parse_time();
-      if (ms_setting.stat_freq == -1)
+      else if (!strcmp(optarg, "set"))
+        opt_test= SET_TEST;
+      else if (!strcmp(optarg, "mget"))
       {
-        fprintf(stderr, "Please specify the frequency of dumping "
-                        "statistic information. :-)\n"
-                        "'s' for second, 'm' for minute, 'h' for hour, "
-                        "'d' for day. e.g.: --time=24h (means 24 hours).\n");
-        exit(1);
+        opt_test= MGET_TEST;
       }
-
-      if (ms_setting.stat_freq == 0)
+      else
       {
-        fprintf(stderr, "The frequency of dumping statistic information "
-                        "can not be 0. :-)\n");
+        fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
         exit(1);
       }
       break;
-
-    case OPT_SOCK_PER_CONN:         /* --conn_sock or -n */
-      ms_setting.sock_per_conn= (uint32_t)strtoul(optarg, (char **) NULL, 10);
-      if (ms_setting.sock_per_conn <= 0)
-      {
-        fprintf(stderr, "Number of socks of each concurrency "
-                        "must be greater than 0.:-)\n");
-        exit(1);
-      }
-      break;
-
-    case OPT_RECONNECT:     /* --reconnect or -R */
-      ms_setting.reconnect= true;
-      break;
-
-    case OPT_VERBOSE:       /* --verbose or -b */
-      ms_setting.verbose= true;
-      break;
-
-    case OPT_FACEBOOK_TEST:         /* --facebook or -a */
-      ms_setting.facebook_test= true;
+    case OPT_SLAP_CONCURRENCY:
+      opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10);
       break;
-
-    case OPT_BINARY_PROTOCOL:       /* --binary or -B */
-      ms_setting.binary_prot= true;
+    case OPT_SLAP_EXECUTE_NUMBER:
+      opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10);
       break;
-
-    case OPT_TPS:       /* --tps or -P */
-      ms_setting.expected_tps= (int)ms_parse_size();
-      if (ms_setting.expected_tps == -1)
-      {
-        fprintf(stderr,
-                "Please specify the item expected throughput. :-)\n"
-                "e.g.: --tps=10k (means 10k throughput).\n");
-        exit(1);
-      }
+    case OPT_SLAP_INITIAL_LOAD:
+      opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10);
       break;
-
-    case OPT_REP_WRITE_SRV:         /* --rep_write or -p */
-      ms_setting.rep_write_srv= (uint32_t)strtoul(optarg, (char **) NULL, 10);
-      if (ms_setting.rep_write_srv <= 0)
-      {
-        fprintf(stderr,
-                "Number of replication writing server must be greater "
-                "than 0.:-)\n");
-        exit(1);
-      }
-      break;
-
     case '?':
       /* getopt_long already printed an error message. */
       exit(1);
-
     default:
       abort();
-    } /* switch */
-  }
-} /* ms_options_parse */
-
-
-static int ms_check_para()
-{
-  if (ms_setting.srv_str == NULL)
-  {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-    {
-      ms_setting.srv_str= strdup(temp);
-    }
-    else
-    {
-      fprintf(stderr, "No Servers provided\n\n");
-      return -1;
     }
   }
 
-  if (ms_setting.nconns % (uint32_t)ms_setting.nthreads != 0)
-  {
-    fprintf(stderr, "Concurrency must be the multiples of threads count.\n");
-    return -1;
-  }
-
-  if (ms_setting.win_size % UNIT_ITEMS_COUNT != 0)
-  {
-    fprintf(stderr, "Window size must be the multiples of 1024.\n\n");
-    return -1;
-  }
-
-  return EXIT_SUCCESS;
-} /* ms_check_para */
-
-
-/* initialize the statistic structure */
-static void ms_statistic_init()
-{
-  pthread_mutex_init(&ms_statistic.stat_mutex, NULL);
-  ms_init_stats(&ms_statistic.get_stat, "Get");
-  ms_init_stats(&ms_statistic.set_stat, "Set");
-  ms_init_stats(&ms_statistic.total_stat, "Total");
-} /* ms_statistic_init */
-
+  if ((opt_test == GET_TEST || opt_test == MGET_TEST) && opt_createial_load == 0)
+    opt_createial_load= DEFAULT_INITIAL_LOAD;
 
-/* initialize the global state structure */
-static void ms_stats_init()
-{
-  memset(&ms_stats, 0, sizeof(ms_stats_t));
-  if (ms_setting.stat_freq > 0)
-  {
-    ms_statistic_init();
-  }
-} /* ms_stats_init */
+  if (opt_execute_number == 0)
+    opt_execute_number= DEFAULT_EXECUTE_NUMBER;
 
+  if (opt_concurrency == 0)
+    opt_concurrency= DEFAULT_CONCURRENCY;
+}
 
-/* use to output the statistic */
-static void ms_print_statistics(int in_time)
+void conclusions_print(conclusions_st *conclusion)
 {
-  int obj_size= (int)(ms_setting.avg_key_size + ms_setting.avg_val_size);
-
-  printf("\033[1;1H\033[2J\n");
-  ms_dump_format_stats(&ms_statistic.get_stat, in_time,
-                       ms_setting.stat_freq, obj_size);
-  ms_dump_format_stats(&ms_statistic.set_stat, in_time,
-                       ms_setting.stat_freq, obj_size);
-  ms_dump_format_stats(&ms_statistic.total_stat, in_time,
-                       ms_setting.stat_freq, obj_size);
-} /* ms_print_statistics */
-
+  printf("\tThreads connecting to servers %u\n", opt_concurrency);
+#ifdef NOT_FINISHED
+  printf("\tLoaded %u rows\n", conclusion->rows_loaded);
+  printf("\tRead %u rows\n", conclusion->rows_read);
+#endif
+  if (opt_test == SET_TEST)
+    printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000,
+           conclusion->load_time % 1000);
+  else
+    printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000,
+           conclusion->read_time % 1000);
+}
 
-/* used to print the states of memslap */
-static void ms_print_memslap_stats(struct timeval *start_time,
-                                   struct timeval *end_time)
+void *run_task(void *p)
 {
-  char buf[1024];
-  char *pos= buf;
-
-  pos+= snprintf(pos,
-                 sizeof(buf), "cmd_get: %lu\n",
-                 (unsigned long) ms_stats.cmd_get);
-  pos+= snprintf(pos,
-                 sizeof(buf) - (size_t)(pos -buf),
-                 "cmd_set: %lu\n",
-                 (unsigned long) ms_stats.cmd_set);
-  pos+= snprintf(pos,
-                 sizeof(buf) - (size_t)(pos -buf),
-                 "get_misses: %lu\n",
-                 (unsigned long) ms_stats.get_misses);
-
-  if (ms_setting.verify_percent > 0)
-  {
-    pos+= snprintf(pos,
-                   sizeof(buf) - (size_t)(pos -buf),
-                   "verify_misses: %lu\n",
-                   (unsigned long) ms_stats.vef_miss);
-    pos+= snprintf(pos,
-                   sizeof(buf) - (size_t)(pos -buf),
-                   "verify_failed: %lu\n",
-                   (unsigned long) ms_stats.vef_failed);
-  }
-
-  if (ms_setting.exp_ver_per > 0)
-  {
-    pos+= snprintf(pos,
-                   sizeof(buf) - (size_t)(pos -buf),
-                   "expired_get: %lu\n",
-                   (unsigned long) ms_stats.exp_get);
-    pos+= snprintf(pos,
-                   sizeof(buf) - (size_t)(pos -buf),
-                   "unexpired_unget: %lu\n",
-                   (unsigned long) ms_stats.unexp_unget);
-  }
+  thread_context_st *context= (thread_context_st *)p;
+  memcached_st *memc;
 
-  pos+= snprintf(pos,
-                 sizeof(buf) - (size_t)(pos -buf),
-                 "written_bytes: %lu\n",
-                 (unsigned long) ms_stats.bytes_written);
-  pos+= snprintf(pos,
-                 sizeof(buf) - (size_t)(pos -buf),
-                 "read_bytes: %lu\n",
-                 (unsigned long) ms_stats.bytes_read);
-  pos+= snprintf(pos,
-                 sizeof(buf) - (size_t)(pos -buf),
-                 "object_bytes: %lu\n",
-                 (unsigned long) ms_stats.obj_bytes);
-
-  if (ms_setting.udp || ms_setting.facebook_test)
-  {
-    pos+= snprintf(pos,
-                   sizeof(buf) - (size_t)(pos -buf),
-                   "packet_disorder: %lu\n",
-                   (unsigned long) ms_stats.pkt_disorder);
-    pos+= snprintf(pos,
-                   sizeof(buf) - (size_t)(pos -buf),
-                   "packet_drop: %lu\n",
-                   (unsigned long)ms_stats.pkt_drop);
-    pos+= snprintf(pos,
-                   sizeof(buf) - (size_t)(pos -buf),
-                   "udp_timeout: %lu\n",
-                   (unsigned long)ms_stats.udp_timeout);
-  }
-
-  if (ms_setting.stat_freq > 0)
-  {
-    ms_dump_stats(&ms_statistic.get_stat);
-    ms_dump_stats(&ms_statistic.set_stat);
-    ms_dump_stats(&ms_statistic.total_stat);
-  }
-
-  int64_t time_diff= ms_time_diff(start_time, end_time);
-  pos+= snprintf(pos,
-                 sizeof(buf) - (size_t)(pos -buf),
-                 "\nRun time: %.1fs Ops: %llu TPS: %.0Lf Net_rate: %.1fM/s\n",
-                 (double)time_diff / 1000000,
-                 (unsigned long long)(ms_stats.cmd_get + ms_stats.cmd_set),
-                 (ms_stats.cmd_get
-                  + ms_stats.cmd_set) / ((long double)time_diff / 1000000),
-                 (double)(
-                          ms_stats.bytes_written
-                          + ms_stats.bytes_read) / 1024 / 1024
-                 / ((double)time_diff / 1000000));
-  assert(pos <= buf);
-
-  fprintf(stdout, "%s", buf);
-  fflush(stdout);
-} /* ms_print_memslap_stats */
-
-
-/* the loop of the main thread, wait the work threads to complete */
-static void ms_monitor_slap_mode()
-{
-  int second= 0;
-  struct timeval start_time, end_time;
+  memc= context->memc;
 
-  /* Wait all the threads complete initialization. */
-  pthread_mutex_lock(&ms_global.init_lock.lock);
-  while (ms_global.init_lock.count < ms_setting.nthreads)
+  pthread_mutex_lock(&sleeper_mutex);
+  while (master_wakeup)
   {
-    pthread_cond_wait(&ms_global.init_lock.cond,
-                      &ms_global.init_lock.lock);
+    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
   }
-  pthread_mutex_unlock(&ms_global.init_lock.lock);
+  pthread_mutex_unlock(&sleeper_mutex);
 
-  /* only when there is no set operation it need warm up */
-  if (ms_setting.cmd_distr[CMD_SET].cmd_prop < PROP_ERROR)
+  /* Do Stuff */
+  switch (context->test)
   {
-    /* Wait all the connects complete warm up. */
-    pthread_mutex_lock(&ms_global.warmup_lock.lock);
-    while (ms_global.warmup_lock.count < ms_setting.nconns)
-    {
-      pthread_cond_wait(&ms_global.warmup_lock.cond, &ms_global.warmup_lock.lock);
-    }
-    pthread_mutex_unlock(&ms_global.warmup_lock.lock);
+  case SET_TEST:
+    assert(context->execute_pairs);
+    execute_set(memc, context->execute_pairs, context->execute_number);
+    break;
+  case GET_TEST:
+    execute_get(memc, context->initial_pairs, context->initial_number);
+    break;
+  case MGET_TEST:
+    execute_mget(memc, (const char*const*)context->keys, context->key_lengths,
+                 context->initial_number);
+    break;
+  default:
+    WATCHPOINT_ASSERT(context->test);
+    break;
   }
-  ms_global.finish_warmup= true;
 
-  /* running in "run time" mode, user specify run time */
-  if (ms_setting.run_time > 0)
-  {
-    gettimeofday(&start_time, NULL);
-    while (1)
-    {
-      sleep(1);
-      second++;
+  memcached_free(memc);
 
-      if ((ms_setting.stat_freq > 0) && (second % ms_setting.stat_freq == 0)
-          && (ms_stats.active_conns >= ms_setting.nconns)
-          && (ms_stats.active_conns <= INT_MAX))
-      {
-        ms_print_statistics(second);
-      }
+  if (context->execute_pairs)
+    pairs_free(context->execute_pairs);
 
-      if (ms_setting.run_time <= second)
-      {
-        ms_global.time_out= true;
-        break;
-      }
+  free(context);
 
-      /* all connections disconnect */
-      if ((second > 5) && (ms_stats.active_conns == 0))
-      {
-        break;
-      }
-    }
-    gettimeofday(&end_time, NULL);
-    sleep(1);       /* wait all threads clean up */
-  }
-  else
-  {
-    /* running in "execute number" mode, user specify execute number */
-    gettimeofday(&start_time, NULL);
-
-    /*
-     * We loop until we know that all connects have cleaned up.
-     */
-    pthread_mutex_lock(&ms_global.run_lock.lock);
-    while (ms_global.run_lock.count < ms_setting.nconns)
-    {
-      pthread_cond_wait(&ms_global.run_lock.cond, &ms_global.run_lock.lock);
-    }
-    pthread_mutex_unlock(&ms_global.run_lock.lock);
-
-    gettimeofday(&end_time, NULL);
-  }
+  pthread_mutex_lock(&counter_mutex);
+  thread_counter--;
+  pthread_cond_signal(&count_threshhold);
+  pthread_mutex_unlock(&counter_mutex);
 
-  ms_print_memslap_stats(&start_time, &end_time);
-} /* ms_monitor_slap_mode */
+  return NULL;
+}
 
+void flush_all(memcached_st *memc)
+{
+  memcached_flush(memc, 0);
+}
 
-/* the main function */
-int main(int argc, char *argv[])
+pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
+                           unsigned int *actual_loaded)
 {
-  srandom((unsigned int)time(NULL));
-  ms_global_struct_init();
+  memcached_st *memc_clone;
+  pairs_st *pairs;
 
-  /* initialization */
-  ms_setting_init_pre();
-  ms_options_parse(argc, argv);
-  if (ms_check_para())
-  {
-    ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
-    exit(1);
-  }
-  ms_setting_init_post();
-  ms_stats_init();
-  ms_thread_init();
+  memc_clone= memcached_clone(NULL, memc);
+  /* We always used non-blocking IO for load since it is faster */
+  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
 
-  /* waiting work thread complete its task */
-  ms_monitor_slap_mode();
+  pairs= pairs_generate(number_of, 400);
+  *actual_loaded= execute_set(memc_clone, pairs, number_of);
 
-  /* clean up */
-  ms_thread_cleanup();
-  ms_global_struct_destroy();
-  ms_setting_cleanup();
+  memcached_free(memc_clone);
 
-  return EXIT_SUCCESS;
-} /* main */
+  return pairs;
+}
index e97ff32a3408267e0e79b666e57d9d643693373a..2d1c28295947b2c3b893ffe28d09d7ef28190cbc 100644 (file)
@@ -61,6 +61,7 @@ GENERIC_PAGES= \
               memerror.pop \
               memflush.pop \
               memrm.pop \
+              memaslap.pop \
               memslap.pop \
               memstat.pop
 BUILT_SOURCES += ${GENERIC_PAGES}
@@ -287,6 +288,7 @@ HTML_FILES= \
            memerror.html \
            memflush.html \
            memrm.html \
+           memaslap.html \
            memslap.html \
            memstat.html
 
@@ -328,6 +330,7 @@ POD_FILES= \
           memerror.pod \
           memflush.pod \
           memrm.pod \
+          memaslap.pod \
           memslap.pod \
           memstat.pod
 EXTRA_DIST+= $(POD_FILES)
@@ -418,6 +421,7 @@ man_MANS = \
           memerror.1 \
           memflush.1 \
           memrm.1 \
+          memaslap.1 \
           memslap.1 \
           memstat.1
 
diff --git a/docs/memaslap.pod b/docs/memaslap.pod
new file mode 100644 (file)
index 0000000..c5de6f7
--- /dev/null
@@ -0,0 +1,1007 @@
+=head1 NAME
+
+memaslap - Load testing and benchmarking tool for memcached
+
+=head1 SYNOPSIS
+
+  memaslap [options]
+
+=head1 DESCRIPTION
+
+B<memaslap> is a load generation and benchmark tool for memcached(1)
+servers. It generates configurable workload such as threads, concurrencies, connections,
+run time, overwrite, miss rate, key size, value size, get/set proportion,
+expected throughput, and so on. Furthermore, it also supports data
+verification, expire-time verification, UDP, binary protocol, facebook test,
+replication test, multi-get and reconnection, etc.
+
+Memslap manages network connections like memcached with
+libevent. Each thread of memaslap is bound with a CPU core, all
+the threads don't communicate with each other, and there are several socket
+connections in each thread. Each connection keeps key size distribution,
+value size distribution, and command distribution by itself.
+
+You can specify servers via the B<--servers> option or via the
+environment variable C<MEMCACHED_SERVERS>.
+
+
+=head1 FEATURES
+
+Memslap is developed to for the following purposes:
+
+=over
+
+=item Manages network connections with libevent asynchronously.
+
+=item Set both TCP and UDP up to use non-blocking IO.
+
+=item Improves parallelism: higher performance in multi-threads environments.
+
+=item Improves time efficiency: faster processing speed.
+
+=item Generates key and value more efficiently; key size distribution and value size distribution are configurable.
+
+=item Supports get, multi-get, and set commands; command distribution is configurable.
+
+=item Supports controllable miss rate and overwrite rate.
+
+=item Supports data and expire-time verification.
+
+=item Supports dumping statistic information periodically. 
+
+=item Supports thousands of TCP connections.
+
+=item Supports binary protocol.
+
+=item Supports facebook test (set with TCP and multi-get with UDP) and replication test.
+
+=back
+
+=head1 DETAILS
+
+=head2 Effective implementation of network.
+
+For memaslap, both TCP and UDP use non-blocking network IO. All
+the network events are managed by libevent as memcached. The network module
+of memaslap is similar to memcached. Libevent can ensure
+memaslap can handle network very efficiently.
+
+=head2 Effective implementation of multi-threads and concurrency
+
+Memslap has the similar implementation of multi-threads to
+memcached. Memslap creates one or more self-governed threads;
+each thread is bound with one CPU core if the system supports setting CPU
+core affinity. 
+
+In addition, each thread has a libevent to manage the events of the network;
+each thread has one or more self-governed concurrencies; and each
+concurrency has one or more socket connections. All the concurrencies don’t
+communicate with each other even though they are in the same thread.
+
+Memslap can create thousands of socket connections, and each
+concurrency has tens of socket connections. Each concurrency randomly or
+sequentially selects one socket connection from its socket connection pool
+to run, so memaslap can ensure each concurrency handles one
+socket connection at any given time. Users can specify the number of
+concurrency and socket connections of each concurrency according to their
+expected workload. 
+
+=head2 Effective implementation of generating key and value
+
+In order to improve time efficiency and space efficiency, 
+memaslap creates a random characters table with 10M characters. All the
+suffixes of keys and values are generated from this random characters table.
+
+Memslap uses the offset in the character table and the length
+of the string to identify a string. It can save much memory.
+Each key contains two parts, a prefix and a suffix. The prefix is an
+uint64_t, 8 bytes. In order to verify the data set before, 
+memaslap need to ensure each key is unique, so it uses the prefix to identify
+a key. The prefix cannot include illegal characters, such as ‘\r’, ‘\n’,
+‘\0’ and ‘ ‘. And memaslap has an algorithm to ensure that. 
+
+Memslap doesn’t generate all the objects (key-value pairs) at
+the beginning. It only generates enough objects to fill the task window
+(default 10K objects) of each concurrency. Each object has the following
+basic information, key prefix, key suffix offset in the character table, key
+length, value offset in the character table, and value length.
+
+In the work process, each concurrency sequentially or randomly selects an
+object from the window to do set operation or get operation. At the same
+time, each concurrency kicks objects out of its window and adds new object
+into it. 
+
+=head2 Simple but useful task scheduling
+
+Memslap uses libevent to schedule all the concurrencies of
+threads, and each concurrency schedules tasks based on the local task
+window. Memslap assumes that if each concurrency keeps the same
+key distribution, value distribution and commands distribution, from
+outside, memaslap keeps all the distribution as a whole. 
+Each task window includes a lot of objects, each object stores its basic
+information, such as key, value, expire time, and so on. At any time, all
+the objects in the window keep the same and fixed key and value
+distribution. If an object is overwritten, the value of the object will be
+updated. Memslap verifies the data or expire-time according to
+the object information stored in the task window.
+
+Libevent selects which concurrency to handle based on a specific network
+event. Then the concurrency selects which command (get or set) to operate
+based on the command distribution. If it needs to kick out an old object and
+add a new object, in order to keep the same key and value distribution, the
+new object must have the same key length and value length. 
+
+If memcached server has two cache layers (memory and SSD), running
+memaslap with different window sizes can get different cache
+miss rates. If memaslap adds enough objects into the windows at
+the beginning, and the cache of memcached cannot store all the objects
+initialized, then memaslap will get some objects from the second
+cache layer. It causes the first cache layer to miss. So the user can
+specify the window size to get the expected miss rate of the first cache
+layer. 
+
+=head2 Useful implementation of multi-servers , UDP, TCP, multi-get and binary protocol
+
+Because each thread is self-governed, memaslap can assign
+different threads to handle different memcached servers. This is just one of
+the ways in which memaslap supports multiple servers. The only
+limitation is that the number of servers cannot be greater than the number
+of threads. The other way to support multiple servers is for replication
+test. Each concurrency has one socket connection to each memcached server.
+For the implementation, memaslap can set some objects to one
+memcached server, and get these objects from the other servers.
+
+By default, Memslap does single get. If the user specifies
+multi-get option, memaslap will collect enough get commands and
+pack and send the commands together. 
+
+Memslap supports both the ASCII protocol and binary protocol,
+but it runs on the ASCII protocol by default. 
+Memslap by default runs on the TCP protocol, but it also
+supports UDP. Because UDP is unreliable, dropped packages and out-of-order
+packages may occur. Memslap creates a memory buffer to handle
+these problems. Memslap tries to read all the response data of
+one command from the server and reorders the response data. If some packages
+get lost, the waiting timeout mechanism can ensure half-baked packages will
+be discarded and the next command will be sent.
+
+
+=head1 USAGE
+
+Below are some usage samples:
+
+=over 4
+
+=item memaslap -s 127.0.0.1:11211 -S 5s
+
+=item memaslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b
+
+=item memaslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2
+
+=item memaslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k
+
+=item memaslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40
+
+=item memaslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m
+
+=item memaslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2
+
+=back
+
+The user must specify one server at least to run memaslap. The
+rest of the parameters have default values, as shown below:
+
+Thread number = 1                    Concurrency = 16
+
+Run time = 600 seconds                Configuration file = NULL
+
+Key size = 64                         Value size = 1024
+
+Get/set = 9:1                         Window size = 10k
+
+Execute number = 0                   Single get = true
+
+Multi-get = false                      Number of sockets of each concurrency = 1
+
+Reconnect = false                     Data verification = false
+
+Expire-time verification = false           ASCII protocol = true
+
+Binary protocol = false                 Dumping statistic information
+
+periodically = false
+
+Overwrite proportion = 0%             UDP = false
+
+TCP = true                           Limit throughput = false
+
+Facebook test = false                  Replication test = false
+
+=head2 Key size, value size and command distribution.
+
+All the distributions are read from the configuration file specified by user
+with “—cfg_cmd” option. If the user does not specify a configuration file,
+memaslap will run with the default distribution (key size = 64,
+value size = 1024, get/set = 9:1). For information on how to edit the
+configuration file, refer to the “Configuration File” section.
+
+The minimum key size is 16 bytes; the maximum key size is 250 bytes. The
+precision of proportion is 0.001. The proportion of distribution will be
+rounded to 3 decimal places.
+
+The minimum value size is 1 bytes; the maximum value size is 1M bytes. The
+precision of proportion is 0.001. The proportion of distribution will be
+rounded to 3 decimal places.
+Currently, memaslap only supports set and get commands. And it
+supports 100% set and 100% get. For 100% get, it will preset some objects to
+the server.
+
+=head2 Multi-thread and concurrency
+
+The high performance of memaslap benefits from the special
+schedule of thread and concurrency. It’s important to specify the proper
+number of them. The default number of threads is 1; the default number of
+concurrency is 16. The user can use “—threads” and “--concurrency” to
+specify these variables.
+
+If the system supports setting CPU affinity and the number of threads
+specified by the user is greater than 1, memaslap will try to
+bind each thread to a different CPU core. So if you want to get the best
+performance memaslap, it is better to specify the number of
+thread equal to the number of CPU cores. The number of threads specified by
+the user can also be less or greater than the number of CPU cores. Because
+of the limitation of implementation, the number of concurrencies could be
+the multiple of the number of threads.
+
+1. For 8 CPU cores system
+
+For example:
+
+--threads=2 --concurrency=128
+
+--threads=8 --concurrency=128
+
+--threads=8 --concurrency=256
+
+--threads=12 --concurrency=144
+
+2. For 16 CPU cores system
+
+For example:
+
+--threads=8 --concurrency=128
+
+--threads=16 --concurrency=256
+
+--threads=16 --concurrency=512
+
+--threads=24 --concurrency=288
+
+The memaslap performs very well, when
+used to test the performance of memcached servers.
+Most of the time, the bottleneck is the network or
+the server. If for some reason the user wants to
+limit the performance of memaslap, there
+are two ways to do this:
+
+Decrease the number of threads and concurrencies.
+Use the option “--tps” that memaslap
+provides to limit the throughput. This option allows
+the user to get the expected throughput. For
+example, assume that the maximum throughput is 50
+kops/s for a specific configuration, you can specify
+the throughput equal to or less than the maximum
+throughput using “--tps” option.
+
+=head2 Window size
+
+Most of the time, the user does not need to specify the window size. The
+default window size is 10k. For Schooner Memcached, the user can specify
+different window sizes to get different cache miss rates based on the test
+case. Memslap supports cache miss rate between 0% and 100%.
+If you use this utility to test the performance of Schooner Memcached, you
+can specify a proper window size to get the expected cache miss rate. The
+formula for calculating window size is as follows:
+
+Assume that the key size is 128 bytes, and the value size is 2048 bytes, and
+concurrency=128.
+
+1. Small cache cache_size=1M, 100% cache miss (all data get from SSD).
+win_size=10k
+
+2. cache_size=4G
+
+(1). cache miss rate 0%
+
+win_size=8k
+
+(2). cache miss rate 5%
+
+win_size=11k
+
+3. cache_size=16G
+
+(1). cache miss rate 0%
+
+win_size=32k
+
+(2). cache miss
+
+rate 5%
+
+win_size=46k
+
+The formula for calculating window size for cache miss rate 0%: 
+
+cache_size / concurrency / (key_size + value_size) * 0.5
+
+The formula for calculating window size for cache miss rate 5%: 
+
+cache_size / concurrency / (key_size + value_size) * 0.7
+
+=head2 Verification
+
+Memslap supports both data verification and expire-time
+verification. The user can use "--verify=" or "-v" to specify the proportion
+of data verification. In theory, it supports 100% data verification. The
+user can use "--exp_verify=" or "-e" to specify the proportion of
+expire-time verification. In theory, it supports 100% expire-time
+verification. Specify the "--verbose" options to get more detailed error
+information.
+
+For example: --exp_verify=0.01 –verify=0.1 , it means that 1% of the objects 
+set with expire-time, 10% of the objects gotten will be verified. If the
+objects are gotten, memaslap will verify the expire-time and
+value. 
+
+=head2 multi-servers and multi-clients
+
+Memslap supports multi-servers based on self-governed thread.
+There is a limitation that the number of servers cannot be greater than the
+number of threads. Memslap assigns one thread to handle one
+server at least. The user can use the "--servers=" or "-s" option to specify
+multi-servers. 
+
+For example:
+
+--servers=10.1.1.1:11211,10.1.1.2:11212,10.1.1.3:11213 --threads=6 --concurrency=36
+
+The above command means that there are 6 threads, with each thread having 6
+concurrencies and that threads 0 and 3 handle server 0 (10.1.1.1); threads 1
+and 4 handle server 1 (10.1.1.2); and thread 2 and 5 handle server 2
+(10.1.1.3).  
+
+All the threads and concurrencies in memaslap are self-governed.
+
+So is memaslap. The user can start up several 
+memaslap instances. The user can run memaslap on different client
+machines to communicate with the same memcached server at the same. It is
+recommended that the user start different memaslap on different
+machines using the same configuration. 
+
+=head2 Run with execute number mode or time mode
+
+The default memaslap runs with time mode. The default run time
+is 10 minutes. If it times out, memaslap will exit. Do not
+specify both execute number mode and time mode at the same time; just
+specify one instead. 
+
+For example:
+
+--time=30s (It means the test will run 30 seconds.)
+
+--execute_number=100000 (It means that after running 100000 commands, the test will exit.)
+
+=head2 Dump statistic information periodically.
+
+The user can use "--stat_freq=" or "-S" to specify the frequency.
+
+For example:
+
+--stat_freq=20s
+
+Memslap will dump the statistics of the commands (get and set) at the frequency of every 20
+seconds. 
+
+For more information on the format of dumping statistic information, refer to “Format of Output” section.
+
+=head2 Multi-get
+
+The user can use "--division=" or "-d" to specify multi-get keys count.
+Memslap by default does single get with TCP. Memslap also supports data 
+verification and expire-time verification for multi-get. 
+
+Memslap supports multi-get with both TCP and UDP. Because of
+the different implementation of the ASCII protocol and binary protocol,
+there are some differences between the two. For the ASCII protocol,
+memaslap sends one “multi-get” to the server once. For the
+binary protocol, memaslap sends several single get commands
+together as “multi-get” to the server.
+
+=head2 UDP and TCP
+
+Memslap supports both UDP and TCP. For TCP,
+memaslap does not reconnect the memcached server if socket connections are
+lost. If all the socket connections are lost or memcached server crashes,
+memaslap will exit. If the user specifies the “--reconnect”
+option when socket connections are lost, it will reconnect them. 
+
+User can use “--udp” to enable the UDP feature, but UDP comes with some
+limitations: 
+
+UDP cannot set data more than 1400 bytes. 
+
+UDP is not supported by the binary protocol because the binary protocol of
+memcached does not support that.
+
+UDP doesn’t support reconnection.
+
+=head2 Facebook test
+
+Set data with TCP and multi-get with UDP. Specify the following options: 
+
+"--facebook --division=50"
+
+If you want to create thousands of TCP connections, specify the
+
+"--conn_sock=" option. 
+
+For example: --facebook --division=50 --conn_sock=200
+
+The above command means that memaslap will do facebook test,
+each concurrency has 200 socket TCP connections and one UDP socket.
+
+Memslap sets objects with the TCP socket, and multi-gets 50
+objects once with the UDP socket.
+
+If you specify "--division=50", the key size must be less that 25 bytes
+because the UDP packet size is 1400 bytes.
+
+=head2 Replication test
+
+For replication test, the user must specify at least two memcached servers.
+The user can use “—rep_write=” option to enable feature. 
+
+For example:
+
+--servers=10.1.1.1:11211,10.1.1.2:11212 –rep_write=2
+
+The above command means that there are 2 replication memcached servers,
+memaslap will set objects to both server 0 and server 1, get
+objects which are set to server 0 before from server 1, and also get objects
+which are set to server 1 before from server 0. If server 0 crashes,
+memaslap will only get objects from server 1. If server 0 comes
+back to life again, memaslap will reconnect server 0. If both
+server 0 and server 1 crash, memaslap will exit.
+
+=head2  Supports thousands of TCP connections
+
+Start memaslap with "--conn_sock=" or "-n" to enable this
+feature. Make sure that your system can support opening thousands of files
+and creating thousands of sockets. However, this feature does not support
+reconnection if sockets disconnect. 
+
+For example: 
+
+--threads=8 --concurrency=128 --conn_sock=128
+
+The above command means that memaslap starts up 8 threads, each
+thread has 16 concurrencies, each concurrency has 128 TCP socket
+connections, and the total number of TCP socket connections is 128 * 128 =
+16384.
+
+=head2 Supports binary protocol
+
+Start memaslap with "--binary" or "-B" options to enable this
+feature. It supports all the above features except UDP, because the latest
+memcached 1.3.3 does not implement binary UDP protocol.
+
+For example:
+
+--binary
+
+Since memcached 1.3.3 doesn't implement binary UDP protocol,
+memaslap does not support UDP. In addition, memcached 1.3.3 does not support
+multi-get. If you specify "--division=50" option, it just sends 50 get
+commands together as “mulit-get” to the server.
+
+=head1 Configuration file
+
+This section describes the format of the configuration file.  By default
+when no configuration file is specified memaslap reads the default
+one located at ~/.memaslap.cnf.
+
+Below is a sample configuration file:
+
+ ***************************************************************************
+ #comments should start with '#'
+ #key 
+ #start_len end_len proportion
+ #
+ #key length range from start_len to end_len
+ #start_len must be equal to or greater than 16
+ #end_len must be equal to or less than 250
+ #start_len must be equal to or greater than end_len
+ #memaslap will generate keys according to the key range
+ #proportion: indicates keys generated from one range accounts for the total
+ generated keys  
+ #
+ #example1: key range 16~100 accounts for 80%
+ #          key range 101~200 accounts for 10%
+ #          key range 201~250 accounts for 10%
+ #          total should be 1 (0.8+0.1+0.1 = 1)
+ #
+ #          16 100 0.8  
+ #          101 200 0.1
+ #          201 249 0.1
+ #
+ #example2: all keys length are 128 bytes
+ #
+ #          128 128 1 
+ key
+ 128 128 1  
+ #value 
+ #start_len end_len proportion
+ #
+ #value length range from start_len to end_len
+ #start_len must be equal to or greater than 1
+ #end_len must be equal to or less than 1M
+ #start_len must be equal to or greater than end_len
+ #memaslap will generate values according to the value range
+ #proportion: indicates values generated from one range accounts for the
+ total generated values  
+ #
+ #example1: value range 1~1000 accounts for 80%
+ #          value range 1001~10000 accounts for 10%
+ #          value range 10001~100000 accounts for 10%
+ #          total should be 1 (0.8+0.1+0.1 = 1)
+ #
+ #          1 1000 0.8  
+ #          1001 10000 0.1
+ #          10001 100000 0.1
+ #
+ #example2: all value length are 128 bytes
+ #
+ #          128 128 1 
+ value
+ 2048 2048 1
+ #cmd
+ #cmd_type cmd_proportion
+ #
+ #currently memaslap only supports get and set command.
+ #
+ #cmd_type
+ #set     0
+ #get     1
+ #
+ #example: set command accounts for 50%
+ #         get command accounts for 50%
+ #         total should be 1 (0.5+0.5 = 1)
+ #
+ #         cmd
+ #         0    0.5
+ #         1    0.5
+ cmd
+ 0    0.1
+ 1.0 0.9
+
+
+
+=head1 Format of output
+
+At the beginning, memaslap displays some configuration information as follows:
+
+=over 4
+
+=item servers : 127.0.0.1:11211
+
+=item threads count: 1
+
+=item concurrency: 16
+
+=item run time: 20s
+
+=item windows size: 10k
+
+=item set proportion: set_prop=0.10
+
+=item get proportion: get_prop=0.90
+
+=back
+
+=head2 Where
+
+=over 4
+
+=item servers : "servers"
+
+The servers used by memaslap.
+
+=item threads count
+
+The number of threads memaslap runs with.
+
+=item concurrency
+
+The number of concurrencies memaslap runs with.
+
+=item run time
+
+How long to run memaslap.
+
+=item windows size
+
+The task window size of each concurrency.
+
+=item set proportion
+
+The proportion of set command.
+
+=item get proportion
+
+The proportion of get command.
+
+=back
+
+The output of dynamic statistics is something like this:
+
+ ---------------------------------------------------------------------------------------------------------------------------------
+ Get Statistics
+ Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
+ Avg(us)  Std_dev    Geo_dist  
+ Period   5   345826  69165     65.3      0         27      2198     203
+ 95.43      177.29
+ Global  20  1257935  62896     71.8      0         26      3791     224
+ 117.79     192.60
+  
+ Set Statistics
+ Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
+ Avg(us)  Std_dev    Geo_dist  
+ Period   5    38425   7685      7.3       0         42      628     240
+ 88.05      220.21
+ Global   20   139780  6989      8.0       0         37      3790    253
+ 117.93     224.83
+  
+ Total Statistics
+ Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
+ Avg(us)  Std_dev    Geo_dist 
+ Period   5   384252   76850     72.5      0        27      2198     207
+ 94.72      181.18
+ Global  20  1397720   69886     79.7      0        26      3791     227
+ 117.93     195.60
+ ---------------------------------------------------------------------------------------------------------------------------------
+
+=head2 Where
+
+=over 4
+
+=item Get Statistics
+
+Statistics information of get command
+
+=item Set Statistics
+
+Statistics information of set command
+
+=item Total Statistics
+
+Statistics information of both get and set command
+
+=item Period
+
+Result within a period
+
+=item Global
+
+Accumulated results
+
+=item Ops
+
+Total operations
+
+=item TPS
+
+Throughput, operations/second
+
+=item Net
+
+The rate of network
+
+=item Get_miss
+
+How many objects can’t be gotten
+
+=item Min
+
+The minimum response time
+
+=item Max
+
+The maximum response time
+
+=item Avg: 
+
+The average response time
+
+=item Std_dev
+
+Standard deviation of response time
+
+=item Geo_dist
+
+Geometric distribution based on natural exponential function
+
+=back
+
+At the end, memaslap will output something like this:
+
+  ---------------------------------------------------------------------------------------------------------------------------------
+  Get Statistics (1257956 events)
+    Min:        26
+    Max:      3791
+    Avg:       224
+    Geo:    192.60
+    Std:    116.23
+                    Log2 Dist:
+                      4:        0       10    84490   215345
+                      8:   484890   459823    12543      824
+                     12:       31
+
+   Set Statistics (139782 events)
+      Min:        37
+      Max:      3790
+      Avg:       253
+      Geo:    224.84
+      Std:    116.83
+      Log2 Dist: 
+        4:        0        0     4200 16988
+        8:    50784    65574 2064      167
+        12:        5
+   
+    Total Statistics (1397738 events)
+        Min:        26
+        Max:      3791
+        Avg:       227
+        Geo:    195.60
+        Std:    116.60
+        Log2 Dist:
+          4:        0       10    88690   232333
+          8:   535674   525397    14607      991
+          12:       36
+
+  cmd_get: 1257969
+  cmd_set: 139785
+  get_misses: 0
+  verify_misses: 0
+  verify_failed: 0
+  expired_get: 0
+  unexpired_unget: 0
+  written_bytes: 242516030
+  read_bytes: 1003702556
+  object_bytes: 152086080
+  packet_disorder: 0
+  packet_drop: 0
+  udp_timeout: 0
+
+  Run time: 20.0s Ops: 1397754 TPS: 69817 Net_rate: 59.4M/s
+  ---------------------------------------------------------------------------------------------------------------------------------
+
+=head2 Where
+
+=over 4
+
+=item Get Statistics
+
+Get statistics of response time
+
+=item Set Statistics
+
+Set statistics of response time
+
+=item Total Statistics
+
+Both get and set statistics of response time
+
+=item Min
+
+The accumulated and minimum response time
+
+=item Max
+
+The accumulated and maximum response time
+
+=item Avg
+
+The accumulated and average response time
+
+=item Std
+
+Standard deviation of response time
+
+=item Log2 Dist
+
+Geometric distribution based on logarithm 2
+
+=item cmd_get
+
+Total get commands done
+
+=item cmd_set
+
+Total set commands done
+
+=item get_misses
+
+How many objects can’t be gotten from server
+
+=item verify_misses
+
+How many objects need to verify but can’t get them
+
+=item verify_failed
+
+How many objects with insistent value
+
+=item expired_get
+
+How many objects are expired but we get them
+
+=item unexpired_unget
+
+How many objects are unexpired but we can’t get them
+
+=item written_bytes
+
+Total written bytes
+
+=item read_bytes
+
+Total read bytes
+
+=item object_bytes
+
+Total object bytes
+
+=item packet_disorder
+
+How many UDP packages are disorder
+
+=item packet_drop
+
+How many UDP packages are lost
+
+=item udp_timeout
+
+How many times UDP time out happen
+
+=item Run time
+
+Total run time
+
+=item Ops
+
+Total operations 
+
+=item TPS
+
+Throughput, operations/second
+
+=item Net_rate
+
+The average rate of network
+
+=back
+
+=head1 OPTIONS
+
+-s, --servers=
+    List one or more servers to connect. Servers count must be less than
+    threads count. e.g.: --servers=localhost:1234,localhost:11211
+
+-T, --threads=
+    Number of threads to startup, better equal to CPU numbers. Default 8.
+
+-c, --concurrency=
+    Number of concurrency to simulate with load. Default 128.
+
+-n, --conn_sock=
+    Number of TCP socks per concurrency. Default 1.
+
+-x, --execute_number=
+    Number of operations(get and set) to execute for the
+    given test. Default 1000000.
+
+-t, --time=
+    How long the test to run, suffix: s-seconds, m-minutes, h-hours,
+    d-days e.g.: --time=2h.
+
+-F, --cfg_cmd=
+    Load the configure file to get command,key and value distribution list.
+
+-w, --win_size=
+    Task window size of each concurrency, suffix: K, M e.g.: --win_size=10k.
+    Default 10k.
+
+-X, --fixed_size=
+    Fixed length of value.
+
+-v, --verify=
+    The proportion of date verification, e.g.: --verify=0.01
+
+-d, --division=
+    Number of keys to multi-get once. Default 1, means single get.
+
+-S, --stat_freq=
+    Frequency of dumping statistic information. suffix: s-seconds,
+    m-minutes, e.g.: --resp_freq=10s.
+
+-e, --exp_verify=
+    The proportion of objects with expire time, e.g.: --exp_verify=0.01.
+    Default no object with expire time
+
+-o, --overwrite=
+    The proportion of objects need overwrite, e.g.: --overwrite=0.01.
+    Default never overwrite object.
+
+-R, --reconnect 
+    Reconnect support, when connection is closed it will be reconnected.
+
+-U, --udp 
+    UDP support, default memaslap uses TCP, TCP port and UDP port of
+    server must be same.
+
+-a, --facebook 
+    Whether it enables facebook test feature, set with TCP and multi-get with UDP.
+
+-B, --binary 
+    Whether it enables binary protocol. Default with ASCII protocol.
+
+-P, --tps=
+    Expected throughput, suffix: K, e.g.: --tps=10k.
+
+-p, --rep_write=
+    The first nth servers can write data, e.g.: --rep_write=2.
+
+-b, --verbose 
+    Whether it outputs detailed information when verification fails.
+
+-h, --help 
+    Display this message and then exit.
+
+-V, --version 
+    Display the version of the application and then exit.
+
+=head1 EXAMPLES
+
+memaslap -s 127.0.0.1:11211 -S 5s
+
+memaslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b
+
+memaslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2
+
+memaslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k
+
+memaslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40
+
+memaslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m
+
+memaslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2
+
+=head1 HOME
+
+To find out more information please check:
+L<http://launchpad.org/libmemcached>
+
+=head1 AUTHORS
+
+Mingqiang Zhuang E<lt>mingqiangzhuang@hengtiansoft.comE<gt> (Schooner Technolgy)
+Brian Aker, E<lt>brian@tangent.orgE<gt>
+
+=head1 SEE ALSO
+
+memcached(1) libmemcached(3)
+
+=cut
+
index 462f67fe944489cd2bf2146bdd3b88900e13e263..43f714ccadc44ed6b8568ba2f8c2fa93eacdd75c 100644 (file)
@@ -9,994 +9,20 @@ memslap - Load testing and benchmarking tool for memcached
 =head1 DESCRIPTION
 
 B<memslap> is a load generation and benchmark tool for memcached(1)
-servers. It generates configurable workload such as threads, concurrencies, connections,
-run time, overwrite, miss rate, key size, value size, get/set proportion,
-expected throughput, and so on. Furthermore, it also supports data
-verification, expire-time verification, UDP, binary protocol, facebook test,
-replication test, multi-get and reconnection, etc.
-
-Memslap manages network connections like memcached with
-libevent. Each thread of memslap is bound with a CPU core, all
-the threads don't communicate with each other, and there are several socket
-connections in each thread. Each connection keeps key size distribution,
-value size distribution, and command distribution by itself.
+servers. It simulates loads on memcached server clusters.
 
 You can specify servers via the B<--servers> option or via the
 environment variable C<MEMCACHED_SERVERS>.
 
-
-=head1 FEATURES
-
-Memslap is developed to for the following purposes:
-
-=over
-
-=item Manages network connections with libevent asynchronously.
-
-=item Set both TCP and UDP up to use non-blocking IO.
-
-=item Improves parallelism: higher performance in multi-threads environments.
-
-=item Improves time efficiency: faster processing speed.
-
-=item Generates key and value more efficiently; key size distribution and value size distribution are configurable.
-
-=item Supports get, multi-get, and set commands; command distribution is configurable.
-
-=item Supports controllable miss rate and overwrite rate.
-
-=item Supports data and expire-time verification.
-
-=item Supports dumping statistic information periodically. 
-
-=item Supports thousands of TCP connections.
-
-=item Supports binary protocol.
-
-=item Supports facebook test (set with TCP and multi-get with UDP) and replication test.
-
-=back
-
-=head1 DETAILS
-
-=head2 Effective implementation of network.
-
-For memslap, both TCP and UDP use non-blocking network IO. All
-the network events are managed by libevent as memcached. The network module
-of memslap is similar to memcached. Libevent can ensure
-memslap can handle network very efficiently.
-
-=head2 Effective implementation of multi-threads and concurrency
-
-Memslap has the similar implementation of multi-threads to
-memcached. Memslap creates one or more self-governed threads;
-each thread is bound with one CPU core if the system supports setting CPU
-core affinity. 
-
-In addition, each thread has a libevent to manage the events of the network;
-each thread has one or more self-governed concurrencies; and each
-concurrency has one or more socket connections. All the concurrencies don’t
-communicate with each other even though they are in the same thread.
-
-Memslap can create thousands of socket connections, and each
-concurrency has tens of socket connections. Each concurrency randomly or
-sequentially selects one socket connection from its socket connection pool
-to run, so memslap can ensure each concurrency handles one
-socket connection at any given time. Users can specify the number of
-concurrency and socket connections of each concurrency according to their
-expected workload. 
-
-=head2 Effective implementation of generating key and value
-
-In order to improve time efficiency and space efficiency, 
-memslap creates a random characters table with 10M characters. All the
-suffixes of keys and values are generated from this random characters table.
-
-Memslap uses the offset in the character table and the length
-of the string to identify a string. It can save much memory.
-Each key contains two parts, a prefix and a suffix. The prefix is an
-uint64_t, 8 bytes. In order to verify the data set before, 
-memslap need to ensure each key is unique, so it uses the prefix to identify
-a key. The prefix cannot include illegal characters, such as ‘\r’, ‘\n’,
-‘\0’ and ‘ ‘. And memslap has an algorithm to ensure that. 
-
-Memslap doesn’t generate all the objects (key-value pairs) at
-the beginning. It only generates enough objects to fill the task window
-(default 10K objects) of each concurrency. Each object has the following
-basic information, key prefix, key suffix offset in the character table, key
-length, value offset in the character table, and value length.
-
-In the work process, each concurrency sequentially or randomly selects an
-object from the window to do set operation or get operation. At the same
-time, each concurrency kicks objects out of its window and adds new object
-into it. 
-
-=head2 Simple but useful task scheduling
-
-Memslap uses libevent to schedule all the concurrencies of
-threads, and each concurrency schedules tasks based on the local task
-window. Memslap assumes that if each concurrency keeps the same
-key distribution, value distribution and commands distribution, from
-outside, memslap keeps all the distribution as a whole. 
-Each task window includes a lot of objects, each object stores its basic
-information, such as key, value, expire time, and so on. At any time, all
-the objects in the window keep the same and fixed key and value
-distribution. If an object is overwritten, the value of the object will be
-updated. Memslap verifies the data or expire-time according to
-the object information stored in the task window.
-
-Libevent selects which concurrency to handle based on a specific network
-event. Then the concurrency selects which command (get or set) to operate
-based on the command distribution. If it needs to kick out an old object and
-add a new object, in order to keep the same key and value distribution, the
-new object must have the same key length and value length. 
-
-If memcached server has two cache layers (memory and SSD), running
-memslap with different window sizes can get different cache
-miss rates. If memslap adds enough objects into the windows at
-the beginning, and the cache of memcached cannot store all the objects
-initialized, then memslap will get some objects from the second
-cache layer. It causes the first cache layer to miss. So the user can
-specify the window size to get the expected miss rate of the first cache
-layer. 
-
-=head2 Useful implementation of multi-servers , UDP, TCP, multi-get and binary protocol
-
-Because each thread is self-governed, memslap can assign
-different threads to handle different memcached servers. This is just one of
-the ways in which memslap supports multiple servers. The only
-limitation is that the number of servers cannot be greater than the number
-of threads. The other way to support multiple servers is for replication
-test. Each concurrency has one socket connection to each memcached server.
-For the implementation, memslap can set some objects to one
-memcached server, and get these objects from the other servers.
-
-By default, Memslap does single get. If the user specifies
-multi-get option, memslap will collect enough get commands and
-pack and send the commands together. 
-
-Memslap supports both the ASCII protocol and binary protocol,
-but it runs on the ASCII protocol by default. 
-Memslap by default runs on the TCP protocol, but it also
-supports UDP. Because UDP is unreliable, dropped packages and out-of-order
-packages may occur. Memslap creates a memory buffer to handle
-these problems. Memslap tries to read all the response data of
-one command from the server and reorders the response data. If some packages
-get lost, the waiting timeout mechanism can ensure half-baked packages will
-be discarded and the next command will be sent.
-
-
-=head1 USAGE
-
-Below are some usage samples:
-
-=over 4
-
-=item memslap -s 127.0.0.1:11211 -S 5s
-
-=item memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b
-
-=item memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2
-
-=item memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k
-
-=item memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40
-
-=item memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m
-
-=item memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2
-
-=back
-
-The user must specify one server at least to run memslap. The
-rest of the parameters have default values, as shown below:
-
-Thread number = 1                    Concurrency = 16
-
-Run time = 600 seconds                Configuration file = NULL
-
-Key size = 64                         Value size = 1024
-
-Get/set = 9:1                         Window size = 10k
-
-Execute number = 0                   Single get = true
-
-Multi-get = false                      Number of sockets of each concurrency = 1
-
-Reconnect = false                     Data verification = false
-
-Expire-time verification = false           ASCII protocol = true
-
-Binary protocol = false                 Dumping statistic information
-
-periodically = false
-
-Overwrite proportion = 0%             UDP = false
-
-TCP = true                           Limit throughput = false
-
-Facebook test = false                  Replication test = false
-
-=head2 Key size, value size and command distribution.
-
-All the distributions are read from the configuration file specified by user
-with “—cfg_cmd” option. If the user does not specify a configuration file,
-memslap will run with the default distribution (key size = 64,
-value size = 1024, get/set = 9:1). For information on how to edit the
-configuration file, refer to the “Configuration File” section.
-
-The minimum key size is 16 bytes; the maximum key size is 250 bytes. The
-precision of proportion is 0.001. The proportion of distribution will be
-rounded to 3 decimal places.
-
-The minimum value size is 1 bytes; the maximum value size is 1M bytes. The
-precision of proportion is 0.001. The proportion of distribution will be
-rounded to 3 decimal places.
-Currently, memslap only supports set and get commands. And it
-supports 100% set and 100% get. For 100% get, it will preset some objects to
-the server.
-
-=head2 Multi-thread and concurrency
-
-The high performance of memslap benefits from the special
-schedule of thread and concurrency. It’s important to specify the proper
-number of them. The default number of threads is 1; the default number of
-concurrency is 16. The user can use “—threads” and “--concurrency” to
-specify these variables.
-
-If the system supports setting CPU affinity and the number of threads
-specified by the user is greater than 1, memslap will try to
-bind each thread to a different CPU core. So if you want to get the best
-performance memslap, it is better to specify the number of
-thread equal to the number of CPU cores. The number of threads specified by
-the user can also be less or greater than the number of CPU cores. Because
-of the limitation of implementation, the number of concurrencies could be
-the multiple of the number of threads.
-
-1. For 8 CPU cores system
-
-For example:
-
---threads=2 --concurrency=128
-
---threads=8 --concurrency=128
-
---threads=8 --concurrency=256
-
---threads=12 --concurrency=144
-
-2. For 16 CPU cores system
-
-For example:
-
---threads=8 --concurrency=128
-
---threads=16 --concurrency=256
-
---threads=16 --concurrency=512
-
---threads=24 --concurrency=288
-
-The memslap performs very well, when
-used to test the performance of memcached servers.
-Most of the time, the bottleneck is the network or
-the server. If for some reason the user wants to
-limit the performance of memslap, there
-are two ways to do this:
-
-Decrease the number of threads and concurrencies.
-Use the option “--tps” that memslap
-provides to limit the throughput. This option allows
-the user to get the expected throughput. For
-example, assume that the maximum throughput is 50
-kops/s for a specific configuration, you can specify
-the throughput equal to or less than the maximum
-throughput using “--tps” option.
-
-=head2 Window size
-
-Most of the time, the user does not need to specify the window size. The
-default window size is 10k. For Schooner Memcached, the user can specify
-different window sizes to get different cache miss rates based on the test
-case. Memslap supports cache miss rate between 0% and 100%.
-If you use this utility to test the performance of Schooner Memcached, you
-can specify a proper window size to get the expected cache miss rate. The
-formula for calculating window size is as follows:
-
-Assume that the key size is 128 bytes, and the value size is 2048 bytes, and
-concurrency=128.
-
-1. Small cache cache_size=1M, 100% cache miss (all data get from SSD).
-win_size=10k
-
-2. cache_size=4G
-
-(1). cache miss rate 0%
-
-win_size=8k
-
-(2). cache miss rate 5%
-
-win_size=11k
-
-3. cache_size=16G
-
-(1). cache miss rate 0%
-
-win_size=32k
-
-(2). cache miss
-
-rate 5%
-
-win_size=46k
-
-The formula for calculating window size for cache miss rate 0%: 
-
-cache_size / concurrency / (key_size + value_size) * 0.5
-
-The formula for calculating window size for cache miss rate 5%: 
-
-cache_size / concurrency / (key_size + value_size) * 0.7
-
-=head2 Verification
-
-Memslap supports both data verification and expire-time
-verification. The user can use "--verify=" or "-v" to specify the proportion
-of data verification. In theory, it supports 100% data verification. The
-user can use "--exp_verify=" or "-e" to specify the proportion of
-expire-time verification. In theory, it supports 100% expire-time
-verification. Specify the "--verbose" options to get more detailed error
-information.
-
-For example: --exp_verify=0.01 –verify=0.1 , it means that 1% of the objects 
-set with expire-time, 10% of the objects gotten will be verified. If the
-objects are gotten, memslap will verify the expire-time and
-value. 
-
-=head2 multi-servers and multi-clients
-
-Memslap supports multi-servers based on self-governed thread.
-There is a limitation that the number of servers cannot be greater than the
-number of threads. Memslap assigns one thread to handle one
-server at least. The user can use the "--servers=" or "-s" option to specify
-multi-servers. 
-
-For example:
-
---servers=10.1.1.1:11211,10.1.1.2:11212,10.1.1.3:11213 --threads=6 --concurrency=36
-
-The above command means that there are 6 threads, with each thread having 6
-concurrencies and that threads 0 and 3 handle server 0 (10.1.1.1); threads 1
-and 4 handle server 1 (10.1.1.2); and thread 2 and 5 handle server 2
-(10.1.1.3).  
-
-All the threads and concurrencies in memslap are self-governed.
-
-So is memslap. The user can start up several 
-memslap instances. The user can run memslap on different client
-machines to communicate with the same memcached server at the same. It is
-recommended that the user start different memslap on different
-machines using the same configuration. 
-
-=head2 Run with execute number mode or time mode
-
-The default memslap runs with time mode. The default run time
-is 10 minutes. If it times out, memslap will exit. Do not
-specify both execute number mode and time mode at the same time; just
-specify one instead. 
-
-For example:
-
---time=30s (It means the test will run 30 seconds.)
-
---execute_number=100000 (It means that after running 100000 commands, the test will exit.)
-
-=head2 Dump statistic information periodically.
-
-The user can use "--stat_freq=" or "-S" to specify the frequency.
-
-For example:
-
---stat_freq=20s
-
-Memslap will dump the statistics of the commands (get and set) at the frequency of every 20
-seconds. 
-
-For more information on the format of dumping statistic information, refer to “Format of Output” section.
-
-=head2 Multi-get
-
-The user can use "--division=" or "-d" to specify multi-get keys count.
-Memslap by default does single get with TCP. Memslap also supports data 
-verification and expire-time verification for multi-get. 
-
-Memslap supports multi-get with both TCP and UDP. Because of
-the different implementation of the ASCII protocol and binary protocol,
-there are some differences between the two. For the ASCII protocol,
-memslap sends one “multi-get” to the server once. For the
-binary protocol, memslap sends several single get commands
-together as “multi-get” to the server.
-
-=head2 UDP and TCP
-
-Memslap supports both UDP and TCP. For TCP,
-memslap does not reconnect the memcached server if socket connections are
-lost. If all the socket connections are lost or memcached server crashes,
-memslap will exit. If the user specifies the “--reconnect”
-option when socket connections are lost, it will reconnect them. 
-
-User can use “--udp” to enable the UDP feature, but UDP comes with some
-limitations: 
-
-UDP cannot set data more than 1400 bytes. 
-
-UDP is not supported by the binary protocol because the binary protocol of
-memcached does not support that.
-
-UDP doesn’t support reconnection.
-
-=head2 Facebook test
-
-Set data with TCP and multi-get with UDP. Specify the following options: 
-
-"--facebook --division=50"
-
-If you want to create thousands of TCP connections, specify the
-
-"--conn_sock=" option. 
-
-For example: --facebook --division=50 --conn_sock=200
-
-The above command means that memslap will do facebook test,
-each concurrency has 200 socket TCP connections and one UDP socket.
-
-Memslap sets objects with the TCP socket, and multi-gets 50
-objects once with the UDP socket.
-
-If you specify "--division=50", the key size must be less that 25 bytes
-because the UDP packet size is 1400 bytes.
-
-=head2 Replication test
-
-For replication test, the user must specify at least two memcached servers.
-The user can use “—rep_write=” option to enable feature. 
-
-For example:
-
---servers=10.1.1.1:11211,10.1.1.2:11212 –rep_write=2
-
-The above command means that there are 2 replication memcached servers,
-memslap will set objects to both server 0 and server 1, get
-objects which are set to server 0 before from server 1, and also get objects
-which are set to server 1 before from server 0. If server 0 crashes,
-memslap will only get objects from server 1. If server 0 comes
-back to life again, memslap will reconnect server 0. If both
-server 0 and server 1 crash, memslap will exit.
-
-=head2  Supports thousands of TCP connections
-
-Start memslap with "--conn_sock=" or "-n" to enable this
-feature. Make sure that your system can support opening thousands of files
-and creating thousands of sockets. However, this feature does not support
-reconnection if sockets disconnect. 
-
-For example: 
-
---threads=8 --concurrency=128 --conn_sock=128
-
-The above command means that memslap starts up 8 threads, each
-thread has 16 concurrencies, each concurrency has 128 TCP socket
-connections, and the total number of TCP socket connections is 128 * 128 =
-16384.
-
-=head2 Supports binary protocol
-
-Start memslap with "--binary" or "-B" options to enable this
-feature. It supports all the above features except UDP, because the latest
-memcached 1.3.3 does not implement binary UDP protocol.
-
-For example:
-
---binary
-
-Since memcached 1.3.3 doesn't implement binary UDP protocol,
-memslap does not support UDP. In addition, memcached 1.3.3 does not support
-multi-get. If you specify "--division=50" option, it just sends 50 get
-commands together as “mulit-get” to the server.
-
-=head1 Configuration file
-
-This section describes the format of the configuration file.  By default
-when no configuration file is specified memslap reads the default
-one located at ~/.memslap.cnf.
-
-Below is a sample configuration file:
-
- ***************************************************************************
- #comments should start with '#'
- #key 
- #start_len end_len proportion
- #
- #key length range from start_len to end_len
- #start_len must be equal to or greater than 16
- #end_len must be equal to or less than 250
- #start_len must be equal to or greater than end_len
- #memslap will generate keys according to the key range
- #proportion: indicates keys generated from one range accounts for the total
- generated keys  
- #
- #example1: key range 16~100 accounts for 80%
- #          key range 101~200 accounts for 10%
- #          key range 201~250 accounts for 10%
- #          total should be 1 (0.8+0.1+0.1 = 1)
- #
- #          16 100 0.8  
- #          101 200 0.1
- #          201 249 0.1
- #
- #example2: all keys length are 128 bytes
- #
- #          128 128 1 
- key
- 128 128 1  
- #value 
- #start_len end_len proportion
- #
- #value length range from start_len to end_len
- #start_len must be equal to or greater than 1
- #end_len must be equal to or less than 1M
- #start_len must be equal to or greater than end_len
- #memslap will generate values according to the value range
- #proportion: indicates values generated from one range accounts for the
- total generated values  
- #
- #example1: value range 1~1000 accounts for 80%
- #          value range 1001~10000 accounts for 10%
- #          value range 10001~100000 accounts for 10%
- #          total should be 1 (0.8+0.1+0.1 = 1)
- #
- #          1 1000 0.8  
- #          1001 10000 0.1
- #          10001 100000 0.1
- #
- #example2: all value length are 128 bytes
- #
- #          128 128 1 
- value
- 2048 2048 1
- #cmd
- #cmd_type cmd_proportion
- #
- #currently memslap only supports get and set command.
- #
- #cmd_type
- #set     0
- #get     1
- #
- #example: set command accounts for 50%
- #         get command accounts for 50%
- #         total should be 1 (0.5+0.5 = 1)
- #
- #         cmd
- #         0    0.5
- #         1    0.5
- cmd
- 0    0.1
- 1.0 0.9
-
-
-
-=head1 Format of output
-
-At the beginning, memslap displays some configuration information as follows:
-
-=over 4
-
-=item servers : 127.0.0.1:11211
-
-=item threads count: 1
-
-=item concurrency: 16
-
-=item run time: 20s
-
-=item windows size: 10k
-
-=item set proportion: set_prop=0.10
-
-=item get proportion: get_prop=0.90
-
-=back
-
-=head2 Where
-
-=over 4
-
-=item servers : "servers"
-
-The servers used by memslap.
-
-=item threads count
-
-The number of threads memslap runs with.
-
-=item concurrency
-
-The number of concurrencies memslap runs with.
-
-=item run time
-
-How long to run memslap.
-
-=item windows size
-
-The task window size of each concurrency.
-
-=item set proportion
-
-The proportion of set command.
-
-=item get proportion
-
-The proportion of get command.
-
-=back
-
-The output of dynamic statistics is something like this:
-
- ---------------------------------------------------------------------------------------------------------------------------------
- Get Statistics
- Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
- Avg(us)  Std_dev    Geo_dist  
- Period   5   345826  69165     65.3      0         27      2198     203
- 95.43      177.29
- Global  20  1257935  62896     71.8      0         26      3791     224
- 117.79     192.60
-  
- Set Statistics
- Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
- Avg(us)  Std_dev    Geo_dist  
- Period   5    38425   7685      7.3       0         42      628     240
- 88.05      220.21
- Global   20   139780  6989      8.0       0         37      3790    253
- 117.93     224.83
-  
- Total Statistics
- Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
- Avg(us)  Std_dev    Geo_dist 
- Period   5   384252   76850     72.5      0        27      2198     207
- 94.72      181.18
- Global  20  1397720   69886     79.7      0        26      3791     227
- 117.93     195.60
- ---------------------------------------------------------------------------------------------------------------------------------
-
-=head2 Where
-
-=over 4
-
-=item Get Statistics
-
-Statistics information of get command
-
-=item Set Statistics
-
-Statistics information of set command
-
-=item Total Statistics
-
-Statistics information of both get and set command
-
-=item Period
-
-Result within a period
-
-=item Global
-
-Accumulated results
-
-=item Ops
-
-Total operations
-
-=item TPS
-
-Throughput, operations/second
-
-=item Net
-
-The rate of network
-
-=item Get_miss
-
-How many objects can’t be gotten
-
-=item Min
-
-The minimum response time
-
-=item Max
-
-The maximum response time
-
-=item Avg: 
-
-The average response time
-
-=item Std_dev
-
-Standard deviation of response time
-
-=item Geo_dist
-
-Geometric distribution based on natural exponential function
-
-=back
-
-At the end, memslap will output something like this:
-
-  ---------------------------------------------------------------------------------------------------------------------------------
-  Get Statistics (1257956 events)
-    Min:        26
-    Max:      3791
-    Avg:       224
-    Geo:    192.60
-    Std:    116.23
-                    Log2 Dist:
-                      4:        0       10    84490   215345
-                      8:   484890   459823    12543      824
-                     12:       31
-
-   Set Statistics (139782 events)
-      Min:        37
-      Max:      3790
-      Avg:       253
-      Geo:    224.84
-      Std:    116.83
-      Log2 Dist: 
-        4:        0        0     4200 16988
-        8:    50784    65574 2064      167
-        12:        5
-   
-    Total Statistics (1397738 events)
-        Min:        26
-        Max:      3791
-        Avg:       227
-        Geo:    195.60
-        Std:    116.60
-        Log2 Dist:
-          4:        0       10    88690   232333
-          8:   535674   525397    14607      991
-          12:       36
-
-  cmd_get: 1257969
-  cmd_set: 139785
-  get_misses: 0
-  verify_misses: 0
-  verify_failed: 0
-  expired_get: 0
-  unexpired_unget: 0
-  written_bytes: 242516030
-  read_bytes: 1003702556
-  object_bytes: 152086080
-  packet_disorder: 0
-  packet_drop: 0
-  udp_timeout: 0
-
-  Run time: 20.0s Ops: 1397754 TPS: 69817 Net_rate: 59.4M/s
-  ---------------------------------------------------------------------------------------------------------------------------------
-
-=head2 Where
-
-=over 4
-
-=item Get Statistics
-
-Get statistics of response time
-
-=item Set Statistics
-
-Set statistics of response time
-
-=item Total Statistics
-
-Both get and set statistics of response time
-
-=item Min
-
-The accumulated and minimum response time
-
-=item Max
-
-The accumulated and maximum response time
-
-=item Avg
-
-The accumulated and average response time
-
-=item Std
-
-Standard deviation of response time
-
-=item Log2 Dist
-
-Geometric distribution based on logarithm 2
-
-=item cmd_get
-
-Total get commands done
-
-=item cmd_set
-
-Total set commands done
-
-=item get_misses
-
-How many objects can’t be gotten from server
-
-=item verify_misses
-
-How many objects need to verify but can’t get them
-
-=item verify_failed
-
-How many objects with insistent value
-
-=item expired_get
-
-How many objects are expired but we get them
-
-=item unexpired_unget
-
-How many objects are unexpired but we can’t get them
-
-=item written_bytes
-
-Total written bytes
-
-=item read_bytes
-
-Total read bytes
-
-=item object_bytes
-
-Total object bytes
-
-=item packet_disorder
-
-How many UDP packages are disorder
-
-=item packet_drop
-
-How many UDP packages are lost
-
-=item udp_timeout
-
-How many times UDP time out happen
-
-=item Run time
-
-Total run time
-
-=item Ops
-
-Total operations 
-
-=item TPS
-
-Throughput, operations/second
-
-=item Net_rate
-
-The average rate of network
-
-=back
-
-=head1 OPTIONS
-
--s, --servers=
-    List one or more servers to connect. Servers count must be less than
-    threads count. e.g.: --servers=localhost:1234,localhost:11211
-
--T, --threads=
-    Number of threads to startup, better equal to CPU numbers. Default 8.
-
--c, --concurrency=
-    Number of concurrency to simulate with load. Default 128.
-
--n, --conn_sock=
-    Number of TCP socks per concurrency. Default 1.
-
--x, --execute_number=
-    Number of operations(get and set) to execute for the
-    given test. Default 1000000.
-
--t, --time=
-    How long the test to run, suffix: s-seconds, m-minutes, h-hours,
-    d-days e.g.: --time=2h.
-
--F, --cfg_cmd=
-    Load the configure file to get command,key and value distribution list.
-
--w, --win_size=
-    Task window size of each concurrency, suffix: K, M e.g.: --win_size=10k.
-    Default 10k.
-
--X, --fixed_size=
-    Fixed length of value.
-
--v, --verify=
-    The proportion of date verification, e.g.: --verify=0.01
-
--d, --division=
-    Number of keys to multi-get once. Default 1, means single get.
-
--S, --stat_freq=
-    Frequency of dumping statistic information. suffix: s-seconds,
-    m-minutes, e.g.: --resp_freq=10s.
-
--e, --exp_verify=
-    The proportion of objects with expire time, e.g.: --exp_verify=0.01.
-    Default no object with expire time
-
--o, --overwrite=
-    The proportion of objects need overwrite, e.g.: --overwrite=0.01.
-    Default never overwrite object.
-
--R, --reconnect 
-    Reconnect support, when connection is closed it will be reconnected.
-
--U, --udp 
-    UDP support, default memslap uses TCP, TCP port and UDP port of
-    server must be same.
-
--a, --facebook 
-    Whether it enables facebook test feature, set with TCP and multi-get with UDP.
-
--B, --binary 
-    Whether it enables binary protocol. Default with ASCII protocol.
-
--P, --tps=
-    Expected throughput, suffix: K, e.g.: --tps=10k.
-
--p, --rep_write=
-    The first nth servers can write data, e.g.: --rep_write=2.
-
--b, --verbose 
-    Whether it outputs detailed information when verification fails.
-
--h, --help 
-    Display this message and then exit.
-
--V, --version 
-    Display the version of the application and then exit.
-
-=head1 EXAMPLES
-
-memslap -s 127.0.0.1:11211 -S 5s
-
-memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b
-
-memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2
-
-memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k
-
-memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40
-
-memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m
-
-memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2
+For a full list of operations run the tool with the B<--help> option.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://launchpad.org/libmemcached>
+L<http://libmemcached.org/>
 
-=head1 AUTHORS
+=head1 AUTHOR
 
-Mingqiang Zhuang E<lt>mingqiangzhuang@hengtiansoft.comE<gt> (Schooner Technolgy)
 Brian Aker, E<lt>brian@tangent.orgE<gt>
 
 =head1 SEE ALSO