diff -r 1c67f512779b -r 10c7dce1a043 memcache_test.c --- 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 [ ... ]\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); + + 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);