memcache_test.c
changeset 48 1c67f512779b
parent 46 8a832c0e01ee
child 49 10c7dce1a043
equal deleted inserted replaced
47:a5c09677ca6f 48:1c67f512779b
       
     1 #define _GNU_SOURCE
       
     2 #include <stdlib.h>
       
     3 #include <unistd.h>
       
     4 #include <getopt.h>
       
     5 #include <sys/time.h>
       
     6 #include <time.h>
       
     7 #include <ctype.h>
       
     8 #include <assert.h>
     1 
     9 
     2 #include <event2/event.h>
    10 #include <event2/event.h>
     3 #include <event2/event_compat.h>
    11 #include <event2/event_compat.h>
     4 #include <event2/event_struct.h>
    12 #include <event2/event_struct.h>
     5 
    13 
     6 #include "memcache.h"
    14 #include "memcache.h"
     7 #include "config.h"
    15 #include "config.h"
     8 #include "common.h"
    16 #include "common.h"
     9 
    17 
       
    18 /*
       
    19  * Test:
       
    20  *  * zero-length entries
       
    21  */
       
    22 
       
    23 static struct event_base *ev_base;
    10 static struct memcache *mc;
    24 static struct memcache *mc;
    11 static struct config_endpoint server_endpoint;
    25 static struct config_endpoint server_endpoint;
    12 static char *data_1 = "rei4quohV8Oocio1ua0co8ni4Ae1re4houcheixahchoh3ioghie0aShooShoh6Ahboequ9eiX5eashuu6Chu1quo"
    26 static char *data_1 = "rei4quohV8Oocio1ua0co8ni4Ae1re4houcheixahchoh3ioghie0aShooShoh6Ahboequ9eiX5eashuu6Chu1quo"
    13                             "o0suph7cheiyai1ea0ooh7Aevoo4feihubupohDeephahwee2Ooz7chiediec7neit7keTh6xuheash8chaeKa5vi"
    27                             "o0suph7cheiyai1ea0ooh7Aevoo4feihubupohDeephahwee2Ooz7chiediec7neit7keTh6xuheash8chaeKa5vi"
    14                             "ekooqu7ooj6Eezooroi6Nequ9ca2yi6iSoigh3loowaey9eiphaphaiJ0souy7wohpa9eXo5Ahu2sa";
    28                             "ekooqu7ooj6Eezooroi6Nequ9ca2yi6iSoigh3loowaey9eiphaphaiJ0souy7wohpa9eXo5Ahu2sa";
    15 static char *data_2 = "iefaek7ighi5UpueThageish5ieshohyeil1raiceerahjahng5ui7vuzie9quu4dai5ar2aiXi5ieth4looweigi"
    29 static char *data_2 = "iefaek7ighi5UpueThageish5ieshohyeil1raiceerahjahng5ui7vuzie9quu4dai5ar2aiXi5ieth4looweigi"
    16                             "e3fo5ieri1queengaiphuaghaic1xahvoo9joo6baiNaig8puCootheowah4moocohDoiquoh3quieka5ao3aeNg9"
    30                             "e3fo5ieri1queengaiphuaghaic1xahvoo9joo6baiNaig8puCootheowah4moocohDoiquoh3quieka5ao3aeNg9"
    17                             "Aimei1soangu4Duch5pho5buu2ohzaich4chahz9iTh3Pei4beep1ongie6au1aafoosh2vierei5E";
    31                             "Aimei1soangu4Duch5pho5buu2ohzaich4chahz9iTh3Pei4beep1ongie6au1aafoosh2vierei5E";
    18 
    32                             
    19 void _memcache_cb (struct memcache_req *req, void *arg) {
    33 #define BENCHMARK_KEY "memcache_benchmark"
    20     char *key = arg;
    34 #define BENCHMARK_KEY_MAX 256
       
    35 #define BENCHMARK_DATA_MAX 1024 * 1024
       
    36 
       
    37 #define MIN(a, b) ((a) < (b) ? (a) : (b))
       
    38 #define MAX(a, b) ((a) > (b) ? (a) : (b))
       
    39 
       
    40 struct common {
       
    41     unsigned int max_connections;
       
    42     
       
    43     struct timeval start;
       
    44 } common;
       
    45 
       
    46 struct benchmark_fetch {
       
    47     unsigned int concurrent_ops;
       
    48     unsigned int total_ops;
       
    49     
       
    50     const char *key_prefix;
       
    51     unsigned int key_len_min, key_len_max, key_count;
       
    52     unsigned int data_len_min, data_len_max;
       
    53     
       
    54     int keys_stored;
       
    55     int cur_ops;
       
    56     int op_count;
       
    57     
       
    58     struct key_buf {
       
    59         char buf[BENCHMARK_KEY_MAX];
       
    60         struct memcache_key key;
       
    61     } *keys;
       
    62 
       
    63 } benchmark_fetch;
       
    64 
       
    65 void benchmark_cb (struct memcache_req *req, void *arg);
       
    66 void benchmark_fetch_fn (void);
       
    67 
       
    68 enum option_code {
       
    69     OPT_CODE_INVALID,
       
    70 
       
    71     COMMON_CONN_MAX,
       
    72     BENCH_FETCH_REQ_CONCURRENCY,
       
    73     BENCH_FETCH_REQ_AMOUNT,
       
    74     BENCH_FETCH_KEY_PREFIX,
       
    75     BENCH_FETCH_KEY_LEN_MIN,
       
    76     BENCH_FETCH_KEY_LEN_MAX,
       
    77     BENCH_FETCH_KEY_COUNT,
       
    78     BENCH_FETCH_DATA_LEN_MIN,
       
    79     BENCH_FETCH_DATA_LEN_MAX,
       
    80 
       
    81     OPT_CODE_MAX,
       
    82 };
       
    83 
       
    84 enum option_type {
       
    85     OPT_TYPE_NONE,
       
    86     OPT_TYPE_UINT,
       
    87     OPT_TYPE_STR,
       
    88 };
       
    89 
       
    90 static struct test {
       
    91     char *name;
       
    92     memcache_cb cb_fn;
       
    93 
       
    94     void (*test_fn) (void);
       
    95 
       
    96 } test_list[] = {
       
    97     { "benchmark_fetch",        &benchmark_cb,  &benchmark_fetch_fn },
       
    98     { 0,                        0,              0,                  }
       
    99 };
       
   100 
       
   101 static struct option options[] = {
       
   102     { "conn-max",           required_argument,  NULL,   COMMON_CONN_MAX             },
       
   103     { "req-concurrency",    required_argument,  NULL,   BENCH_FETCH_REQ_CONCURRENCY },
       
   104     { "req-amount",         required_argument,  NULL,   BENCH_FETCH_REQ_AMOUNT      },
       
   105     { "key-prefix",         required_argument,  NULL,   BENCH_FETCH_KEY_PREFIX      },
       
   106     { "key-len-min",        required_argument,  NULL,   BENCH_FETCH_KEY_LEN_MIN     },
       
   107     { "key-len-max",        required_argument,  NULL,   BENCH_FETCH_KEY_LEN_MAX     },
       
   108     { "key-count",          required_argument,  NULL,   BENCH_FETCH_KEY_COUNT       },
       
   109     { "data-len-min",       required_argument,  NULL,   BENCH_FETCH_DATA_LEN_MIN    },
       
   110     { "data-len-max",       required_argument,  NULL,   BENCH_FETCH_DATA_LEN_MAX    },
       
   111     { 0,                    0,                  0,      0                           },
       
   112 };
       
   113 
       
   114 static struct opt {
       
   115     enum option_code code;
       
   116     enum option_type type;
       
   117     
       
   118     union opt_type_data {
       
   119         struct {
       
   120             unsigned int *value;
       
   121             unsigned int default_value;
       
   122         } uint;
       
   123 
       
   124         struct {
       
   125             const char **value;
       
   126             const char *default_value;
       
   127         } str;
       
   128     } data;
       
   129 } option_info[OPT_CODE_MAX] = {
       
   130     {   OPT_CODE_INVALID,               OPT_TYPE_NONE                                                           },
       
   131     {   COMMON_CONN_MAX,                OPT_TYPE_UINT,  { .uint = { &common.max_connections,          1     }}  },
       
   132     {   BENCH_FETCH_REQ_CONCURRENCY,    OPT_TYPE_UINT,  { .uint = { &benchmark_fetch.concurrent_ops,  1     }}  },
       
   133     {   BENCH_FETCH_REQ_AMOUNT,         OPT_TYPE_UINT,  { .uint = { &benchmark_fetch.total_ops,       500   }}  },
       
   134     {   BENCH_FETCH_KEY_PREFIX,         OPT_TYPE_STR,   { .str  = { &benchmark_fetch.key_prefix,      "bf_" }}  },
       
   135     {   BENCH_FETCH_KEY_LEN_MIN,        OPT_TYPE_UINT,  { .uint = { &benchmark_fetch.key_len_min,     8     }}  },
       
   136     {   BENCH_FETCH_KEY_LEN_MAX,        OPT_TYPE_UINT,  { .uint = { &benchmark_fetch.key_len_max,     8     }}  },
       
   137     {   BENCH_FETCH_KEY_COUNT,          OPT_TYPE_UINT,  { .uint = { &benchmark_fetch.key_count,       1     }}  },
       
   138     {   BENCH_FETCH_DATA_LEN_MIN,       OPT_TYPE_UINT,  { .uint = { &benchmark_fetch.data_len_min,    64    }}  },
       
   139     {   BENCH_FETCH_DATA_LEN_MAX,       OPT_TYPE_UINT,  { .uint = { &benchmark_fetch.data_len_max,    64    }}  },
       
   140 };
       
   141 
       
   142 void time_reset () {
       
   143     // start timing
       
   144     assert(gettimeofday(&common.start, NULL) == 0);
       
   145 }
       
   146 
       
   147 double time_offset () {
       
   148     struct timeval time;
       
   149 
       
   150     assert(gettimeofday(&time, NULL) == 0);
       
   151     
       
   152     return ((double) (time.tv_sec - common.start.tv_sec)) + ((double) (time.tv_usec - common.start.tv_usec)) / 1000000;
       
   153 }
       
   154 
       
   155 
       
   156 
       
   157 void mc_init (int max_connections, memcache_cb cb_fn) {
       
   158     // memcache init    
       
   159     if ((mc = memcache_alloc(cb_fn)) == NULL)
       
   160         ERROR("memcache_alloc");
       
   161     
       
   162     // fix up the endpoint
       
   163     endpoint_init(&server_endpoint, 11211);
       
   164     
       
   165     if (endpoint_parse(&server_endpoint, "localhost"))
       
   166         ERROR("config_endpoint_parse");
       
   167     
       
   168     // add the server
       
   169     if (memcache_add_server(mc, &server_endpoint, max_connections))
       
   170         ERROR("memcache_add_server");
       
   171     
       
   172     INFO("[memcache] initialized with max_connections=%d", max_connections);
       
   173 
       
   174     return;
       
   175 
       
   176 error:
       
   177     assert(0);
       
   178 }
       
   179 
       
   180 void dump_req (struct memcache_req *req, void *unused) {
    21     const struct memcache_obj *obj;
   181     const struct memcache_obj *obj;
    22     const struct memcache_buf *buf;
   182     const struct memcache_buf *buf;
    23 
   183 
    24     INFO("[%s]: cmd=%15s state=%15s reply=%15s", key,
   184     INFO("[%*s]: cmd=%s state=%s reply=%s",
       
   185         (int) memcache_req_key(req)->len, memcache_req_key(req)->buf,
    25         memcache_command_str(memcache_req_cmd(req)),
   186         memcache_command_str(memcache_req_cmd(req)),
    26         memcache_state_str(memcache_req_state(req)),
   187         memcache_state_str(memcache_req_state(req)),
    27         memcache_reply_str(memcache_req_reply(req))
   188         memcache_reply_str(memcache_req_reply(req))
    28     );
   189     );
    29     
   190     
    30     if ((obj = memcache_req_obj(req)))
   191     if ((obj = memcache_req_obj(req)))
    31         INFO("\tobj: flags=0x%04X exptime=%9zu bytes=%6zu cas=%llu", obj->flags, obj->exptime, obj->bytes, obj->cas);
   192         INFO("\tobj: flags=0x%04X exptime=%zu bytes=%zu cas=%llu", obj->flags, obj->exptime, obj->bytes, obj->cas);
    32 
   193 
    33     if ((buf = memcache_req_buf(req)))
   194     if ((buf = memcache_req_buf(req)))
    34         INFO("\tbuf: data=%p len=%6zu offset=%6zu", buf->data, buf->len, buf->offset);
   195         INFO("\tbuf: data=%p len=%zu offset=%zu", buf->data, buf->len, buf->offset);
    35     
   196     
    36     INFO("%s", "");
   197     INFO("%s", "");
       
   198 }
       
   199 
       
   200 size_t random_value (size_t min, size_t max) {
       
   201     return ((max == min) ? min : (random() % (max - min)) + min);
       
   202 }
       
   203 
       
   204 size_t random_data (char *buf, size_t min, size_t max) {
       
   205 #define CHAR_TABLE_MAX (('z' - 'a' + 1) + ('Z' - 'A' + 1) + ('9' - '0' + 1))
       
   206 
       
   207     static char char_table[CHAR_TABLE_MAX] = {
       
   208         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
       
   209         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
       
   210         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
       
   211     };
       
   212 
       
   213     assert(max >= min);
       
   214 
       
   215     size_t size = random_value(min, max), i;
       
   216 
       
   217     for (i = 0; i < size; i++) {
       
   218         buf[i] = char_table[random_value(0, CHAR_TABLE_MAX)];
       
   219 
       
   220         assert(isalnum(buf[i]));
       
   221 /*    
       
   222         switch (MIN((size - i), 4)) {
       
   223             case 4: * ((u_int32_t*) &buf[i]) = random(); i += 4; break;
       
   224             case 3:
       
   225             case 2: * ((u_int16_t*) &buf[i]) = random(); i += 2; break;
       
   226             case 1: * ((u_int8_t*)  &buf[i]) = random(); i += 1; break;
       
   227             default: assert(0);
       
   228         }
       
   229 */        
       
   230     }
       
   231 
       
   232     return size;
       
   233 }
       
   234 
       
   235 void test_cb (struct memcache_req *req, void *arg) {
       
   236     dump_req(req, arg);
    37 }
   237 }
    38 
   238 
    39 void begin_test () {
   239 void begin_test () {
    40     struct memcache_key key_1, key_2;
   240     struct memcache_key key_1, key_2;
    41     struct memcache_obj obj_1, obj_2;
   241     struct memcache_obj obj_1, obj_2;
    42     struct memcache_buf buf_1, buf_2;
   242     struct memcache_buf buf_1, buf_2;
    43 
   243     struct memcache_req *req_1s, *req_2s, *req_1f, *req_2f;
    44     if ((mc = memcache_alloc(&_memcache_cb)) == NULL)
   244     
    45         ERROR("memcache_alloc");
   245     mc_init(1, &test_cb);
    46     
   246 
    47     // fix up the endpoint
       
    48     endpoint_init(&server_endpoint, 11211);
       
    49     
       
    50     if (endpoint_parse(&server_endpoint, "localhost"))
       
    51         ERROR("config_endpoint_parse");
       
    52     
       
    53     // add the server
       
    54     if (memcache_add_server(mc, &server_endpoint, 1))
       
    55         ERROR("memcache_add_server");
       
    56    
       
    57     // add a request or two
   247     // add a request or two
    58     key_1.buf = "memcache_test_k1";
   248     key_1.buf = "memcache_test_k1";
    59     key_2.buf = "memcache_test_k2";
   249     key_2.buf = "memcache_test_k2";
    60     key_1.len = key_2.len = 0;
   250     key_1.len = key_2.len = 0;
    61 
   251 
    74 
   264 
    75     buf_2.data = data_2;
   265     buf_2.data = data_2;
    76     buf_2.len = strlen(data_2);
   266     buf_2.len = strlen(data_2);
    77     buf_2.offset = buf_2.len;
   267     buf_2.offset = buf_2.len;
    78 
   268 
    79     if (memcache_store(mc, MEMCACHE_CMD_STORE_SET, &key_1, &obj_1, &buf_1, key_1.buf))
   269     if ((req_1s = memcache_store(mc, MEMCACHE_CMD_STORE_SET, &key_1, &obj_1, &buf_1, key_1.buf)) == NULL)
    80         ERROR("memcache_store: key_1");
   270         ERROR("memcache_store: key_1");
    81     
   271     
    82     if (memcache_store(mc, MEMCACHE_CMD_STORE_ADD, &key_2, &obj_2, &buf_2, key_2.buf))
   272     if ((req_2s = memcache_store(mc, MEMCACHE_CMD_STORE_ADD, &key_2, &obj_2, &buf_2, key_2.buf)) == NULL)
    83         ERROR("memcache_store: key_2");
   273         ERROR("memcache_store: key_2");
    84     
   274     
    85     if (memcache_fetch(mc, &key_1, key_1.buf))
   275     if ((req_1f = memcache_fetch(mc, &key_1, key_1.buf)) == NULL)
    86         ERROR("memcache_fetch: key_1");
   276         ERROR("memcache_fetch: key_1");
    87     
   277     
    88     if (memcache_fetch(mc, &key_2, key_2.buf))
   278     if ((req_2f = memcache_fetch(mc, &key_2, key_2.buf)) == NULL)
    89         ERROR("memcache_fetch: key_2");
   279         ERROR("memcache_fetch: key_2");
    90 
   280 
    91 error:
   281 error:
    92     return;
   282     return;
    93 }
   283 }
    94 
   284 
       
   285 void benchmark_continue () {
       
   286     while (benchmark_fetch.cur_ops < benchmark_fetch.concurrent_ops && (benchmark_fetch.op_count + benchmark_fetch.cur_ops) < benchmark_fetch.total_ops) {
       
   287         // launch
       
   288         assert(memcache_fetch(mc, &benchmark_fetch.keys[random_value(0, benchmark_fetch.key_count)].key, NULL) != NULL);
       
   289 
       
   290         benchmark_fetch.cur_ops++;
       
   291 
       
   292         if ((benchmark_fetch.op_count + benchmark_fetch.cur_ops) % (benchmark_fetch.total_ops / 10) == 0)
       
   293             INFO("[benchmark] %0.6f: %d+%d/%d requests", 
       
   294                 time_offset(),
       
   295                 benchmark_fetch.op_count, benchmark_fetch.cur_ops, benchmark_fetch.total_ops
       
   296             );
       
   297     }
       
   298 
       
   299     if (benchmark_fetch.op_count == benchmark_fetch.total_ops) {
       
   300         // done
       
   301         assert(event_base_loopexit(ev_base, NULL) == 0);
       
   302 
       
   303         INFO("[benchmark] %.6f: %.6f req/s", 
       
   304             time_offset(),
       
   305             benchmark_fetch.op_count / time_offset()
       
   306         );
       
   307     }
       
   308 }
       
   309 
       
   310 void benchmark_fetch_start () {    
       
   311     INFO(
       
   312         "[benchmark] %0.6f: starting\n"
       
   313         "\tconcurrent_ops   = %u\n"
       
   314         "\ttotal_ops        = %u\n"
       
   315         "\tkey_prefix       = %s\n"
       
   316         "\tkey_len_min      = %u\n"
       
   317         "\tkey_len_max      = %u\n"
       
   318         "\tkey_count        = %u\n"
       
   319         "\tdata_len_min     = %u\n"
       
   320         "\tdata_len_max     = %u\n"
       
   321         , time_offset(),
       
   322         benchmark_fetch.concurrent_ops, benchmark_fetch.total_ops,
       
   323         benchmark_fetch.key_prefix, benchmark_fetch.key_len_min, benchmark_fetch.key_len_max, benchmark_fetch.key_count,
       
   324         benchmark_fetch.data_len_min, benchmark_fetch.data_len_max
       
   325     );
       
   326     
       
   327     time_reset();
       
   328 
       
   329     benchmark_continue();
       
   330     
       
   331     INFO("[benchmark] %0.6f: running", 
       
   332         time_offset()
       
   333     );
       
   334 }
       
   335 
       
   336 
       
   337 void benchmark_cb (struct memcache_req *req, void *arg) {
       
   338     enum memcache_command cmd = memcache_req_cmd(req);
       
   339     enum memcache_state state = memcache_req_state(req);
       
   340 
       
   341     if (state == MEMCACHE_STATE_ERROR) {
       
   342         dump_req(req, arg);
       
   343         FATAL("request failed");
       
   344     }
       
   345 
       
   346     if (state == MEMCACHE_STATE_DONE || state == MEMCACHE_STATE_DONE_DATA) {
       
   347         if (cmd == MEMCACHE_CMD_FETCH_GET) {
       
   348             benchmark_fetch.cur_ops--;
       
   349             benchmark_fetch.op_count++;
       
   350 
       
   351             benchmark_continue();
       
   352 
       
   353         } else if (cmd == MEMCACHE_CMD_STORE_SET) {
       
   354             if (memcache_req_reply(req) != MEMCACHE_RPL_STORED) {
       
   355                 dump_req(req, arg);
       
   356                 WARNING("value was not stored");
       
   357             }
       
   358 
       
   359             benchmark_fetch.keys_stored++;
       
   360 
       
   361             if (benchmark_fetch.keys_stored % (benchmark_fetch.key_count / 10) == 0)
       
   362                 INFO("[benchmark] %.6f: key %u/%u stored: %.*s", 
       
   363                     time_offset(), benchmark_fetch.keys_stored, benchmark_fetch.key_count, (int) memcache_req_key(req)->len, memcache_req_key(req)->buf
       
   364                 );
       
   365 
       
   366             if (benchmark_fetch.keys_stored == benchmark_fetch.key_count)
       
   367                 benchmark_fetch_start();
       
   368         }
       
   369         
       
   370         memcache_req_free(req);
       
   371     }
       
   372 }
       
   373 
       
   374 /*
       
   375  * Run <concurrent_op> ops in parrallel, until we have completed total_ops, at which point we shut down.
       
   376  */
       
   377 void benchmark_fetch_fn () {
       
   378     static char data[BENCHMARK_DATA_MAX];
       
   379     char key_postfix[BENCHMARK_KEY_MAX];
       
   380     int i, key_len, data_len;
       
   381     struct memcache_obj obj;
       
   382     struct memcache_buf buf;
       
   383 
       
   384     assert(benchmark_fetch.key_len_min > 0 && (strlen(benchmark_fetch.key_prefix) + benchmark_fetch.key_len_max) < BENCHMARK_KEY_MAX);
       
   385     assert(benchmark_fetch.data_len_min > 0 && benchmark_fetch.data_len_max < BENCHMARK_DATA_MAX);
       
   386 
       
   387     benchmark_fetch.cur_ops = benchmark_fetch.op_count = benchmark_fetch.keys_stored = 0;
       
   388 
       
   389     if ((benchmark_fetch.keys = calloc(benchmark_fetch.key_count, sizeof(struct key_buf))) == NULL)
       
   390         FATAL("calloc");
       
   391 
       
   392     // pregenerate the data
       
   393     data_len = random_data(data, benchmark_fetch.data_len_min, benchmark_fetch.data_len_max);
       
   394 
       
   395     obj.flags = 0x1234;
       
   396     obj.exptime = 0;
       
   397     obj.bytes = data_len;
       
   398     buf.data = data;
       
   399     buf.len = buf.offset = data_len;
       
   400 
       
   401     // insert keys
       
   402     INFO("[benchmark] %0.6f: inserting %u keys with prefix=%s and len=(%u -> %u)",
       
   403         time_offset(),
       
   404         benchmark_fetch.key_count, benchmark_fetch.key_prefix, benchmark_fetch.key_len_min, benchmark_fetch.key_len_max
       
   405     );
       
   406     
       
   407     for (i = 0; i < benchmark_fetch.key_count; i++) {
       
   408         struct key_buf *keybuf = &benchmark_fetch.keys[i];
       
   409 
       
   410         key_len = random_data(key_postfix, benchmark_fetch.key_len_min, benchmark_fetch.key_len_max);
       
   411 
       
   412         key_postfix[key_len] = '\0';
       
   413 
       
   414         assert((keybuf->key.len = snprintf(keybuf->buf, BENCHMARK_KEY_MAX, "%s%*s", benchmark_fetch.key_prefix, key_len, key_postfix)) < BENCHMARK_KEY_MAX);
       
   415         
       
   416         keybuf->key.buf = keybuf->buf;
       
   417 
       
   418         assert(memcache_store(mc, MEMCACHE_CMD_STORE_SET, &keybuf->key, &obj, &buf, NULL) != NULL);
       
   419     }
       
   420 }
       
   421 
       
   422 void usage (char *cmd) {
       
   423     INFO(
       
   424         "Usage: %s <cmd> [<args> ... ]\n"
       
   425         "\n"
       
   426         "COMMANDS\n"
       
   427         "\n"
       
   428         "benchmark_fetch:\n"
       
   429         "\tMeasure the speed of fetch requests\n"
       
   430         "\t\n"
       
   431         "\tconn-max         1       number of connections to use\n"
       
   432         "\treq-concurrency  1       number of requests to have running\n"
       
   433         "\treq-amount       500     number of requests to issue\n"
       
   434         "\tkey-prefix       bf_     key prefix\n"
       
   435         "\tkey-len-min      8       minimum key lengt\n"
       
   436         "\tkey-len-max      8       maximum key length\n"
       
   437         "\tkey-count        1       how many keys to use\n"
       
   438         "\tdata-len-min     64      minimum data length\n"
       
   439         "\tdata-len-max     64      maximum data length\n",
       
   440 
       
   441         cmd
       
   442     );
       
   443 
       
   444     exit(1);
       
   445 }
       
   446 
    95 int main (int argc, char **argv) {
   447 int main (int argc, char **argv) {
    96     // libevent init
   448     char *name, *invalid;
    97     struct event_base *ev_base = event_init();
   449     struct test *test;
       
   450     int c, option_index;
       
   451 
       
   452     // argument-parsing
       
   453     if (argc < 2) {
       
   454         WARNING("No command given");
       
   455         usage(argv[0]);
       
   456     }
       
   457     
       
   458     // look up the test
       
   459     name = argv[1];
       
   460     test = test_list;
       
   461     
       
   462     while (test->name && strcmp(test->name, name) != 0)
       
   463         test++;
       
   464     
       
   465     if (!test->name) {
       
   466         WARNING("Unknown cmd '%s'", name);
       
   467         usage(argv[0]);
       
   468     }
       
   469     
       
   470     // default values
       
   471     for (c = OPT_CODE_INVALID; c < OPT_CODE_MAX; c++) {
       
   472         switch (option_info[c].type) {
       
   473             case OPT_TYPE_NONE:
       
   474                 break;
       
   475 
       
   476             case OPT_TYPE_UINT:
       
   477                 *option_info[c].data.uint.value = option_info[c].data.uint.default_value;
       
   478 
       
   479                 break;
       
   480 
       
   481             case OPT_TYPE_STR:
       
   482                 *option_info[c].data.str.value = option_info[c].data.str.default_value;
       
   483 
       
   484                 break;
       
   485 
       
   486             default:
       
   487                 assert(0);
       
   488         }
       
   489     }
       
   490 
       
   491     while ((c = getopt_long(argc, argv, "", options, &option_index)) != -1) {
       
   492         if (c <= OPT_CODE_INVALID || c >= OPT_CODE_MAX)
       
   493             FATAL("invalid argument %s", options[option_index].name);
       
   494         
       
   495         switch (option_info[c].type) {
       
   496             case OPT_TYPE_UINT:
       
   497                 assert(optarg);
       
   498 
       
   499                 *option_info[c].data.uint.value = strtol(optarg, &invalid, 10);
       
   500 
       
   501                 if (*invalid)
       
   502                     FATAL("invalid argument value: %s: %s (%s)", options[option_index].name, optarg, invalid);
       
   503                 
       
   504                 break;
       
   505 
       
   506             case OPT_TYPE_STR:
       
   507                 assert(optarg);
       
   508 
       
   509                 *option_info[c].data.str.value = optarg;
       
   510 
       
   511                 break;
       
   512     
       
   513             case OPT_TYPE_NONE:
       
   514             default:
       
   515                 FATAL("invalid argument type %s", options[option_index].name);
       
   516                 
       
   517                 break;
       
   518         }
       
   519     }
       
   520 
       
   521     // libevent init 
       
   522     ev_base = event_init();
    98 
   523 
    99     if (!ev_base)
   524     if (!ev_base)
   100         FATAL("event_init");
   525         FATAL("event_init");
   101     
   526     
   102     begin_test();
   527     // set up the memcache
       
   528     mc_init(common.max_connections, test->cb_fn);
       
   529 
       
   530     // start timing
       
   531     time_reset();
       
   532     
       
   533     // start the test
       
   534     test->test_fn();
       
   535     
       
   536     INFO("[libevent] run");
   103 
   537 
   104     // run the libevent mainloop
   538     // run the libevent mainloop
   105     if (event_base_dispatch(ev_base))
   539     if (event_base_dispatch(ev_base))
   106         WARNING("event_dispatch");
   540         WARNING("event_dispatch");
   107 
   541 
   108     INFO("SHUTDOWN");
   542     INFO("[libevent] shutdown");
   109     
   543     
   110     // clean up
   544     // clean up
   111     event_base_free(ev_base);
   545     event_base_free(ev_base);
   112     
   546     
   113     // successfull exit
   547     // successfull exit