Merged trunk.
[m6w6/libmemcached] / clients / memslap.c
1 /*
2 * 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 \
24 "Generates workload against memcached servers."
25
26 /* options */
27 static struct option long_options[]=
28 {
29 { "servers", required_argument, NULL,
30 OPT_SERVERS },
31 { "threads", required_argument, NULL,
32 OPT_THREAD_NUMBER },
33 { "concurrency", required_argument, NULL,
34 OPT_CONCURRENCY },
35 { "conn_sock", required_argument, NULL,
36 OPT_SOCK_PER_CONN },
37 { "execute_number", required_argument, NULL,
38 OPT_EXECUTE_NUMBER },
39 { "time", required_argument, NULL,
40 OPT_TIME },
41 { "cfg_cmd", required_argument, NULL,
42 OPT_CONFIG_CMD },
43 { "win_size", required_argument, NULL,
44 OPT_WINDOW_SIZE },
45 { "fixed_size", required_argument, NULL,
46 OPT_FIXED_LTH },
47 { "verify", required_argument, NULL,
48 OPT_VERIFY },
49 { "division", required_argument, NULL,
50 OPT_GETS_DIVISION },
51 { "stat_freq", required_argument, NULL,
52 OPT_STAT_FREQ },
53 { "exp_verify", required_argument, NULL,
54 OPT_EXPIRE },
55 { "overwrite", required_argument, NULL,
56 OPT_OVERWRITE },
57 { "reconnect", no_argument, NULL,
58 OPT_RECONNECT },
59 { "udp", no_argument, NULL,
60 OPT_UDP },
61 { "facebook", no_argument, NULL,
62 OPT_FACEBOOK_TEST },
63 { "binary", no_argument, NULL,
64 OPT_BINARY_PROTOCOL },
65 { "tps", required_argument, NULL,
66 OPT_TPS },
67 { "rep_write", required_argument, NULL,
68 OPT_REP_WRITE_SRV },
69 { "verbose", no_argument, NULL,
70 OPT_VERBOSE },
71 { "help", no_argument, NULL,
72 OPT_HELP },
73 { "version", no_argument, NULL,
74 OPT_VERSION },
75 { 0, 0, 0, 0 },
76 };
77
78 /* Prototypes */
79 static void ms_sync_lock_init(void);
80 static void ms_sync_lock_destroy(void);
81 static void ms_global_struct_init(void);
82 static void ms_global_struct_destroy(void);
83 static void ms_version_command(const char *command_name);
84 static const char *ms_lookup_help(ms_options_t option);
85 static int64_t ms_parse_time(void);
86 static int64_t ms_parse_size(void);
87 static void ms_options_parse(int argc, char *argv[]);
88 static int ms_check_para(void);
89 static void ms_statistic_init(void);
90 static void ms_stats_init(void);
91 static void ms_print_statistics(int time);
92 static void ms_print_memslap_stats(struct timeval *start_time,
93 struct timeval *end_time);
94 static void ms_monitor_slap_mode(void);
95 void ms_help_command(const char *command_name, const char *description);
96
97
98 /* initialize the global locks */
99 static void ms_sync_lock_init()
100 {
101 ms_global.init_lock.count= 0;
102 pthread_mutex_init(&ms_global.init_lock.lock, NULL);
103 pthread_cond_init(&ms_global.init_lock.cond, NULL);
104
105 ms_global.run_lock.count= 0;
106 pthread_mutex_init(&ms_global.run_lock.lock, NULL);
107 pthread_cond_init(&ms_global.run_lock.cond, NULL);
108
109 pthread_mutex_init(&ms_global.quit_mutex, NULL);
110 pthread_mutex_init(&ms_global.seq_mutex, NULL);
111 } /* ms_sync_lock_init */
112
113
114 /* destroy the global locks */
115 static void ms_sync_lock_destroy()
116 {
117 pthread_mutex_destroy(&ms_global.init_lock.lock);
118 pthread_cond_destroy(&ms_global.init_lock.cond);
119
120 pthread_mutex_destroy(&ms_global.run_lock.lock);
121 pthread_cond_destroy(&ms_global.run_lock.cond);
122
123 pthread_mutex_destroy(&ms_global.quit_mutex);
124 pthread_mutex_destroy(&ms_global.seq_mutex);
125
126 if (ms_setting.stat_freq > 0)
127 {
128 pthread_mutex_destroy(&ms_statistic.stat_mutex);
129 }
130 } /* ms_sync_lock_destroy */
131
132
133 /* initialize the global structure */
134 static void ms_global_struct_init()
135 {
136 ms_sync_lock_init();
137 ms_global.finish_warmup= false;
138 ms_global.time_out= false;
139 }
140
141
142 /* destroy the global structure */
143 static void ms_global_struct_destroy()
144 {
145 ms_sync_lock_destroy();
146 }
147
148
149 /**
150 * output the version information
151 *
152 * @param command_name, the string of this process
153 */
154 static void ms_version_command(const char *command_name)
155 {
156 printf("%s v%u.%u\n", command_name, 1, 0);
157 exit(0);
158 }
159
160
161 /**
162 * get the description of the option
163 *
164 * @param option, option of command line
165 *
166 * @return char*, description of the command option
167 */
168 static const char *ms_lookup_help(ms_options_t option)
169 {
170 switch (option)
171 {
172 case OPT_SERVERS:
173 return
174 "List one or more servers to connect. Servers count must be less than\n"
175 " threads count. e.g.: --servers=localhost:1234,localhost:11211";
176
177 case OPT_VERSION:
178 return "Display the version of the application and then exit.";
179
180 case OPT_HELP:
181 return "Display this message and then exit.";
182
183 case OPT_EXECUTE_NUMBER:
184 return "Number of operations(get and set) to execute for the\n"
185 " given test. Default 1000000.";
186
187 case OPT_THREAD_NUMBER:
188 return
189 "Number of threads to startup, better equal to CPU numbers. Default 8.";
190
191 case OPT_CONCURRENCY:
192 return "Number of concurrency to simulate with load. Default 128.";
193
194 case OPT_FIXED_LTH:
195 return "Fixed length of value.";
196
197 case OPT_VERIFY:
198 return "The proportion of date verification, e.g.: --verify=0.01";
199
200 case OPT_GETS_DIVISION:
201 return "Number of keys to multi-get once. Default 1, means single get.";
202
203 case OPT_TIME:
204 return
205 "How long the test to run, suffix: s-seconds, m-minutes, h-hours,\n"
206 " d-days e.g.: --time=2h.";
207
208 case OPT_CONFIG_CMD:
209 return
210 "Load the configure file to get command,key and value distribution list.";
211
212 case OPT_WINDOW_SIZE:
213 return
214 "Task window size of each concurrency, suffix: K, M e.g.: --win_size=10k.\n"
215 " Default 10k.";
216
217 case OPT_UDP:
218 return
219 "UDP support, default memslap uses TCP, TCP port and UDP port of\n"
220 " server must be same.";
221
222 case OPT_EXPIRE:
223 return
224 "The proportion of objects with expire time, e.g.: --exp_verify=0.01.\n"
225 " Default no object with expire time";
226
227 case OPT_OVERWRITE:
228 return
229 "The proportion of objects need overwrite, e.g.: --overwrite=0.01.\n"
230 " Default never overwrite object.";
231
232 case OPT_STAT_FREQ:
233 return
234 "Frequency of dumping statistic information. suffix: s-seconds,\n"
235 " m-minutes, e.g.: --resp_freq=10s.";
236
237 case OPT_SOCK_PER_CONN:
238 return "Number of TCP socks per concurrency. Default 1.";
239
240 case OPT_RECONNECT:
241 return
242 "Reconnect support, when connection is closed it will be reconnected.";
243
244 case OPT_VERBOSE:
245 return
246 "Whether it outputs detailed information when verification fails.";
247
248 case OPT_FACEBOOK_TEST:
249 return
250 "Whether it enables facebook test feature, set with TCP and multi-get with UDP.";
251
252 case OPT_BINARY_PROTOCOL:
253 return
254 "Whether it enables binary protocol. Default with ASCII protocol.";
255
256 case OPT_TPS:
257 return "Expected throughput, suffix: K, e.g.: --tps=10k.";
258
259 case OPT_REP_WRITE_SRV:
260 return "The first nth servers can write data, e.g.: --rep_write=2.";
261
262 default:
263 return "Forgot to document this option :)";
264 } /* switch */
265 } /* ms_lookup_help */
266
267
268 /**
269 * output the help information
270 *
271 * @param command_name, the string of this process
272 * @param description, description of this process
273 * @param long_options, global options array
274 */
275 void ms_help_command(const char *command_name, const char *description)
276 {
277 char *help_message= NULL;
278
279 printf("%s v%u.%u\n", command_name, 1, 0);
280 printf(" %s\n\n", description);
281 printf(
282 "Usage:\n"
283 " memslap -hV | -s servers [-F config_file] [-t time | -x exe_num] [...]\n\n"
284 "Options:\n");
285
286 for (int x= 0; long_options[x].name; x++)
287 {
288 printf(" -%c, --%s%c\n", long_options[x].val, long_options[x].name,
289 long_options[x].has_arg ? '=' : ' ');
290 if ((help_message= (char *)ms_lookup_help(long_options[x].val)) != NULL)
291 {
292 printf(" %s\n", help_message);
293 }
294 }
295
296 printf(
297 "\nExamples:\n"
298 " memslap -s 127.0.0.1:11211 -S 5s\n"
299 " memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b\n"
300 " memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2\n"
301 " memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k\n"
302 " memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40\n"
303 " memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m\n"
304 " memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2\n\n");
305
306 exit(0);
307 } /* ms_help_command */
308
309
310 /* used to parse the time string */
311 static int64_t ms_parse_time()
312 {
313 int64_t ret= 0;
314 char unit= optarg[strlen(optarg) - 1];
315
316 optarg[strlen(optarg) - 1]= '\0';
317 ret= atoi(optarg);
318
319 switch (unit)
320 {
321 case 'd':
322 case 'D':
323 ret*= 24;
324
325 case 'h':
326 case 'H':
327 ret*= 60;
328
329 case 'm':
330 case 'M':
331 ret*= 60;
332
333 case 's':
334 case 'S':
335 break;
336
337 default:
338 ret= -1;
339 break;
340 } /* switch */
341
342 return ret;
343 } /* ms_parse_time */
344
345
346 /* used to parse the size string */
347 static int64_t ms_parse_size()
348 {
349 int64_t ret= -1;
350 char unit= optarg[strlen(optarg) - 1];
351
352 optarg[strlen(optarg) - 1]= '\0';
353 ret= strtoll(optarg, (char **)NULL, 10);
354
355 switch (unit)
356 {
357 case 'k':
358 case 'K':
359 ret*= 1024;
360 break;
361
362 case 'm':
363 case 'M':
364 ret*= 1024 * 1024;
365 break;
366
367 case 'g':
368 case 'G':
369 ret*= 1024 * 1024 * 1024;
370 break;
371
372 default:
373 ret= -1;
374 break;
375 } /* switch */
376
377 return ret;
378 } /* ms_parse_size */
379
380
381 /* used to parse the options of command line */
382 static void ms_options_parse(int argc, char *argv[])
383 {
384 int option_index= 0;
385 int option_rv;
386
387 while ((option_rv= getopt_long(argc, argv, "VhURbaBs:x:T:c:X:v:d:"
388 "t:S:F:w:e:o:n:P:p:",
389 long_options, &option_index)) != -1)
390 {
391 switch (option_rv)
392 {
393 case 0:
394 break;
395
396 case OPT_VERSION: /* --version or -V */
397 ms_version_command(PROGRAM_NAME);
398 break;
399
400 case OPT_HELP: /* --help or -h */
401 ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
402 break;
403
404 case OPT_SERVERS: /* --servers or -s */
405 ms_setting.srv_str= strdup(optarg);
406 break;
407
408 case OPT_CONCURRENCY: /* --concurrency or -c */
409 ms_setting.nconns= atoi(optarg);
410 if (ms_setting.nconns <= 0)
411 {
412 fprintf(stderr, "Concurrency must be greater than 0.:-)\n");
413 exit(1);
414 }
415 break;
416
417 case OPT_EXECUTE_NUMBER: /* --execute_number or -x */
418 ms_setting.exec_num= atoll(optarg);
419 if (ms_setting.exec_num <= 0)
420 {
421 fprintf(stderr, "Execute number must be greater than 0.:-)\n");
422 exit(1);
423 }
424 break;
425
426 case OPT_THREAD_NUMBER: /* --threads or -T */
427 ms_setting.nthreads= atoi(optarg);
428 if (ms_setting.nthreads <= 0)
429 {
430 fprintf(stderr, "Threads number must be greater than 0.:-)\n");
431 exit(1);
432 }
433 break;
434
435 case OPT_FIXED_LTH: /* --fixed_size or -X */
436 ms_setting.fixed_value_size= (size_t)atoi(optarg);
437 if ((ms_setting.fixed_value_size <= 0)
438 || (ms_setting.fixed_value_size > MAX_VALUE_SIZE))
439 {
440 fprintf(stderr, "Value size must be between 0 and 1M.:-)\n");
441 exit(1);
442 }
443 break;
444
445 case OPT_VERIFY: /* --verify or -v */
446 ms_setting.verify_percent= atof(optarg);
447 if ((ms_setting.verify_percent <= 0)
448 || (ms_setting.verify_percent > 1.0))
449 {
450 fprintf(stderr, "Data verification rate must be "
451 "greater than 0 and less than 1.0. :-)\n");
452 exit(1);
453 }
454 break;
455
456 case OPT_GETS_DIVISION: /* --division or -d */
457 ms_setting.mult_key_num= atoi(optarg);
458 if (ms_setting.mult_key_num <= 0)
459 {
460 fprintf(stderr, "Multi-get key number must be greater than 0.:-)\n");
461 exit(1);
462 }
463 break;
464
465 case OPT_TIME: /* --time or -t */
466 ms_setting.run_time= (int)ms_parse_time();
467 if (ms_setting.run_time == -1)
468 {
469 fprintf(stderr, "Please specify the run time. :-)\n"
470 "'s' for second, 'm' for minute, 'h' for hour, "
471 "'d' for day. e.g.: --time=24h (means 24 hours).\n");
472 exit(1);
473 }
474
475 if (ms_setting.run_time == 0)
476 {
477 fprintf(stderr, "Running time can not be 0. :-)\n");
478 exit(1);
479 }
480 break;
481
482 case OPT_CONFIG_CMD: /* --cfg_cmd or -F */
483 ms_setting.cfg_file= strdup(optarg);
484 break;
485
486 case OPT_WINDOW_SIZE: /* --win_size or -w */
487 ms_setting.win_size= (size_t)ms_parse_size();
488 if (ms_setting.win_size == (size_t)-1)
489 {
490 fprintf(
491 stderr,
492 "Please specify the item window size. :-)\n"
493 "e.g.: --win_size=10k (means 10k task window size).\n");
494 exit(1);
495 }
496 break;
497
498 case OPT_UDP: /* --udp or -U*/
499 ms_setting.udp= true;
500 break;
501
502 case OPT_EXPIRE: /* --exp_verify or -e */
503 ms_setting.exp_ver_per= atof(optarg);
504 if ((ms_setting.exp_ver_per <= 0) || (ms_setting.exp_ver_per > 1.0))
505 {
506 fprintf(stderr, "Expire time verification rate must be "
507 "greater than 0 and less than 1.0. :-)\n");
508 exit(1);
509 }
510 break;
511
512 case OPT_OVERWRITE: /* --overwrite or -o */
513 ms_setting.overwrite_percent= atof(optarg);
514 if ((ms_setting.overwrite_percent <= 0)
515 || (ms_setting.overwrite_percent > 1.0))
516 {
517 fprintf(stderr, "Objects overwrite rate must be "
518 "greater than 0 and less than 1.0. :-)\n");
519 exit(1);
520 }
521 break;
522
523 case OPT_STAT_FREQ: /* --stat_freq or -S */
524 ms_setting.stat_freq= (int)ms_parse_time();
525 if (ms_setting.stat_freq == -1)
526 {
527 fprintf(stderr, "Please specify the frequency of dumping "
528 "statistic information. :-)\n"
529 "'s' for second, 'm' for minute, 'h' for hour, "
530 "'d' for day. e.g.: --time=24h (means 24 hours).\n");
531 exit(1);
532 }
533
534 if (ms_setting.stat_freq == 0)
535 {
536 fprintf(stderr, "The frequency of dumping statistic information "
537 "can not be 0. :-)\n");
538 exit(1);
539 }
540 break;
541
542 case OPT_SOCK_PER_CONN: /* --conn_sock or -n */
543 ms_setting.sock_per_conn= atoi(optarg);
544 if (ms_setting.sock_per_conn <= 0)
545 {
546 fprintf(stderr, "Number of socks of each concurrency "
547 "must be greater than 0.:-)\n");
548 exit(1);
549 }
550 break;
551
552 case OPT_RECONNECT: /* --reconnect or -R */
553 ms_setting.reconnect= true;
554 break;
555
556 case OPT_VERBOSE: /* --verbose or -b */
557 ms_setting.verbose= true;
558 break;
559
560 case OPT_FACEBOOK_TEST: /* --facebook or -a */
561 ms_setting.facebook_test= true;
562 break;
563
564 case OPT_BINARY_PROTOCOL: /* --binary or -B */
565 ms_setting.binary_prot= true;
566 break;
567
568 case OPT_TPS: /* --tps or -P */
569 ms_setting.expected_tps= (int)ms_parse_size();
570 if (ms_setting.expected_tps == -1)
571 {
572 fprintf(stderr,
573 "Please specify the item expected throughput. :-)\n"
574 "e.g.: --tps=10k (means 10k throughput).\n");
575 exit(1);
576 }
577 break;
578
579 case OPT_REP_WRITE_SRV: /* --rep_write or -p */
580 ms_setting.rep_write_srv= atoi(optarg);
581 if (ms_setting.rep_write_srv <= 0)
582 {
583 fprintf(stderr,
584 "Number of replication writing server must be greater "
585 "than 0.:-)\n");
586 exit(1);
587 }
588 break;
589
590 case '?':
591 /* getopt_long already printed an error message. */
592 exit(1);
593
594 default:
595 abort();
596 } /* switch */
597 }
598 } /* ms_options_parse */
599
600
601 static int ms_check_para()
602 {
603 if (ms_setting.srv_str == NULL)
604 {
605 fprintf(stderr, "No Servers provided.\n\n");
606 return -1;
607 }
608
609 if (ms_setting.nconns % ms_setting.nthreads != 0)
610 {
611 fprintf(stderr, "Concurrency must be the multiples of threads count.\n");
612 return -1;
613 }
614
615 if (ms_setting.win_size % UNIT_ITEMS_COUNT != 0)
616 {
617 fprintf(stderr, "Window size must be the multiples of 1024.\n\n");
618 return -1;
619 }
620
621 return 0;
622 } /* ms_check_para */
623
624
625 /* initialize the statistic structure */
626 static void ms_statistic_init()
627 {
628 pthread_mutex_init(&ms_statistic.stat_mutex, NULL);
629 ms_init_stats(&ms_statistic.get_stat, "Get");
630 ms_init_stats(&ms_statistic.set_stat, "Set");
631 ms_init_stats(&ms_statistic.total_stat, "Total");
632 } /* ms_statistic_init */
633
634
635 /* initialize the global state structure */
636 static void ms_stats_init()
637 {
638 memset(&ms_stats, 0, sizeof(ms_stats_t));
639 if (ms_setting.stat_freq > 0)
640 {
641 ms_statistic_init();
642 }
643 } /* ms_stats_init */
644
645
646 /* use to output the statistic */
647 static void ms_print_statistics(int in_time)
648 {
649 int obj_size= (int)(ms_setting.avg_key_size + ms_setting.avg_val_size);
650
651 printf("\033[1;1H\033[2J\n");
652 ms_dump_format_stats(&ms_statistic.get_stat, in_time,
653 ms_setting.stat_freq, obj_size);
654 ms_dump_format_stats(&ms_statistic.set_stat, in_time,
655 ms_setting.stat_freq, obj_size);
656 ms_dump_format_stats(&ms_statistic.total_stat, in_time,
657 ms_setting.stat_freq, obj_size);
658 } /* ms_print_statistics */
659
660
661 /* used to print the states of memslap */
662 static void ms_print_memslap_stats(struct timeval *start_time,
663 struct timeval *end_time)
664 {
665 char buf[1024];
666 char *pos= buf;
667
668 pos+= sprintf(pos,
669 "cmd_get: %llu\n",
670 (unsigned long long)ms_stats.cmd_get);
671 pos+= sprintf(pos,
672 "cmd_set: %llu\n",
673 (unsigned long long)ms_stats.cmd_set);
674 pos+= sprintf(pos,
675 "get_misses: %llu\n",
676 (unsigned long long)ms_stats.get_misses);
677
678 if (ms_setting.verify_percent > 0)
679 {
680 pos+= sprintf(pos, "verify_misses: %llu\n",
681 (unsigned long long)ms_stats.vef_miss);
682 pos+= sprintf(pos, "verify_failed: %llu\n",
683 (unsigned long long)ms_stats.vef_failed);
684 }
685
686 if (ms_setting.exp_ver_per > 0)
687 {
688 pos+= sprintf(pos, "expired_get: %llu\n",
689 (unsigned long long)ms_stats.exp_get);
690 pos+= sprintf(pos, "unexpired_unget: %llu\n",
691 (unsigned long long)ms_stats.unexp_unget);
692 }
693
694 pos+= sprintf(pos,
695 "written_bytes: %llu\n",
696 (unsigned long long)ms_stats.bytes_written);
697 pos+= sprintf(pos,
698 "read_bytes: %llu\n",
699 (unsigned long long)ms_stats.bytes_read);
700 pos+= sprintf(pos,
701 "object_bytes: %llu\n",
702 (unsigned long long)ms_stats.obj_bytes);
703
704 if (ms_setting.udp || ms_setting.facebook_test)
705 {
706 pos+= sprintf(pos,
707 "packet_disorder: %llu\n",
708 (unsigned long long)ms_stats.pkt_disorder);
709 pos+= sprintf(pos,
710 "packet_drop: %llu\n",
711 (unsigned long long)ms_stats.pkt_drop);
712 pos+= sprintf(pos,
713 "udp_timeout: %llu\n",
714 (unsigned long long)ms_stats.udp_timeout);
715 }
716
717 if (ms_setting.stat_freq > 0)
718 {
719 ms_dump_stats(&ms_statistic.get_stat);
720 ms_dump_stats(&ms_statistic.set_stat);
721 ms_dump_stats(&ms_statistic.total_stat);
722 }
723
724 int64_t time_diff= ms_time_diff(start_time, end_time);
725 pos+= sprintf(
726 pos,
727 "\nRun time: %.1fs Ops: %llu TPS: %.0Lf Net_rate: %.1fM/s\n",
728 (double)time_diff / 1000000,
729 (unsigned long long)(ms_stats.cmd_get + ms_stats.cmd_set),
730 (ms_stats.cmd_get
731 + ms_stats.cmd_set) / ((long double)time_diff / 1000000),
732 (double)(
733 ms_stats.bytes_written
734 + ms_stats.bytes_read) / 1024 / 1024
735 / ((double)time_diff / 1000000));
736
737 fprintf(stdout, "%s", buf);
738 fflush(stdout);
739 } /* ms_print_memslap_stats */
740
741
742 /* the loop of the main thread, wait the work threads to complete */
743 static void ms_monitor_slap_mode()
744 {
745 int second= 0;
746 struct timeval start_time, end_time;
747
748 /* only when there is no set operation it need warm up */
749 if (ms_setting.cmd_distr[CMD_SET].cmd_prop < PROP_ERROR)
750 {
751 /* Wait all the connects complete warm up. */
752 pthread_mutex_lock(&ms_global.init_lock.lock);
753 while (ms_global.init_lock.count < ms_setting.nconns)
754 {
755 pthread_cond_wait(&ms_global.init_lock.cond,
756 &ms_global.init_lock.lock);
757 }
758 pthread_mutex_unlock(&ms_global.init_lock.lock);
759 }
760
761 ms_global.finish_warmup= true;
762
763 /* running in "run time" mode, user specify run time */
764 if (ms_setting.run_time > 0)
765 {
766 gettimeofday(&start_time, NULL);
767 while (1)
768 {
769 sleep(1);
770 second++;
771
772 if ((ms_setting.stat_freq > 0) && (second % ms_setting.stat_freq == 0)
773 && (ms_stats.active_conns >= ms_setting.nconns))
774 {
775 ms_print_statistics(second);
776 }
777
778 if (ms_setting.run_time <= second)
779 {
780 ms_global.time_out= true;
781 break;
782 }
783
784 /* all connections disconnect */
785 if ((second > 5) && (ms_stats.active_conns == 0))
786 {
787 break;
788 }
789 }
790 gettimeofday(&end_time, NULL);
791 sleep(1); /* wait all threads clean up */
792 }
793 else
794 {
795 /* running in "execute number" mode, user specify execute number */
796 gettimeofday(&start_time, NULL);
797
798 /*
799 * We loop until we know that all connects have cleaned up.
800 */
801 pthread_mutex_lock(&ms_global.run_lock.lock);
802 while (ms_global.run_lock.count < ms_setting.nconns)
803 {
804 pthread_cond_wait(&ms_global.run_lock.cond, &ms_global.run_lock.lock);
805 }
806 pthread_mutex_unlock(&ms_global.run_lock.lock);
807
808 gettimeofday(&end_time, NULL);
809 }
810
811 ms_print_memslap_stats(&start_time, &end_time);
812 } /* ms_monitor_slap_mode */
813
814
815 /* the main function */
816 int main(int argc, char *argv[])
817 {
818 srandom((unsigned int)time(NULL));
819 ms_global_struct_init();
820
821 /* initialization */
822 ms_setting_init_pre();
823 ms_options_parse(argc, argv);
824 if (ms_check_para())
825 {
826 ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
827 exit(1);
828 }
829 ms_setting_init_post();
830 ms_stats_init();
831 ms_thread_init();
832
833 /* waiting work thread complete its task */
834 ms_monitor_slap_mode();
835
836 /* clean up */
837 ms_thread_cleanup();
838 ms_global_struct_destroy();
839 ms_setting_cleanup();
840
841 return 0;
842 } /* main */