92f26e798e83fbeaaf767d2879610dc96977ea09
4 * (c) Copyright 2009, Schooner Information Technology, Inc.
6 * http://www.schoonerinfotech.com/
8 * Use and distribution licensed under the BSD license. See
9 * the COPYING file for full text.
13 * Mingqiang Zhuang <mingqiangzhuang@hengtiansoft.com>
18 #include "ms_sigsegv.h"
19 #include "ms_setting.h"
20 #include "ms_thread.h"
22 #define PROGRAM_NAME "memslap"
23 #define PROGRAM_DESCRIPTION "Generates workload against memcached servers."
26 static struct option long_options
[] =
28 {"servers", required_argument
, NULL
, OPT_SERVERS
},
29 {"threads", required_argument
, NULL
, OPT_THREAD_NUMBER
},
30 {"concurrency", required_argument
, NULL
, OPT_CONCURRENCY
},
31 {"conn_sock", required_argument
, NULL
, OPT_SOCK_PER_CONN
},
32 {"execute_number", required_argument
, NULL
, OPT_EXECUTE_NUMBER
},
33 {"time", required_argument
, NULL
, OPT_TIME
},
34 {"cfg_cmd", required_argument
, NULL
, OPT_CONFIG_CMD
},
35 {"win_size", required_argument
, NULL
, OPT_WINDOW_SIZE
},
36 {"fixed_size", required_argument
, NULL
, OPT_FIXED_LTH
},
37 {"verify", required_argument
, NULL
, OPT_VERIFY
},
38 {"division", required_argument
, NULL
, OPT_GETS_DIVISION
},
39 {"stat_freq", required_argument
, NULL
, OPT_STAT_FREQ
},
40 {"exp_verify", required_argument
, NULL
, OPT_EXPIRE
},
41 {"overwrite", required_argument
, NULL
, OPT_OVERWRITE
},
42 {"reconnect", no_argument
, NULL
, OPT_RECONNECT
},
43 {"udp", no_argument
, NULL
, OPT_UDP
},
44 {"facebook", no_argument
, NULL
, OPT_FACEBOOK_TEST
},
45 {"binary", no_argument
, NULL
, OPT_BINARY_PROTOCOL
},
46 {"tps", required_argument
, NULL
, OPT_TPS
},
47 {"rep_write", required_argument
, NULL
, OPT_REP_WRITE_SRV
},
48 {"verbose", no_argument
, NULL
, OPT_VERBOSE
},
49 {"help", no_argument
, NULL
, OPT_HELP
},
50 {"version", no_argument
, NULL
, OPT_VERSION
},
55 static void ms_sync_lock_init(void);
56 static void ms_sync_lock_destroy(void);
57 static void ms_global_struct_init(void);
58 static void ms_global_struct_destroy(void);
59 static void ms_version_command(const char *command_name
);
60 static const char * ms_lookup_help(ms_options_t option
);
61 static int64_t ms_parse_time(void);
62 static int64_t ms_parse_size(void);
63 static void ms_options_parse(int argc
, char *argv
[]);
64 static int ms_check_para(void);
65 static void ms_statistic_init(void);
66 static void ms_stats_init(void);
67 static void ms_print_statistics(int time
);
68 static void ms_print_memslap_stats(struct timeval
*start_time
, struct timeval
*end_time
);
69 static void ms_monitor_slap_mode(void);
70 void ms_help_command(const char *command_name
, const char *description
);
73 /* initialize the global locks */
74 static void ms_sync_lock_init()
76 ms_global
.init_lock
.count
= 0;
77 pthread_mutex_init(&ms_global
.init_lock
.lock
, NULL
);
78 pthread_cond_init(&ms_global
.init_lock
.cond
, NULL
);
80 ms_global
.run_lock
.count
= 0;
81 pthread_mutex_init(&ms_global
.run_lock
.lock
, NULL
);
82 pthread_cond_init(&ms_global
.run_lock
.cond
, NULL
);
84 pthread_mutex_init(&ms_global
.quit_mutex
, NULL
);
85 pthread_mutex_init(&ms_global
.seq_mutex
, NULL
);
88 /* destroy the global locks */
89 static void ms_sync_lock_destroy()
91 pthread_mutex_destroy(&ms_global
.init_lock
.lock
);
92 pthread_cond_destroy(&ms_global
.init_lock
.cond
);
94 pthread_mutex_destroy(&ms_global
.run_lock
.lock
);
95 pthread_cond_destroy(&ms_global
.run_lock
.cond
);
97 pthread_mutex_destroy(&ms_global
.quit_mutex
);
98 pthread_mutex_destroy(&ms_global
.seq_mutex
);
100 if (ms_setting
.stat_freq
> 0) {
101 pthread_mutex_destroy(&ms_statistic
.stat_mutex
);
105 /* initialize the global structure */
106 static void ms_global_struct_init()
109 ms_global
.finish_warmup
= false;
110 ms_global
.time_out
= false;
113 /* destroy the global structure */
114 static void ms_global_struct_destroy()
116 ms_sync_lock_destroy();
120 * output the version information
122 * @param command_name, the string of this process
124 static void ms_version_command(const char *command_name
)
126 printf("%s v%u.%u\n", command_name
, 1, 0);
131 * get the description of the option
133 * @param option, option of command line
135 * @return char*, description of the command option
137 static const char * ms_lookup_help(ms_options_t option
)
141 return("List one or more servers to connect. Servers count must be less than\n"
142 " threads count. e.g.: --servers=localhost:1234,localhost:11211");
144 return("Display the version of the application and then exit.");
146 return("Display this message and then exit.");
147 case OPT_EXECUTE_NUMBER
:
148 return("Number of operations(get and set) to execute for the\n"
149 " given test. Default 1000000.");
150 case OPT_THREAD_NUMBER
:
151 return("Number of threads to startup, better equal to CPU numbers. Default 8.");
152 case OPT_CONCURRENCY
:
153 return("Number of concurrency to simulate with load. Default 128.");
155 return("Fixed length of value.");
157 return("The proportion of date verification, e.g.: --verify=0.01");
158 case OPT_GETS_DIVISION
:
159 return("Number of keys to multi-get once. Default 1, means single get.");
161 return("How long the test to run, suffix: s-seconds, m-minutes, h-hours,\n"
162 " d-days e.g.: --time=2h.");
164 return("Load the configure file to get command,key and value distribution list.");
165 case OPT_WINDOW_SIZE
:
166 return("Task window size of each concurrency, suffix: K, M e.g.: --win_size=10k.\n"
169 return("UDP support, default memslap uses TCP, TCP port and UDP port of\n"
170 " server must be same.");
172 return("The proportion of objects with expire time, e.g.: --exp_verify=0.01.\n"
173 " Default no object with expire time");
175 return("The proportion of objects need overwrite, e.g.: --overwrite=0.01.\n"
176 " Default never overwrite object.");
178 return("Frequency of dumping statistic information. suffix: s-seconds,\n"
179 " m-minutes, e.g.: --resp_freq=10s.");
180 case OPT_SOCK_PER_CONN
:
181 return("Number of TCP socks per concurrency. Default 1.");
183 return("Reconnect support, when connection is closed it will be reconnected.");
185 return("Whether it outputs detailed information when verification fails.");
186 case OPT_FACEBOOK_TEST
:
187 return("Whether it enables facebook test feature, set with TCP and multi-get with UDP.");
188 case OPT_BINARY_PROTOCOL
:
189 return("Whether it enables binary protocol. Default with ASCII protocol.");
191 return("Expected throughput, suffix: K, e.g.: --tps=10k.");
192 case OPT_REP_WRITE_SRV
:
193 return("The first nth servers can write data, e.g.: --rep_write=2.");
195 return "Forgot to document this option :)";
200 * output the help information
202 * @param command_name, the string of this process
203 * @param description, description of this process
204 * @param long_options, global options array
206 void ms_help_command(const char *command_name
, const char *description
)
208 char *help_message
= NULL
;
210 printf("%s v%u.%u\n", command_name
, 1, 0);
211 printf(" %s\n\n", description
);
213 " memslap -hV | -s servers [-F config_file] [-t time | -x exe_num] [...]\n\n"
216 for (int x
= 0; long_options
[x
].name
; x
++) {
217 printf(" -%c, --%s%c\n", long_options
[x
].val
, long_options
[x
].name
,
218 long_options
[x
].has_arg
? '=' : ' ');
219 if ((help_message
= (char *)ms_lookup_help(long_options
[x
].val
)) != NULL
) {
220 printf(" %s\n", help_message
);
224 printf("\nExamples:\n"
225 " memslap -s 127.0.0.1:11211 -S 5s\n"
226 " memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b\n"
227 " memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2\n"
228 " memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k\n"
229 " memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40\n"
230 " memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m\n"
231 " memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2\n\n");
236 /* used to parse the time string */
237 static int64_t ms_parse_time()
240 char unit
= optarg
[strlen(optarg
) - 1];
241 optarg
[strlen(optarg
) - 1] = '\0';
265 /* used to parse the size string */
266 static int64_t ms_parse_size()
269 char unit
= optarg
[strlen(optarg
) - 1];
270 optarg
[strlen(optarg
) - 1] = '\0';
271 ret
= strtoll(optarg
, (char **)NULL
, 10);
284 ret
*= 1024 * 1024 * 1024;
294 /* used to parse the options of command line */
295 static void ms_options_parse(int argc
, char *argv
[])
300 while ((option_rv
= getopt_long(argc
, argv
, "VhURbaBs:x:T:c:X:v:d:"
301 "t:S:F:w:e:o:n:P:p:",
302 long_options
, &option_index
)) != -1) {
308 case OPT_VERSION
: /* --version or -V */
309 ms_version_command(PROGRAM_NAME
);
312 case OPT_HELP
: /* --help or -h */
313 ms_help_command(PROGRAM_NAME
, PROGRAM_DESCRIPTION
);
316 case OPT_SERVERS
: /* --servers or -s */
317 ms_setting
.srv_str
= strdup(optarg
);
320 case OPT_CONCURRENCY
: /* --concurrency or -c */
321 ms_setting
.nconns
= atoi(optarg
);
322 if (ms_setting
.nconns
<= 0) {
323 fprintf(stderr
, "Concurrency must be greater than 0.:-)\n");
328 case OPT_EXECUTE_NUMBER
: /* --execute_number or -x */
329 ms_setting
.exec_num
= atoll(optarg
);
330 if (ms_setting
.exec_num
<= 0) {
331 fprintf(stderr
, "Execute number must be greater than 0.:-)\n");
336 case OPT_THREAD_NUMBER
: /* --threads or -T */
337 ms_setting
.nthreads
= atoi(optarg
);
338 if (ms_setting
.nthreads
<= 0) {
339 fprintf(stderr
, "Threads number must be greater than 0.:-)\n");
344 case OPT_FIXED_LTH
: /* --fixed_size or -X */
345 ms_setting
.fixed_value_size
= (size_t)atoi(optarg
);
346 if (ms_setting
.fixed_value_size
<= 0
347 || ms_setting
.fixed_value_size
> MAX_VALUE_SIZE
) {
348 fprintf(stderr
, "Value size must be between 0 and 1M.:-)\n");
353 case OPT_VERIFY
: /* --verify or -v */
354 ms_setting
.verify_percent
= atof(optarg
);
355 if (ms_setting
.verify_percent
<= 0 || ms_setting
.verify_percent
> 1.0) {
356 fprintf(stderr
, "Data verification rate must be "
357 "greater than 0 and less than 1.0. :-)\n");
362 case OPT_GETS_DIVISION
: /* --division or -d */
363 ms_setting
.mult_key_num
= atoi(optarg
);
364 if (ms_setting
.mult_key_num
<= 0) {
365 fprintf(stderr
, "Multi-get key number must be greater than 0.:-)\n");
370 case OPT_TIME
: /* --time or -t */
371 ms_setting
.run_time
= (int)ms_parse_time();
372 if (ms_setting
.run_time
== -1) {
373 fprintf(stderr
, "Please specify the run time. :-)\n"
374 "'s' for second, 'm' for minute, 'h' for hour, "
375 "'d' for day. e.g.: --time=24h (means 24 hours).\n");
379 if (ms_setting
.run_time
== 0) {
380 fprintf(stderr
, "Running time can not be 0. :-)\n");
385 case OPT_CONFIG_CMD
: /* --cfg_cmd or -F */
386 ms_setting
.cfg_file
= strdup(optarg
);
389 case OPT_WINDOW_SIZE
: /* --win_size or -w */
390 ms_setting
.win_size
= (size_t)ms_parse_size();
391 if (ms_setting
.win_size
== (size_t)-1) {
392 fprintf(stderr
, "Please specify the item window size. :-)\n"
393 "e.g.: --win_size=10k (means 10k task window size).\n");
398 case OPT_UDP
: /* --udp or -U*/
399 ms_setting
.udp
= true;
402 case OPT_EXPIRE
: /* --exp_verify or -e */
403 ms_setting
.exp_ver_per
= atof(optarg
);
404 if (ms_setting
.exp_ver_per
<= 0 || ms_setting
.exp_ver_per
> 1.0) {
405 fprintf(stderr
, "Expire time verification rate must be "
406 "greater than 0 and less than 1.0. :-)\n");
411 case OPT_OVERWRITE
: /* --overwrite or -o */
412 ms_setting
.overwrite_percent
= atof(optarg
);
413 if (ms_setting
.overwrite_percent
<= 0 || ms_setting
.overwrite_percent
> 1.0) {
414 fprintf(stderr
, "Objects overwrite rate must be "
415 "greater than 0 and less than 1.0. :-)\n");
420 case OPT_STAT_FREQ
: /* --stat_freq or -S */
421 ms_setting
.stat_freq
= (int)ms_parse_time();
422 if (ms_setting
.stat_freq
== -1) {
423 fprintf(stderr
, "Please specify the frequency of dumping "
424 "statistic information. :-)\n"
425 "'s' for second, 'm' for minute, 'h' for hour, "
426 "'d' for day. e.g.: --time=24h (means 24 hours).\n");
430 if (ms_setting
.stat_freq
== 0) {
431 fprintf(stderr
, "The frequency of dumping statistic information "
432 "can not be 0. :-)\n");
437 case OPT_SOCK_PER_CONN
: /* --conn_sock or -n */
438 ms_setting
.sock_per_conn
= atoi(optarg
);
439 if (ms_setting
.sock_per_conn
<= 0) {
440 fprintf(stderr
, "Number of socks of each concurrency "
441 "must be greater than 0.:-)\n");
446 case OPT_RECONNECT
: /* --reconnect or -R */
447 ms_setting
.reconnect
= true;
450 case OPT_VERBOSE
: /* --verbose or -b */
451 ms_setting
.verbose
= true;
454 case OPT_FACEBOOK_TEST
: /* --facebook or -a */
455 ms_setting
.facebook_test
= true;
458 case OPT_BINARY_PROTOCOL
: /* --binary or -B */
459 ms_setting
.binary_prot
= true;
462 case OPT_TPS
: /* --tps or -P */
463 ms_setting
.expected_tps
= (int)ms_parse_size();
464 if (ms_setting
.expected_tps
== -1) {
465 fprintf(stderr
, "Please specify the item expected throughput. :-)\n"
466 "e.g.: --tps=10k (means 10k throughput).\n");
471 case OPT_REP_WRITE_SRV
: /* --rep_write or -p */
472 ms_setting
.rep_write_srv
= atoi(optarg
);
473 if (ms_setting
.rep_write_srv
<= 0) {
474 fprintf(stderr
, "Number of replication writing server must be greater "
481 /* getopt_long already printed an error message. */
490 static int ms_check_para()
492 if (ms_setting
.srv_str
== NULL
) {
493 fprintf(stderr
, "No Servers provided.\n\n");
497 if (ms_setting
.nconns
% ms_setting
.nthreads
!= 0) {
498 fprintf(stderr
, "Concurrency must be the multiples of threads count.\n");
502 if (ms_setting
.win_size
% UNIT_ITEMS_COUNT
!= 0) {
503 fprintf(stderr
, "Window size must be the multiples of 1024.\n\n");
510 /* initialize the statistic structure */
511 static void ms_statistic_init()
513 pthread_mutex_init(&ms_statistic
.stat_mutex
, NULL
);
514 ms_init_stats(&ms_statistic
.get_stat
, "Get");
515 ms_init_stats(&ms_statistic
.set_stat
, "Set");
516 ms_init_stats(&ms_statistic
.total_stat
, "Total");
519 /* initialize the global state structure */
520 static void ms_stats_init()
522 memset(&ms_stats
, 0, sizeof(ms_stats_t
));
523 if (ms_setting
.stat_freq
> 0) {
528 /* use to output the statistic */
529 static void ms_print_statistics(int in_time
)
531 int obj_size
= (int)(ms_setting
.avg_key_size
+ ms_setting
.avg_val_size
);
533 printf("\033[1;1H\033[2J\n");
534 ms_dump_format_stats(&ms_statistic
.get_stat
, in_time
,
535 ms_setting
.stat_freq
, obj_size
);
536 ms_dump_format_stats(&ms_statistic
.set_stat
, in_time
,
537 ms_setting
.stat_freq
, obj_size
);
538 ms_dump_format_stats(&ms_statistic
.total_stat
, in_time
,
539 ms_setting
.stat_freq
, obj_size
);
542 /* used to print the states of memslap */
543 static void ms_print_memslap_stats(struct timeval
*start_time
, struct timeval
*end_time
)
548 pos
+= sprintf(pos
, "cmd_get: %llu\n", (unsigned long long)ms_stats
.cmd_get
);
549 pos
+= sprintf(pos
, "cmd_set: %llu\n", (unsigned long long)ms_stats
.cmd_set
);
550 pos
+= sprintf(pos
, "get_misses: %llu\n", (unsigned long long)ms_stats
.get_misses
);
552 if (ms_setting
.verify_percent
> 0) {
553 pos
+= sprintf(pos
, "verify_misses: %llu\n",
554 (unsigned long long)ms_stats
.vef_miss
);
555 pos
+= sprintf(pos
, "verify_failed: %llu\n",
556 (unsigned long long)ms_stats
.vef_failed
);
559 if (ms_setting
.exp_ver_per
> 0) {
560 pos
+= sprintf(pos
, "expired_get: %llu\n",
561 (unsigned long long)ms_stats
.exp_get
);
562 pos
+= sprintf(pos
, "unexpired_unget: %llu\n",
563 (unsigned long long)ms_stats
.unexp_unget
);
566 pos
+= sprintf(pos
, "written_bytes: %llu\n", (unsigned long long)ms_stats
.bytes_written
);
567 pos
+= sprintf(pos
, "read_bytes: %llu\n", (unsigned long long)ms_stats
.bytes_read
);
568 pos
+= sprintf(pos
, "object_bytes: %llu\n", (unsigned long long)ms_stats
.obj_bytes
);
570 if (ms_setting
.udp
|| ms_setting
.facebook_test
) {
571 pos
+= sprintf(pos
, "packet_disorder: %llu\n", (unsigned long long)ms_stats
.pkt_disorder
);
572 pos
+= sprintf(pos
, "packet_drop: %llu\n", (unsigned long long)ms_stats
.pkt_drop
);
573 pos
+= sprintf(pos
, "udp_timeout: %llu\n", (unsigned long long)ms_stats
.udp_timeout
);
576 if (ms_setting
.stat_freq
> 0) {
577 ms_dump_stats(&ms_statistic
.get_stat
);
578 ms_dump_stats(&ms_statistic
.set_stat
);
579 ms_dump_stats(&ms_statistic
.total_stat
);
582 int64_t time_diff
= ms_time_diff(start_time
, end_time
);
583 pos
+= sprintf(pos
, "\nRun time: %.1fs Ops: %llu TPS: %.0Lf Net_rate: %.1fM/s\n",
584 (double)time_diff
/ 1000000,
585 (unsigned long long)(ms_stats
.cmd_get
+ ms_stats
.cmd_set
),
586 (ms_stats
.cmd_get
+ ms_stats
.cmd_set
) / ((long double)time_diff
/ 1000000),
587 (double)(ms_stats
.bytes_written
+ ms_stats
.bytes_read
) / 1024 / 1024
588 / ((double)time_diff
/ 1000000));
590 fprintf(stdout
, "%s", buf
);
594 /* the loop of the main thread, wait the work threads to complete */
595 static void ms_monitor_slap_mode()
598 struct timeval start_time
, end_time
;
600 /* only when there is no set operation it need warm up */
601 if (ms_setting
.cmd_distr
[CMD_SET
].cmd_prop
< PROP_ERROR
) {
602 /* Wait all the connects complete warm up. */
603 pthread_mutex_lock(&ms_global
.init_lock
.lock
);
604 while (ms_global
.init_lock
.count
< ms_setting
.nconns
) {
605 pthread_cond_wait(&ms_global
.init_lock
.cond
, &ms_global
.init_lock
.lock
);
607 pthread_mutex_unlock(&ms_global
.init_lock
.lock
);
610 ms_global
.finish_warmup
= true;
612 /* running in "run time" mode, user specify run time */
613 if (ms_setting
.run_time
> 0) {
614 gettimeofday(&start_time
, NULL
);
619 if (ms_setting
.stat_freq
> 0 && second
% ms_setting
.stat_freq
== 0
620 && ms_stats
.active_conns
>= ms_setting
.nconns
) {
621 ms_print_statistics(second
);
624 if (ms_setting
.run_time
<= second
) {
625 ms_global
.time_out
= true;
629 /* all connections disconnect */
630 if (second
> 5 && ms_stats
.active_conns
== 0) {
634 gettimeofday(&end_time
, NULL
);
635 sleep(1); /* wait all threads clean up */
637 /* running in "execute number" mode, user specify execute number */
638 gettimeofday(&start_time
, NULL
);
641 * We loop until we know that all connects have cleaned up.
643 pthread_mutex_lock(&ms_global
.run_lock
.lock
);
644 while (ms_global
.run_lock
.count
< ms_setting
.nconns
) {
645 pthread_cond_wait(&ms_global
.run_lock
.cond
, &ms_global
.run_lock
.lock
);
647 pthread_mutex_unlock(&ms_global
.run_lock
.lock
);
649 gettimeofday(&end_time
, NULL
);
652 ms_print_memslap_stats(&start_time
, &end_time
);
655 /* the main function */
656 int main(int argc
, char *argv
[])
658 srandom((unsigned int)time(NULL
));
659 ms_global_struct_init();
662 ms_setting_init_pre();
663 ms_options_parse(argc
, argv
);
664 if (ms_check_para()) {
665 ms_help_command(PROGRAM_NAME
, PROGRAM_DESCRIPTION
);
668 ms_setting_init_post();
672 /* waiting work thread complete its task */
673 ms_monitor_slap_mode();
677 ms_global_struct_destroy();
678 ms_setting_cleanup();