81 OPT_CODE_MAX, |
90 OPT_CODE_MAX, |
82 }; |
91 }; |
83 |
92 |
84 enum option_type { |
93 enum option_type { |
85 OPT_TYPE_NONE, |
94 OPT_TYPE_NONE, |
|
95 OPT_TYPE_BOOL, |
86 OPT_TYPE_UINT, |
96 OPT_TYPE_UINT, |
87 OPT_TYPE_STR, |
97 OPT_TYPE_STR, |
88 }; |
98 }; |
89 |
99 |
90 static struct test { |
100 static struct test { |
91 char *name; |
101 char *name; |
92 memcache_cb cb_fn; |
102 memcache_cb cb_fn; |
93 |
103 |
94 void (*test_fn) (void); |
104 void (*test_fn) (void); |
95 |
105 |
|
106 enum option_test code; |
|
107 |
|
108 char *descr; |
|
109 |
96 } test_list[] = { |
110 } test_list[] = { |
97 { "benchmark_fetch", &benchmark_cb, &benchmark_fetch_fn }, |
111 { "benchmark_fetch", &benchmark_cb, &benchmark_fetch_fn, TEST_BENCH_FETCH, |
98 { 0, 0, 0, } |
112 "Measure the speed of fetch requests" }, |
|
113 { 0, 0, 0, 0, 0 } |
99 }; |
114 }; |
100 |
115 |
101 static struct option options[] = { |
116 static struct option options[] = { |
102 { "conn-max", required_argument, NULL, COMMON_CONN_MAX }, |
117 { "conn-max", required_argument, NULL, COMMON_CONN_MAX }, |
|
118 { "pipeline", required_argument, NULL, COMMON_PIPELINE }, |
103 { "req-concurrency", required_argument, NULL, BENCH_FETCH_REQ_CONCURRENCY }, |
119 { "req-concurrency", required_argument, NULL, BENCH_FETCH_REQ_CONCURRENCY }, |
104 { "req-amount", required_argument, NULL, BENCH_FETCH_REQ_AMOUNT }, |
120 { "req-amount", required_argument, NULL, BENCH_FETCH_REQ_AMOUNT }, |
105 { "key-prefix", required_argument, NULL, BENCH_FETCH_KEY_PREFIX }, |
121 { "key-prefix", required_argument, NULL, BENCH_FETCH_KEY_PREFIX }, |
106 { "key-len-min", required_argument, NULL, BENCH_FETCH_KEY_LEN_MIN }, |
122 { "key-len-min", required_argument, NULL, BENCH_FETCH_KEY_LEN_MIN }, |
107 { "key-len-max", required_argument, NULL, BENCH_FETCH_KEY_LEN_MAX }, |
123 { "key-len-max", required_argument, NULL, BENCH_FETCH_KEY_LEN_MAX }, |
110 { "data-len-max", required_argument, NULL, BENCH_FETCH_DATA_LEN_MAX }, |
126 { "data-len-max", required_argument, NULL, BENCH_FETCH_DATA_LEN_MAX }, |
111 { 0, 0, 0, 0 }, |
127 { 0, 0, 0, 0 }, |
112 }; |
128 }; |
113 |
129 |
114 static struct opt { |
130 static struct opt { |
|
131 enum option_test test; |
115 enum option_code code; |
132 enum option_code code; |
116 enum option_type type; |
133 enum option_type type; |
117 |
134 |
118 union opt_type_data { |
135 union opt_type_data { |
|
136 struct { |
|
137 char *value; |
|
138 char default_value; |
|
139 } bool; |
|
140 |
119 struct { |
141 struct { |
120 unsigned int *value; |
142 unsigned int *value; |
121 unsigned int default_value; |
143 unsigned int default_value; |
122 } uint; |
144 } uint; |
123 |
145 |
124 struct { |
146 struct { |
125 const char **value; |
147 const char **value; |
126 const char *default_value; |
148 const char *default_value; |
127 } str; |
149 } str; |
128 } data; |
150 } data; |
|
151 |
|
152 const char *name; |
|
153 const char *descr; |
129 } option_info[OPT_CODE_MAX] = { |
154 } option_info[OPT_CODE_MAX] = { |
130 { OPT_CODE_INVALID, OPT_TYPE_NONE }, |
155 { TEST_INVALID, OPT_CODE_INVALID, OPT_TYPE_NONE }, |
131 { COMMON_CONN_MAX, OPT_TYPE_UINT, { .uint = { &common.max_connections, 1 }} }, |
156 |
132 { BENCH_FETCH_REQ_CONCURRENCY, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.concurrent_ops, 1 }} }, |
157 { TEST_COMMON, COMMON_CONN_MAX, OPT_TYPE_UINT, { .uint = { &common.max_connections, 1 }}, |
133 { BENCH_FETCH_REQ_AMOUNT, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.total_ops, 500 }} }, |
158 "conn-max", "number of connections to use" }, |
134 { BENCH_FETCH_KEY_PREFIX, OPT_TYPE_STR, { .str = { &benchmark_fetch.key_prefix, "bf_" }} }, |
159 |
135 { BENCH_FETCH_KEY_LEN_MIN, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_len_min, 8 }} }, |
160 { TEST_COMMON, COMMON_PIPELINE, OPT_TYPE_BOOL, { .bool = { &common.pipeline_requests, 1 }}, |
136 { BENCH_FETCH_KEY_LEN_MAX, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_len_max, 8 }} }, |
161 "pipeline", "pipeline requests" }, |
137 { BENCH_FETCH_KEY_COUNT, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_count, 1 }} }, |
162 |
138 { BENCH_FETCH_DATA_LEN_MIN, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.data_len_min, 64 }} }, |
163 { TEST_BENCH_FETCH, BENCH_FETCH_REQ_CONCURRENCY, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.concurrent_ops, 1 }}, |
139 { BENCH_FETCH_DATA_LEN_MAX, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.data_len_max, 64 }} }, |
164 "req-concurrency", "number of requests to have running" }, |
|
165 |
|
166 { TEST_BENCH_FETCH, BENCH_FETCH_REQ_AMOUNT, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.total_ops, 500 }}, |
|
167 "req-amount", "number of requests to issue" }, |
|
168 |
|
169 { TEST_BENCH_FETCH, BENCH_FETCH_KEY_PREFIX, OPT_TYPE_STR, { .str = { &benchmark_fetch.key_prefix, "bf_" }}, |
|
170 "key-prefix", "key prefix" }, |
|
171 |
|
172 { TEST_BENCH_FETCH, BENCH_FETCH_KEY_LEN_MIN, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_len_min, 8 }}, |
|
173 "key-len-min", "minimum key length" }, |
|
174 |
|
175 { TEST_BENCH_FETCH, BENCH_FETCH_KEY_LEN_MAX, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_len_max, 8 }}, |
|
176 "key-len-max", "maximum key length" }, |
|
177 |
|
178 { TEST_BENCH_FETCH, BENCH_FETCH_KEY_COUNT, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.key_count, 1 }}, |
|
179 "key-count", "how many keys to use" }, |
|
180 |
|
181 { TEST_BENCH_FETCH, BENCH_FETCH_DATA_LEN_MIN, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.data_len_min, 64 }}, |
|
182 "data-len-min", "minimum data length" }, |
|
183 |
|
184 { TEST_BENCH_FETCH, BENCH_FETCH_DATA_LEN_MAX, OPT_TYPE_UINT, { .uint = { &benchmark_fetch.data_len_max, 64 }}, |
|
185 "data-len-max", "maximum data length" }, |
140 }; |
186 }; |
141 |
187 |
142 void time_reset () { |
188 void time_reset () { |
143 // start timing |
189 // start timing |
144 assert(gettimeofday(&common.start, NULL) == 0); |
190 assert(gettimeofday(&common.start, NULL) == 0); |
150 assert(gettimeofday(&time, NULL) == 0); |
196 assert(gettimeofday(&time, NULL) == 0); |
151 |
197 |
152 return ((double) (time.tv_sec - common.start.tv_sec)) + ((double) (time.tv_usec - common.start.tv_usec)) / 1000000; |
198 return ((double) (time.tv_sec - common.start.tv_sec)) + ((double) (time.tv_usec - common.start.tv_usec)) / 1000000; |
153 } |
199 } |
154 |
200 |
|
201 int ratelimit (int count, int total) { |
|
202 return ((total / 10) ? (count % (total / 10) == 0) : 1); |
|
203 } |
|
204 |
155 |
205 |
156 |
206 |
157 void mc_init (int max_connections, memcache_cb cb_fn) { |
207 void mc_init (int max_connections, memcache_cb cb_fn) { |
158 // memcache init |
208 // memcache init |
159 if ((mc = memcache_alloc(cb_fn)) == NULL) |
209 if ((mc = memcache_alloc(cb_fn, common.pipeline_requests)) == NULL) |
160 ERROR("memcache_alloc"); |
210 ERROR("memcache_alloc"); |
161 |
211 |
162 // fix up the endpoint |
212 // fix up the endpoint |
163 endpoint_init(&server_endpoint, 11211); |
213 endpoint_init(&server_endpoint, 11211); |
164 |
214 |
165 if (endpoint_parse(&server_endpoint, "localhost")) |
215 if (endpoint_parse(&server_endpoint, "localhost")) |
166 ERROR("config_endpoint_parse"); |
216 ERROR("config_endpoint_parse"); |
167 |
217 |
168 // add the server |
218 // add the server |
169 if (memcache_add_server(mc, &server_endpoint, max_connections)) |
219 if (memcache_add_server(mc, &server_endpoint, common.max_connections)) |
170 ERROR("memcache_add_server"); |
220 ERROR("memcache_add_server"); |
171 |
221 |
172 INFO("[memcache] initialized with max_connections=%d", max_connections); |
222 INFO("[memcache] initialized with pipeline_requests=%c max_connections=%d", common.pipeline_requests ? 't' : 'f', common.max_connections); |
173 |
223 |
174 return; |
224 return; |
175 |
225 |
176 error: |
226 error: |
177 assert(0); |
227 assert(0); |
179 |
229 |
180 void dump_req (struct memcache_req *req, void *unused) { |
230 void dump_req (struct memcache_req *req, void *unused) { |
181 const struct memcache_obj *obj; |
231 const struct memcache_obj *obj; |
182 const struct memcache_buf *buf; |
232 const struct memcache_buf *buf; |
183 |
233 |
184 INFO("[%*s]: cmd=%s state=%s reply=%s", |
234 INFO("[%.*s]: cmd=%s state=%s reply=%s", |
185 (int) memcache_req_key(req)->len, memcache_req_key(req)->buf, |
235 (int) memcache_req_key(req)->len, memcache_req_key(req)->buf, |
186 memcache_command_str(memcache_req_cmd(req)), |
236 memcache_command_str(memcache_req_cmd(req)), |
187 memcache_state_str(memcache_req_state(req)), |
237 memcache_state_str(memcache_req_state(req)), |
188 memcache_reply_str(memcache_req_reply(req)) |
238 memcache_reply_str(memcache_req_reply(req)) |
189 ); |
239 ); |
417 |
467 |
418 assert(memcache_store(mc, MEMCACHE_CMD_STORE_SET, &keybuf->key, &obj, &buf, NULL) != NULL); |
468 assert(memcache_store(mc, MEMCACHE_CMD_STORE_SET, &keybuf->key, &obj, &buf, NULL) != NULL); |
419 } |
469 } |
420 } |
470 } |
421 |
471 |
|
472 void usage_opt (enum option_test test) { |
|
473 struct opt *opt; |
|
474 |
|
475 for (opt = option_info + 1; opt->code; opt++) { |
|
476 if (opt->test == test) { |
|
477 switch (opt->type) { |
|
478 case OPT_TYPE_BOOL: |
|
479 INFO("\t%-20s %c %s", opt->name, opt->data.bool.default_value ? 't' : 'f', opt->descr); |
|
480 break; |
|
481 |
|
482 case OPT_TYPE_UINT: |
|
483 INFO("\t%-20s %-6d %s", opt->name, opt->data.uint.default_value, opt->descr); |
|
484 break; |
|
485 |
|
486 case OPT_TYPE_STR: |
|
487 INFO("\t%-20s %-6s %s", opt->name, opt->data.str.default_value, opt->descr); |
|
488 break; |
|
489 |
|
490 default: |
|
491 assert(0); |
|
492 } |
|
493 } |
|
494 } |
|
495 } |
|
496 |
422 void usage (char *cmd) { |
497 void usage (char *cmd) { |
423 INFO( |
498 struct test *test; |
424 "Usage: %s <cmd> [<args> ... ]\n" |
499 |
425 "\n" |
500 INFO("Usage: %s <cmd> [<args> ... ]", cmd); |
426 "COMMANDS\n" |
501 |
427 "\n" |
502 INFO("\nCOMMON OPTIONS\n"); |
428 "benchmark_fetch:\n" |
503 |
429 "\tMeasure the speed of fetch requests\n" |
504 usage_opt(TEST_COMMON); |
430 "\t\n" |
505 |
431 "\tconn-max 1 number of connections to use\n" |
506 INFO("\nCOMMANDS\n"); |
432 "\treq-concurrency 1 number of requests to have running\n" |
507 |
433 "\treq-amount 500 number of requests to issue\n" |
508 for (test = test_list; test->name; test++) { |
434 "\tkey-prefix bf_ key prefix\n" |
509 INFO("%s:", test->name); |
435 "\tkey-len-min 8 minimum key lengt\n" |
510 INFO("\t%s", test->descr); |
436 "\tkey-len-max 8 maximum key length\n" |
511 INFO("\t"); |
437 "\tkey-count 1 how many keys to use\n" |
512 |
438 "\tdata-len-min 64 minimum data length\n" |
513 usage_opt(test->code); |
439 "\tdata-len-max 64 maximum data length\n", |
514 |
440 |
515 INFO("\t"); |
441 cmd |
516 } |
442 ); |
|
443 |
517 |
444 exit(1); |
518 exit(1); |
445 } |
519 } |
446 |
520 |
447 int main (int argc, char **argv) { |
521 int main (int argc, char **argv) { |
489 } |
568 } |
490 |
569 |
491 while ((c = getopt_long(argc, argv, "", options, &option_index)) != -1) { |
570 while ((c = getopt_long(argc, argv, "", options, &option_index)) != -1) { |
492 if (c <= OPT_CODE_INVALID || c >= OPT_CODE_MAX) |
571 if (c <= OPT_CODE_INVALID || c >= OPT_CODE_MAX) |
493 FATAL("invalid argument %s", options[option_index].name); |
572 FATAL("invalid argument %s", options[option_index].name); |
|
573 |
|
574 if (option_info[c].test != test->code && option_info[c].test != TEST_COMMON) |
|
575 FATAL("invalid option %s for test %s", options[option_index].name, test->name); |
494 |
576 |
495 switch (option_info[c].type) { |
577 switch (option_info[c].type) { |
|
578 case OPT_TYPE_BOOL: |
|
579 assert(optarg); |
|
580 |
|
581 switch (optarg[0]) { |
|
582 case 't': |
|
583 case '1': |
|
584 *option_info[c].data.bool.value = 1; |
|
585 break; |
|
586 |
|
587 case 'f': |
|
588 case '0': |
|
589 *option_info[c].data.bool.value = 0; |
|
590 break; |
|
591 |
|
592 default: |
|
593 FATAL("invalid true/false value: %s: %s", options[option_index].name, optarg); |
|
594 } |
|
595 |
|
596 break; |
|
597 |
496 case OPT_TYPE_UINT: |
598 case OPT_TYPE_UINT: |
497 assert(optarg); |
599 assert(optarg); |
498 |
600 |
499 *option_info[c].data.uint.value = strtol(optarg, &invalid, 10); |
601 *option_info[c].data.uint.value = strtol(optarg, &invalid, 10); |
500 |
602 |