Schooner memslap changes
[m6w6/libmemcached] / clients / memslap.c
1 /*
2 * memslap - memslap
3 *
4 * (c) Copyright 2009, Schooner Information Technology, Inc.
5 * All rights reserved.
6 * http://www.schoonerinfotech.com/
7 *
8 * Use and distribution licensed under the BSD license. See
9 * the COPYING file for full text.
10 *
11 * Authors:
12 * Brian Aker
13 * Mingqiang Zhuang <mingqiangzhuang@hengtiansoft.com>
14 *
15 */
16 #include <getopt.h>
17
18 #include "ms_sigsegv.h"
19 #include "ms_setting.h"
20 #include "ms_thread.h"
21
22 #define PROGRAM_NAME "memslap"
23 #define PROGRAM_DESCRIPTION "Generates workload against memcached servers."
24
25 /* options */
26 static struct option long_options[] =
27 {
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},
51 {0, 0, 0, 0},
52 };
53
54 /* Prototypes */
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);
71
72
73 /* initialize the global locks */
74 static void ms_sync_lock_init()
75 {
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);
79
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);
83
84 pthread_mutex_init(&ms_global.quit_mutex, NULL);
85 pthread_mutex_init(&ms_global.seq_mutex, NULL);
86 }
87
88 /* destroy the global locks */
89 static void ms_sync_lock_destroy()
90 {
91 pthread_mutex_destroy(&ms_global.init_lock.lock);
92 pthread_cond_destroy(&ms_global.init_lock.cond);
93
94 pthread_mutex_destroy(&ms_global.run_lock.lock);
95 pthread_cond_destroy(&ms_global.run_lock.cond);
96
97 pthread_mutex_destroy(&ms_global.quit_mutex);
98 pthread_mutex_destroy(&ms_global.seq_mutex);
99
100 if (ms_setting.stat_freq > 0) {
101 pthread_mutex_destroy(&ms_statistic.stat_mutex);
102 }
103 }
104
105 /* initialize the global structure */
106 static void ms_global_struct_init()
107 {
108 ms_sync_lock_init();
109 ms_global.finish_warmup = false;
110 ms_global.time_out = false;
111 }
112
113 /* destroy the global structure */
114 static void ms_global_struct_destroy()
115 {
116 ms_sync_lock_destroy();
117 }
118
119 /**
120 * output the version information
121 *
122 * @param command_name, the string of this process
123 */
124 static void ms_version_command(const char *command_name)
125 {
126 printf("%s v%u.%u\n", command_name, 1, 0);
127 exit(0);
128 }
129
130 /**
131 * get the description of the option
132 *
133 * @param option, option of command line
134 *
135 * @return char*, description of the command option
136 */
137 static const char * ms_lookup_help(ms_options_t option)
138 {
139 switch (option) {
140 case OPT_SERVERS:
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");
143 case OPT_VERSION:
144 return("Display the version of the application and then exit.");
145 case OPT_HELP:
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.");
154 case OPT_FIXED_LTH :
155 return("Fixed length of value.");
156 case OPT_VERIFY :
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.");
160 case OPT_TIME :
161 return("How long the test to run, suffix: s-seconds, m-minutes, h-hours,\n"
162 " d-days e.g.: --time=2h.");
163 case OPT_CONFIG_CMD:
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"
167 " Default 10k.");
168 case OPT_UDP:
169 return("UDP support, default memslap uses TCP, TCP port and UDP port of\n"
170 " server must be same.");
171 case OPT_EXPIRE:
172 return("The proportion of objects with expire time, e.g.: --exp_verify=0.01.\n"
173 " Default no object with expire time");
174 case OPT_OVERWRITE:
175 return("The proportion of objects need overwrite, e.g.: --overwrite=0.01.\n"
176 " Default never overwrite object.");
177 case OPT_STAT_FREQ:
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.");
182 case OPT_RECONNECT:
183 return("Reconnect support, when connection is closed it will be reconnected.");
184 case OPT_VERBOSE:
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.");
190 case OPT_TPS:
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.");
194 default:
195 return "Forgot to document this option :)";
196 };
197 }
198
199 /**
200 * output the help information
201 *
202 * @param command_name, the string of this process
203 * @param description, description of this process
204 * @param long_options, global options array
205 */
206 void ms_help_command(const char *command_name, const char *description)
207 {
208 char *help_message = NULL;
209
210 printf("%s v%u.%u\n", command_name, 1, 0);
211 printf(" %s\n\n", description);
212 printf("Usage:\n"
213 " memslap -hV | -s servers [-F config_file] [-t time | -x exe_num] [...]\n\n"
214 "Options:\n");
215
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);
221 }
222 }
223
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");
232
233 exit(0);
234 }
235
236 /* used to parse the time string */
237 static int64_t ms_parse_time()
238 {
239 int64_t ret = 0;
240 char unit = optarg[strlen(optarg) - 1];
241 optarg[strlen(optarg) - 1] = '\0';
242 ret = atoi(optarg);
243
244 switch (unit) {
245 case 'd':
246 case 'D':
247 ret *= 24;
248 case 'h':
249 case 'H':
250 ret *= 60;
251 case 'm':
252 case 'M':
253 ret *= 60;
254 case 's':
255 case 'S':
256 break;
257 default:
258 ret = -1;
259 break;
260 }
261
262 return ret;
263 }
264
265 /* used to parse the size string */
266 static int64_t ms_parse_size()
267 {
268 int64_t ret = -1;
269 char unit = optarg[strlen(optarg) - 1];
270 optarg[strlen(optarg) - 1] = '\0';
271 ret = strtoll(optarg, (char **)NULL, 10);
272
273 switch (unit) {
274 case 'k':
275 case 'K':
276 ret *= 1024;
277 break;
278 case 'm':
279 case 'M':
280 ret *= 1024 * 1024;
281 break;
282 case 'g':
283 case 'G':
284 ret *= 1024 * 1024 * 1024;
285 break;
286 default:
287 ret = -1;
288 break;
289 }
290
291 return ret;
292 }
293
294 /* used to parse the options of command line */
295 static void ms_options_parse(int argc, char *argv[])
296 {
297 int option_index= 0;
298 int option_rv;
299
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) {
303
304 switch (option_rv) {
305 case 0:
306 break;
307
308 case OPT_VERSION: /* --version or -V */
309 ms_version_command(PROGRAM_NAME);
310 break;
311
312 case OPT_HELP: /* --help or -h */
313 ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
314 break;
315
316 case OPT_SERVERS: /* --servers or -s */
317 ms_setting.srv_str= strdup(optarg);
318 break;
319
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");
324 exit(1);
325 }
326 break;
327
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");
332 exit(1);
333 }
334 break;
335
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");
340 exit(1);
341 }
342 break;
343
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");
349 exit(1);
350 }
351 break;
352
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");
358 exit(1);
359 }
360 break;
361
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");
366 exit(1);
367 }
368 break;
369
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");
376 exit(1);
377 }
378
379 if (ms_setting.run_time == 0) {
380 fprintf(stderr, "Running time can not be 0. :-)\n");
381 exit(1);
382 }
383 break;
384
385 case OPT_CONFIG_CMD: /* --cfg_cmd or -F */
386 ms_setting.cfg_file = strdup(optarg);
387 break;
388
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");
394 exit(1);
395 }
396 break;
397
398 case OPT_UDP: /* --udp or -U*/
399 ms_setting.udp = true;
400 break;
401
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");
407 exit(1);
408 }
409 break;
410
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");
416 exit(1);
417 }
418 break;
419
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");
427 exit(1);
428 }
429
430 if (ms_setting.stat_freq == 0) {
431 fprintf(stderr, "The frequency of dumping statistic information "
432 "can not be 0. :-)\n");
433 exit(1);
434 }
435 break;
436
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");
442 exit(1);
443 }
444 break;
445
446 case OPT_RECONNECT: /* --reconnect or -R */
447 ms_setting.reconnect = true;
448 break;
449
450 case OPT_VERBOSE: /* --verbose or -b */
451 ms_setting.verbose = true;
452 break;
453
454 case OPT_FACEBOOK_TEST: /* --facebook or -a */
455 ms_setting.facebook_test = true;
456 break;
457
458 case OPT_BINARY_PROTOCOL: /* --binary or -B */
459 ms_setting.binary_prot = true;
460 break;
461
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");
467 exit(1);
468 }
469 break;
470
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 "
475 "than 0.:-)\n");
476 exit(1);
477 }
478 break;
479
480 case '?':
481 /* getopt_long already printed an error message. */
482 exit(1);
483
484 default:
485 abort();
486 }
487 }
488 }
489
490 static int ms_check_para()
491 {
492 if (ms_setting.srv_str == NULL) {
493 fprintf(stderr, "No Servers provided.\n\n");
494 return -1;
495 }
496
497 if (ms_setting.nconns % ms_setting.nthreads != 0) {
498 fprintf(stderr, "Concurrency must be the multiples of threads count.\n");
499 return -1;
500 }
501
502 if (ms_setting.win_size % UNIT_ITEMS_COUNT != 0) {
503 fprintf(stderr, "Window size must be the multiples of 1024.\n\n");
504 return -1;
505 }
506
507 return 0;
508 }
509
510 /* initialize the statistic structure */
511 static void ms_statistic_init()
512 {
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");
517 }
518
519 /* initialize the global state structure */
520 static void ms_stats_init()
521 {
522 memset(&ms_stats, 0, sizeof(ms_stats_t));
523 if (ms_setting.stat_freq > 0) {
524 ms_statistic_init();
525 }
526 }
527
528 /* use to output the statistic */
529 static void ms_print_statistics(int in_time)
530 {
531 int obj_size = (int)(ms_setting.avg_key_size + ms_setting.avg_val_size);
532
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);
540 }
541
542 /* used to print the states of memslap */
543 static void ms_print_memslap_stats(struct timeval *start_time, struct timeval *end_time)
544 {
545 char buf[1024];
546 char *pos = buf;
547
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);
551
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);
557 }
558
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);
564 }
565
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);
569
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);
574 }
575
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);
580 }
581
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));
589
590 fprintf(stdout, "%s", buf);
591 fflush(stdout);
592 }
593
594 /* the loop of the main thread, wait the work threads to complete */
595 static void ms_monitor_slap_mode()
596 {
597 int second = 0;
598 struct timeval start_time, end_time;
599
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);
606 }
607 pthread_mutex_unlock(&ms_global.init_lock.lock);
608 }
609
610 ms_global.finish_warmup = true;
611
612 /* running in "run time" mode, user specify run time */
613 if (ms_setting.run_time > 0) {
614 gettimeofday(&start_time, NULL);
615 while (1) {
616 sleep(1);
617 second++;
618
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);
622 }
623
624 if (ms_setting.run_time <= second) {
625 ms_global.time_out = true;
626 break;
627 }
628
629 /* all connections disconnect */
630 if (second > 5 && ms_stats.active_conns == 0) {
631 break;
632 }
633 }
634 gettimeofday(&end_time, NULL);
635 sleep(1); /* wait all threads clean up */
636 } else {
637 /* running in "execute number" mode, user specify execute number */
638 gettimeofday(&start_time, NULL);
639
640 /*
641 * We loop until we know that all connects have cleaned up.
642 */
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);
646 }
647 pthread_mutex_unlock(&ms_global.run_lock.lock);
648
649 gettimeofday(&end_time, NULL);
650 }
651
652 ms_print_memslap_stats(&start_time, &end_time);
653 }
654
655 /* the main function */
656 int main(int argc, char *argv[])
657 {
658 srandom((unsigned int)time(NULL));
659 ms_global_struct_init();
660
661 /* initialization */
662 ms_setting_init_pre();
663 ms_options_parse(argc, argv);
664 if (ms_check_para()) {
665 ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
666 exit(1);
667 }
668 ms_setting_init_post();
669 ms_stats_init();
670 ms_thread_init();
671
672 /* waiting work thread complete its task */
673 ms_monitor_slap_mode();
674
675 /* clean up */
676 ms_thread_cleanup();
677 ms_global_struct_destroy();
678 ms_setting_cleanup();
679
680 return 0;
681 }