3de38f309d48e213d01e6a8c60a434d7a52e6cd9
[awesomized/libmemcached] / src / memslap.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <sys/mman.h>
7 #include <fcntl.h>
8 #include <sys/time.h>
9 #include <getopt.h>
10 #include <pthread.h>
11
12 #include <memcached.h>
13
14 #include "client_options.h"
15 #include "utilities.h"
16 #include "generator.h"
17 #include "execute.h"
18
19 #define DEFAULT_INITIAL_LOAD 10000
20 #define DEFAULT_EXECUTE_NUMBER 10000
21 #define DEFAULT_CONCURRENCY 1
22
23 #define PROGRAM_NAME "memslap"
24 #define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
25
26 /* Global Thread counter */
27 unsigned int thread_counter;
28 pthread_mutex_t counter_mutex;
29 pthread_cond_t count_threshhold;
30 unsigned int master_wakeup;
31 pthread_mutex_t sleeper_mutex;
32 pthread_cond_t sleep_threshhold;
33
34 void *run_task(void *p);
35
36 /* Types */
37 typedef struct conclusions_st conclusions_st;
38 typedef struct thread_context_st thread_context_st;
39 typedef enum {
40 SET_TEST,
41 GET_TEST,
42 } test_type;
43
44 struct thread_context_st {
45 unsigned int key_count;
46 pairs_st *initial_pairs;
47 unsigned int initial_number;
48 pairs_st *execute_pairs;
49 unsigned int execute_number;
50 test_type test;
51 memcached_server_st *servers;
52 };
53
54 struct conclusions_st {
55 long int load_time;
56 long int read_time;
57 unsigned int rows_loaded;
58 unsigned int rows_read;
59 };
60
61 /* Prototypes */
62 void options_parse(int argc, char *argv[]);
63 void conclusions_print(conclusions_st *conclusion);
64 void scheduler(memcached_server_st *servers, conclusions_st *conclusion);
65 pairs_st *load_create_data(memcached_server_st *servers, unsigned int number_of,
66 unsigned int *actual_loaded);
67 void flush_all(memcached_server_st *servers);
68
69 static int opt_verbose= 0;
70 static int opt_flush= 0;
71 static int opt_non_blocking_io= 0;
72 static int opt_tcp_nodelay= 0;
73 static unsigned int opt_execute_number= 0;
74 static unsigned int opt_createial_load= 0;
75 static unsigned int opt_concurrency= 0;
76 static int opt_displayflag= 0;
77 static char *opt_servers= NULL;
78 test_type opt_test= SET_TEST;
79
80 int main(int argc, char *argv[])
81 {
82 conclusions_st conclusion;
83 memcached_server_st *servers;
84
85 memset(&conclusion, 0, sizeof(conclusions_st));
86
87 srandom(time(NULL));
88 options_parse(argc, argv);
89
90 if (!opt_servers)
91 {
92 char *temp;
93
94 if ((temp= getenv("MEMCACHED_SERVERS")))
95 opt_servers= strdup(temp);
96 else
97 exit(1);
98 }
99
100 servers= memcached_servers_parse(opt_servers);
101
102 pthread_mutex_init(&counter_mutex, NULL);
103 pthread_cond_init(&count_threshhold, NULL);
104 pthread_mutex_init(&sleeper_mutex, NULL);
105 pthread_cond_init(&sleep_threshhold, NULL);
106
107 scheduler(servers, &conclusion);
108
109 free(opt_servers);
110
111 (void)pthread_mutex_destroy(&counter_mutex);
112 (void)pthread_cond_destroy(&count_threshhold);
113 (void)pthread_mutex_destroy(&sleeper_mutex);
114 (void)pthread_cond_destroy(&sleep_threshhold);
115 conclusions_print(&conclusion);
116 memcached_server_list_free(servers);
117
118 return 0;
119 }
120
121 void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
122 {
123 unsigned int x;
124 unsigned int actual_loaded;
125
126 struct timeval start_time, end_time;
127 pthread_t mainthread; /* Thread descriptor */
128 pthread_attr_t attr; /* Thread attributes */
129 pairs_st *pairs= NULL;
130
131 pthread_attr_init(&attr);
132 pthread_attr_setdetachstate(&attr,
133 PTHREAD_CREATE_DETACHED);
134
135 if (opt_flush)
136 flush_all(servers);
137 if (opt_createial_load)
138 pairs= load_create_data(servers, opt_createial_load, &actual_loaded);
139
140 pthread_mutex_lock(&counter_mutex);
141 thread_counter= 0;
142
143 pthread_mutex_lock(&sleeper_mutex);
144 master_wakeup= 1;
145 pthread_mutex_unlock(&sleeper_mutex);
146
147 for (x= 0; x < opt_concurrency; x++)
148 {
149 thread_context_st *context;
150 context= (thread_context_st *)malloc(sizeof(thread_context_st));
151
152 context->servers= servers;
153 context->test= opt_test;
154
155 context->initial_pairs= pairs;
156 context->initial_number= actual_loaded;
157
158 if (opt_test == SET_TEST)
159 {
160 context->execute_pairs= pairs_generate(opt_execute_number);
161 context->execute_number= opt_execute_number;
162 }
163
164 /* now you create the thread */
165 if (pthread_create(&mainthread, &attr, run_task,
166 (void *)context) != 0)
167 {
168 fprintf(stderr,"Could not create thread\n");
169 exit(1);
170 }
171 thread_counter++;
172 }
173
174 pthread_mutex_unlock(&counter_mutex);
175 pthread_attr_destroy(&attr);
176
177 pthread_mutex_lock(&sleeper_mutex);
178 master_wakeup= 0;
179 pthread_mutex_unlock(&sleeper_mutex);
180 pthread_cond_broadcast(&sleep_threshhold);
181
182 gettimeofday(&start_time, NULL);
183 /*
184 We loop until we know that all children have cleaned up.
185 */
186 pthread_mutex_lock(&counter_mutex);
187 while (thread_counter)
188 {
189 struct timespec abstime;
190
191 memset(&abstime, 0, sizeof(struct timespec));
192 abstime.tv_sec= 1;
193
194 pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
195 }
196 pthread_mutex_unlock(&counter_mutex);
197
198 gettimeofday(&end_time, NULL);
199
200 conclusion->load_time= timedif(end_time, start_time);
201 conclusion->read_time= timedif(end_time, start_time);
202 pairs_free(pairs);
203 }
204
205 void options_parse(int argc, char *argv[])
206 {
207 memcached_programs_help_st help_options[]=
208 {
209 {0},
210 };
211
212 static struct option long_options[]=
213 {
214 {"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY},
215 {"debug", no_argument, &opt_verbose, OPT_DEBUG},
216 {"execute-number", required_argument, NULL, OPT_SLAP_EXECUTE_NUMBER},
217 {"flag", no_argument, &opt_displayflag, OPT_FLAG},
218 {"flush", no_argument, &opt_flush, OPT_FLUSH},
219 {"help", no_argument, NULL, OPT_HELP},
220 {"initial-load", required_argument, NULL, OPT_SLAP_INITIAL_LOAD}, /* Number to load initially */
221 {"non-blocking", no_argument, &opt_non_blocking_io, OPT_SLAP_NON_BLOCK},
222 {"servers", required_argument, NULL, OPT_SERVERS},
223 {"tcp-nodelay", no_argument, &opt_tcp_nodelay, OPT_SLAP_TCP_NODELAY},
224 {"test", required_argument, NULL, OPT_SLAP_TEST},
225 {"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
226 {"version", no_argument, NULL, OPT_VERSION},
227 {0, 0, 0, 0},
228 };
229
230 int option_index= 0;
231 int option_rv;
232
233 while (1)
234 {
235 option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
236 if (option_rv == -1) break;
237 switch (option_rv)
238 {
239 case 0:
240 break;
241 case OPT_VERBOSE: /* --verbose or -v */
242 opt_verbose = OPT_VERBOSE;
243 break;
244 case OPT_DEBUG: /* --debug or -d */
245 opt_verbose = OPT_DEBUG;
246 break;
247 case OPT_VERSION: /* --version or -V */
248 version_command(PROGRAM_NAME);
249 break;
250 case OPT_HELP: /* --help or -h */
251 help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
252 break;
253 case OPT_SERVERS: /* --servers or -s */
254 opt_servers= strdup(optarg);
255 break;
256 case OPT_SLAP_TEST:
257 if (!strcmp(optarg, "get"))
258 opt_test= GET_TEST ;
259 else if (!strcmp(optarg, "set"))
260 opt_test= SET_TEST;
261 else
262 {
263 fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
264 exit(1);
265 }
266 break;
267 case OPT_SLAP_CONCURRENCY:
268 opt_concurrency= strtol(optarg, (char **)NULL, 10);
269 case OPT_SLAP_EXECUTE_NUMBER:
270 opt_execute_number= strtol(optarg, (char **)NULL, 10);
271 break;
272 case OPT_SLAP_INITIAL_LOAD:
273 opt_createial_load= strtol(optarg, (char **)NULL, 10);
274 break;
275 case '?':
276 /* getopt_long already printed an error message. */
277 exit(1);
278 default:
279 abort();
280 }
281 }
282
283 if (opt_test == GET_TEST && opt_createial_load == 0)
284 opt_createial_load= DEFAULT_INITIAL_LOAD;
285
286 if (opt_execute_number == 0)
287 opt_execute_number= DEFAULT_EXECUTE_NUMBER;
288
289 if (opt_concurrency == 0)
290 opt_concurrency= DEFAULT_CONCURRENCY;
291 }
292
293 void conclusions_print(conclusions_st *conclusion)
294 {
295 printf("\tThreads connecting to servers %u\n", opt_concurrency);
296 #ifdef NOT_FINISHED
297 printf("\tLoaded %u rows\n", conclusion->rows_loaded);
298 printf("\tRead %u rows\n", conclusion->rows_read);
299 #endif
300 if (opt_test == SET_TEST)
301 printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000,
302 conclusion->load_time % 1000);
303 else
304 printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000,
305 conclusion->read_time % 1000);
306 }
307
308 void *run_task(void *p)
309 {
310 thread_context_st *context= (thread_context_st *)p;
311 memcached_st *memc;
312 unsigned int value= 1;
313
314 memc= memcached_create(NULL);
315 if (opt_non_blocking_io)
316 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, &value);
317 if (opt_tcp_nodelay)
318 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, &value);
319
320 memcached_server_push(memc, context->servers);
321
322 pthread_mutex_lock(&sleeper_mutex);
323 while (master_wakeup)
324 {
325 pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
326 }
327 pthread_mutex_unlock(&sleeper_mutex);
328
329 /* Do Stuff */
330 switch (context->test)
331 {
332 case SET_TEST:
333 execute_set(memc, context->execute_pairs, context->execute_number);
334 break;
335 case GET_TEST:
336 execute_get(memc, context->initial_pairs, context->initial_number);
337 break;
338 }
339
340 pthread_mutex_lock(&counter_mutex);
341 thread_counter--;
342 pthread_cond_signal(&count_threshhold);
343 pthread_mutex_unlock(&counter_mutex);
344 memcached_free(memc);
345
346 if (context->execute_pairs)
347 pairs_free(context->execute_pairs);
348 free(context);
349
350 return NULL;
351 }
352
353 void flush_all(memcached_server_st *servers)
354 {
355 memcached_st *memc;
356
357 memc= memcached_create(NULL);
358
359 memcached_server_push(memc, servers);
360
361 memcached_flush(memc, 0);
362
363 memcached_free(memc);
364 }
365
366 pairs_st *load_create_data(memcached_server_st *servers, unsigned int number_of,
367 unsigned int *actual_loaded)
368 {
369 memcached_st *memc;
370 pairs_st *pairs;
371
372 memc= memcached_create(NULL);
373 /* We always used non-blocking IO for load since it is faster */
374 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, NULL );
375 memcached_server_push(memc, servers);
376
377 pairs= pairs_generate(number_of);
378 *actual_loaded= execute_set(memc, pairs, number_of);
379
380 memcached_free(memc);
381
382 return pairs;
383 }