--- a/memcache_test.c Fri Aug 29 23:31:17 2008 +0300
+++ b/memcache_test.c Sat Aug 30 19:13:15 2008 +0300
@@ -39,6 +39,7 @@
struct common {
unsigned int max_connections;
+ char pipeline_requests;
struct timeval start;
} common;
@@ -65,10 +66,18 @@
void benchmark_cb (struct memcache_req *req, void *arg);
void benchmark_fetch_fn (void);
+enum option_test {
+ TEST_INVALID,
+ TEST_COMMON,
+
+ TEST_BENCH_FETCH,
+};
+
enum option_code {
OPT_CODE_INVALID,
COMMON_CONN_MAX,
+ COMMON_PIPELINE,
BENCH_FETCH_REQ_CONCURRENCY,
BENCH_FETCH_REQ_AMOUNT,
BENCH_FETCH_KEY_PREFIX,
@@ -83,6 +92,7 @@
enum option_type {
OPT_TYPE_NONE,
+ OPT_TYPE_BOOL,
OPT_TYPE_UINT,
OPT_TYPE_STR,
};
@@ -93,13 +103,19 @@
void (*test_fn) (void);
+ enum option_test code;
+
+ char *descr;
+
} test_list[] = {
- { "benchmark_fetch", &benchmark_cb, &benchmark_fetch_fn },
- { 0, 0, 0, }
+ { "benchmark_fetch", &benchmark_cb, &benchmark_fetch_fn, TEST_BENCH_FETCH,
+ "Measure the speed of fetch requests" },
+ { 0, 0, 0, 0, 0 }
};
static struct option options[] = {
{ "conn-max", required_argument, NULL, COMMON_CONN_MAX },
+ { "pipeline", required_argument, NULL, COMMON_PIPELINE },
{ "req-concurrency", required_argument, NULL, BENCH_FETCH_REQ_CONCURRENCY },
{ "req-amount", required_argument, NULL, BENCH_FETCH_REQ_AMOUNT },
{ "key-prefix", required_argument, NULL, BENCH_FETCH_KEY_PREFIX },
@@ -112,10 +128,16 @@
};
static struct opt {
+ enum option_test test;
enum option_code code;
enum option_type type;
union opt_type_data {
+ struct {
+ char *value;
+ char default_value;
+ } bool;
+
struct {
unsigned int *value;
unsigned int default_value;
@@ -126,17 +148,41 @@
const char *default_value;
} str;
} data;
+
+ const char *name;
+ const char *descr;
} option_info[OPT_CODE_MAX] = {
- { OPT_CODE_INVALID, OPT_TYPE_NONE },
- { COMMON_CONN_MAX, OPT_TYPE_UINT, { .uint = { &common.max_connections, 1 }} },
- { BENCH_FETCH_REQ_CONCURRENCY, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.concurrent_ops, 1 }} },
- { BENCH_FETCH_REQ_AMOUNT, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.total_ops, 500 }} },
- { BENCH_FETCH_KEY_PREFIX, OPT_TYPE_STR, { .str = { &benchmark_fetch.key_prefix, "bf_" }} },
- { BENCH_FETCH_KEY_LEN_MIN, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_len_min, 8 }} },
- { BENCH_FETCH_KEY_LEN_MAX, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_len_max, 8 }} },
- { BENCH_FETCH_KEY_COUNT, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_count, 1 }} },
- { BENCH_FETCH_DATA_LEN_MIN, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.data_len_min, 64 }} },
- { BENCH_FETCH_DATA_LEN_MAX, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.data_len_max, 64 }} },
+ { TEST_INVALID, OPT_CODE_INVALID, OPT_TYPE_NONE },
+
+ { TEST_COMMON, COMMON_CONN_MAX, OPT_TYPE_UINT, { .uint = { &common.max_connections, 1 }},
+ "conn-max", "number of connections to use" },
+
+ { TEST_COMMON, COMMON_PIPELINE, OPT_TYPE_BOOL, { .bool = { &common.pipeline_requests, 1 }},
+ "pipeline", "pipeline requests" },
+
+ { TEST_BENCH_FETCH, BENCH_FETCH_REQ_CONCURRENCY, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.concurrent_ops, 1 }},
+ "req-concurrency", "number of requests to have running" },
+
+ { TEST_BENCH_FETCH, BENCH_FETCH_REQ_AMOUNT, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.total_ops, 500 }},
+ "req-amount", "number of requests to issue" },
+
+ { TEST_BENCH_FETCH, BENCH_FETCH_KEY_PREFIX, OPT_TYPE_STR, { .str = { &benchmark_fetch.key_prefix, "bf_" }},
+ "key-prefix", "key prefix" },
+
+ { TEST_BENCH_FETCH, BENCH_FETCH_KEY_LEN_MIN, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_len_min, 8 }},
+ "key-len-min", "minimum key length" },
+
+ { TEST_BENCH_FETCH, BENCH_FETCH_KEY_LEN_MAX, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_len_max, 8 }},
+ "key-len-max", "maximum key length" },
+
+ { TEST_BENCH_FETCH, BENCH_FETCH_KEY_COUNT, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_count, 1 }},
+ "key-count", "how many keys to use" },
+
+ { TEST_BENCH_FETCH, BENCH_FETCH_DATA_LEN_MIN, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.data_len_min, 64 }},
+ "data-len-min", "minimum data length" },
+
+ { TEST_BENCH_FETCH, BENCH_FETCH_DATA_LEN_MAX, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.data_len_max, 64 }},
+ "data-len-max", "maximum data length" },
};
void time_reset () {
@@ -152,11 +198,15 @@
return ((double) (time.tv_sec - common.start.tv_sec)) + ((double) (time.tv_usec - common.start.tv_usec)) / 1000000;
}
+int ratelimit (int count, int total) {
+ return ((total / 10) ? (count % (total / 10) == 0) : 1);
+}
+
void mc_init (int max_connections, memcache_cb cb_fn) {
// memcache init
- if ((mc = memcache_alloc(cb_fn)) == NULL)
+ if ((mc = memcache_alloc(cb_fn, common.pipeline_requests)) == NULL)
ERROR("memcache_alloc");
// fix up the endpoint
@@ -166,10 +216,10 @@
ERROR("config_endpoint_parse");
// add the server
- if (memcache_add_server(mc, &server_endpoint, max_connections))
+ if (memcache_add_server(mc, &server_endpoint, common.max_connections))
ERROR("memcache_add_server");
- INFO("[memcache] initialized with max_connections=%d", max_connections);
+ INFO("[memcache] initialized with pipeline_requests=%c max_connections=%d", common.pipeline_requests ? 't' : 'f', common.max_connections);
return;
@@ -181,7 +231,7 @@
const struct memcache_obj *obj;
const struct memcache_buf *buf;
- INFO("[%*s]: cmd=%s state=%s reply=%s",
+ INFO("[%.*s]: cmd=%s state=%s reply=%s",
(int) memcache_req_key(req)->len, memcache_req_key(req)->buf,
memcache_command_str(memcache_req_cmd(req)),
memcache_state_str(memcache_req_state(req)),
@@ -288,8 +338,8 @@
assert(memcache_fetch(mc, &benchmark_fetch.keys[random_value(0, benchmark_fetch.key_count)].key, NULL) != NULL);
benchmark_fetch.cur_ops++;
-
- if ((benchmark_fetch.op_count + benchmark_fetch.cur_ops) % (benchmark_fetch.total_ops / 10) == 0)
+
+ if (ratelimit(benchmark_fetch.op_count + benchmark_fetch.cur_ops, benchmark_fetch.total_ops))
INFO("[benchmark] %0.6f: %d+%d/%d requests",
time_offset(),
benchmark_fetch.op_count, benchmark_fetch.cur_ops, benchmark_fetch.total_ops
@@ -357,8 +407,8 @@
}
benchmark_fetch.keys_stored++;
-
- if (benchmark_fetch.keys_stored % (benchmark_fetch.key_count / 10) == 0)
+
+ if (ratelimit(benchmark_fetch.keys_stored, benchmark_fetch.key_count))
INFO("[benchmark] %.6f: key %u/%u stored: %.*s",
time_offset(), benchmark_fetch.keys_stored, benchmark_fetch.key_count, (int) memcache_req_key(req)->len, memcache_req_key(req)->buf
);
@@ -419,27 +469,51 @@
}
}
+void usage_opt (enum option_test test) {
+ struct opt *opt;
+
+ for (opt = option_info + 1; opt->code; opt++) {
+ if (opt->test == test) {
+ switch (opt->type) {
+ case OPT_TYPE_BOOL:
+ INFO("\t%-20s %c %s", opt->name, opt->data.bool.default_value ? 't' : 'f', opt->descr);
+ break;
+
+ case OPT_TYPE_UINT:
+ INFO("\t%-20s %-6d %s", opt->name, opt->data.uint.default_value, opt->descr);
+ break;
+
+ case OPT_TYPE_STR:
+ INFO("\t%-20s %-6s %s", opt->name, opt->data.str.default_value, opt->descr);
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ }
+}
+
void usage (char *cmd) {
- INFO(
- "Usage: %s <cmd> [<args> ... ]\n"
- "\n"
- "COMMANDS\n"
- "\n"
- "benchmark_fetch:\n"
- "\tMeasure the speed of fetch requests\n"
- "\t\n"
- "\tconn-max 1 number of connections to use\n"
- "\treq-concurrency 1 number of requests to have running\n"
- "\treq-amount 500 number of requests to issue\n"
- "\tkey-prefix bf_ key prefix\n"
- "\tkey-len-min 8 minimum key lengt\n"
- "\tkey-len-max 8 maximum key length\n"
- "\tkey-count 1 how many keys to use\n"
- "\tdata-len-min 64 minimum data length\n"
- "\tdata-len-max 64 maximum data length\n",
+ struct test *test;
- cmd
- );
+ INFO("Usage: %s <cmd> [<args> ... ]", cmd);
+
+ INFO("\nCOMMON OPTIONS\n");
+
+ usage_opt(TEST_COMMON);
+
+ INFO("\nCOMMANDS\n");
+
+ for (test = test_list; test->name; test++) {
+ INFO("%s:", test->name);
+ INFO("\t%s", test->descr);
+ INFO("\t");
+
+ usage_opt(test->code);
+
+ INFO("\t");
+ }
exit(1);
}
@@ -472,6 +546,11 @@
switch (option_info[c].type) {
case OPT_TYPE_NONE:
break;
+
+ case OPT_TYPE_BOOL:
+ *option_info[c].data.bool.value = option_info[c].data.bool.default_value;
+
+ break;
case OPT_TYPE_UINT:
*option_info[c].data.uint.value = option_info[c].data.uint.default_value;
@@ -491,8 +570,31 @@
while ((c = getopt_long(argc, argv, "", options, &option_index)) != -1) {
if (c <= OPT_CODE_INVALID || c >= OPT_CODE_MAX)
FATAL("invalid argument %s", options[option_index].name);
+
+ if (option_info[c].test != test->code && option_info[c].test != TEST_COMMON)
+ FATAL("invalid option %s for test %s", options[option_index].name, test->name);
switch (option_info[c].type) {
+ case OPT_TYPE_BOOL:
+ assert(optarg);
+
+ switch (optarg[0]) {
+ case 't':
+ case '1':
+ *option_info[c].data.bool.value = 1;
+ break;
+
+ case 'f':
+ case '0':
+ *option_info[c].data.bool.value = 0;
+ break;
+
+ default:
+ FATAL("invalid true/false value: %s: %s", options[option_index].name, optarg);
+ }
+
+ break;
+
case OPT_TYPE_UINT:
assert(optarg);