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