|
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 |