• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *   Copyright (c) International Business Machines Corp., 2001-2004
3  *
4  *   This program is free software;  you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12  *   the GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program;  if not, write to the Free Software
16  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include <stdio.h>
19 #include <string.h>
20 #include <assert.h>
21 #include <inttypes.h>
22 #include <ctype.h>
23 
24 #include "ffsb.h"
25 #include "parser.h"
26 #include "ffsb_tg.h"
27 #include "ffsb_stats.h"
28 #include "util.h"
29 #include "list.h"
30 
31 #define BUFSIZE 1024
32 
33 config_options_t global_options[] = GLOBAL_OPTIONS;
34 config_options_t tg_options[] = THREADGROUP_OPTIONS;
35 config_options_t fs_options[] = FILESYSTEM_OPTIONS;
36 config_options_t stats_options[] = STATS_OPTIONS;
37 container_desc_t container_desc[] = CONTAINER_DESC;
38 
39 /* strips out whitespace and comments, returns NULL on eof */
parseerror(char * msg)40 void parseerror(char *msg)
41 {
42 	fprintf(stderr, "Error parsing %s\n", msg);
43 	exit(1);
44 }
45 
get_next_line(FILE * f)46 static char *get_next_line(FILE * f)
47 {
48 	static char buf[BUFSIZE];
49 	char *ret, *tmp;
50 	int flag = 1;
51 	while (flag) {
52 		ret = fgets(buf, BUFSIZE, f);
53 		if (ret == NULL)
54 			return NULL;
55 		ret = buf;
56 		while (isspace(*ret))
57 			ret++;
58 
59 		if ((*ret == COMMENT_CHAR) || (*ret == '\0'))
60 			continue;
61 
62 		tmp = ret;
63 		while (*tmp != '\0') {
64 			if (*tmp == COMMENT_CHAR) {
65 				*tmp = '\0';
66 				break;
67 			}
68 			tmp++;
69 		}
70 		flag = 0;
71 	}
72 	return ret;
73 }
74 
strip_space(char * buf)75 static char *strip_space(char *buf)
76 {
77 	int len;
78 	char *tmp, *tmp2;
79 	int flag = 1;
80 
81 	len = strnlen(buf, BUFSIZE);
82 	tmp = malloc(sizeof(char) * len);
83 	memset(tmp, 0, sizeof(char) * len);
84 	tmp2 = tmp;
85 	while (flag) {
86 		if (!isspace(*buf)) {
87 			*tmp = *buf;
88 			tmp++;
89 		}
90 		buf++;
91 		if (*buf != '\0')
92 			continue;
93 		flag = 0;
94 	}
95 	return tmp2;
96 }
97 
size64_convert(char * buf)98 static uint64_t size64_convert(char *buf)
99 {
100 	size_t buf_size = strlen(buf);
101 	char unit[3] = { 0 };
102 	char search_str[256];
103 	uint64_t size;
104 	uint64_t multiplier = 1;
105 	int i;
106 
107 	if (buf_size == 1)
108 		goto out;
109 
110 	strcpy(unit, buf + (buf_size - 2));
111 	for (i = 0; i < 2; i++) {
112 		if (isdigit(unit[i]))
113 			goto try_single;
114 		unit[i] = toupper(unit[i]);
115 	}
116 	goto do_multiplier;
117 
118 try_single:
119 	memcpy(unit, "\0", 3);
120 	strcpy(unit, buf + (buf_size - 1));
121 	if (isdigit(unit[0])) {
122 		unit[0] = 0;
123 		goto out;
124 	}
125 	unit[0] = toupper(unit[0]);
126 
127 do_multiplier:
128 	if (!strcmp("KB", unit) || !strcmp("K", unit))
129 		multiplier = 1024;
130 	if (!strcmp("MB", unit) || !strcmp("M", unit))
131 		multiplier = 1048576;
132 	if (!strcmp("GB", unit) || !strcmp("G", unit))
133 		multiplier = 1073741824;
134 	if (multiplier == 1) {
135 		unit[0] = 0;
136 		multiplier = 0;
137 	}
138 out:
139 	sprintf(search_str, "%%llu%s", unit);
140 	if (1 == sscanf(buf, search_str, &size))
141 		return size * multiplier;
142 	return 0;
143 }
144 
get_opt64(char * buf,char string[])145 static uint64_t *get_opt64(char *buf, char string[])
146 {
147 	char search_str[256];
148 	char *line = strip_space(buf);
149 	uint64_t temp;
150 	uint64_t *ret;
151 
152 	sprintf(search_str, "%s=%%llu\\n", string);
153 	if (1 == sscanf(line, search_str, &temp)) {
154 		ret = malloc(sizeof(uint64_t));
155 		*ret = temp;
156 		return ret;
157 	}
158 	free(line);
159 	return NULL;
160 }
161 
get_opt32(char * buf,char string[])162 static uint32_t *get_opt32(char *buf, char string[])
163 {
164 	uint32_t *ret;
165 	uint64_t *res;
166 	res = get_opt64(buf, string);
167 	if (res) {
168 		ret = malloc(sizeof(uint32_t));
169 		*ret = *res;
170 		free(res);
171 		return ret;
172 	}
173 	return NULL;
174 }
175 
get_optbool(char * buf,char string[])176 static uint8_t *get_optbool(char *buf, char string[])
177 {
178 	uint8_t *ret;
179 	uint64_t *res;
180 	res = get_opt64(buf, string);
181 	if (res) {
182 		if ((int)*res < 0 || (int)*res > 1) {
183 			printf("Error in: %s", buf);
184 			printf("%llu not boolean\n", (long long unsigned)*res);
185 			exit(1);
186 		}
187 		ret = malloc(sizeof(uint8_t));
188 		*ret = *res;
189 		free(res);
190 		return ret;
191 	}
192 	return NULL;
193 }
194 
get_optstr(char * buf,char string[])195 static char *get_optstr(char *buf, char string[])
196 {
197 	char search_str[256];
198 	char *line = strip_space(buf);
199 	char *ret_buf;
200 	char temp[BUFSIZE];
201 	int len;
202 
203 	len = strnlen(string, BUFSIZE);
204 	sprintf(search_str, "%s=%%%ds\\n", string, BUFSIZE - len - 1);
205 	if (1 == sscanf(line, search_str, &temp)) {
206 		len = strnlen(temp, 4096);
207 		ret_buf = malloc(len);
208 		strncpy(ret_buf, temp, len);
209 		return ret_buf;
210 	}
211 	free(line);
212 	return NULL;
213 }
214 
get_optdouble(char * buf,char string[])215 static double *get_optdouble(char *buf, char string[])
216 {
217 	char search_str[256];
218 	char *line = strip_space(buf);
219 	double temp;
220 	double *ret;
221 
222 	sprintf(search_str, "%s=%%lf\\n", string);
223 	if (1 == sscanf(line, search_str, &temp)) {
224 		ret = malloc(sizeof(double));
225 		*ret = temp;
226 		return ret;
227 	}
228 	free(line);
229 	return NULL;
230 }
231 
get_optrange(char * buf,char string[])232 static range_t *get_optrange(char *buf, char string[])
233 {
234 	char search_str[256];
235 	double a, b;
236 	range_t *ret;
237 
238 	sprintf(search_str, "%s %%lf %%lf\\n", string);
239 	if (2 == sscanf(buf, search_str, &a, &b)) {
240 		ret = malloc(sizeof(struct range));
241 		ret->a = a;
242 		ret->b = b;
243 		return ret;
244 	}
245 	return NULL;
246 }
247 
get_optsizeweight(char * buf,char string[])248 static size_weight_t *get_optsizeweight(char *buf, char string[])
249 {
250 	char search_str[256];
251 	char size[256];
252 	int weight;
253 	size_weight_t *ret;
254 
255 	sprintf(search_str, "%s %%s %%d\\n", string);
256 	if (2 == sscanf(buf, search_str, &size, &weight)) {
257 		ret = malloc(sizeof(struct size_weight));
258 		ret->size = size64_convert(size);
259 		ret->weight = weight;
260 		return ret;
261 	}
262 	return NULL;
263 }
264 
get_optsize64(char * buf,char string[])265 static uint64_t *get_optsize64(char *buf, char string[])
266 {
267 	char search_str[256];
268 	char *line = strip_space(buf);
269 	char temp[256];
270 	uint64_t size;
271 	uint64_t *ret = NULL;
272 
273 	sprintf(search_str, "%s=%%s\\n", string);
274 	if (1 == sscanf(line, search_str, &temp)) {
275 		ret = malloc(sizeof(uint64_t));
276 		*ret = size64_convert(temp);
277 	}
278 	free(line);
279 	return ret;
280 }
281 
get_optsize32(char * buf,char string[])282 static uint32_t *get_optsize32(char *buf, char string[])
283 {
284 	uint32_t *ret;
285 	uint64_t *res;
286 	res = get_optsize64(buf, string);
287 	if (res) {
288 		ret = malloc(sizeof(uint32_t));
289 		*ret = *res;
290 		free(res);
291 		return ret;
292 	}
293 	return NULL;
294 }
295 
get_deprecated(char * buf,char string[])296 static uint64_t *get_deprecated(char *buf, char string[])
297 {
298 	char search_str[256];
299 	char temp[BUFSIZE];
300 	int len;
301 
302 	len = strnlen(string, BUFSIZE);
303 	sprintf(search_str, "%s%%%ds\\n", string, BUFSIZE - len - 1);
304 	if (1 == sscanf(buf, search_str, &temp))
305 		printf("WARNING: The \"%s\" option is deprecated!!!\n", string);
306 
307 	return NULL;
308 }
309 
init_container(void)310 static container_t *init_container(void)
311 {
312 	container_t *container;
313 	container = malloc(sizeof(container_t));
314 	container->config = NULL;
315 	container->type = 0;
316 	container->next = NULL;
317 	return container;
318 }
319 
set_option(char * buf,config_options_t * options)320 static int set_option(char *buf, config_options_t * options)
321 {
322 	void *value;
323 
324 	while (options->name) {
325 		switch (options->type) {
326 		case TYPE_WEIGHT:
327 		case TYPE_U32:
328 			value = get_opt32(buf, options->name);
329 			if (value)
330 				goto out;
331 			break;
332 		case TYPE_U64:
333 			value = get_opt64(buf, options->name);
334 			if (value)
335 				goto out;
336 			break;
337 		case TYPE_STRING:
338 			value = get_optstr(buf, options->name);
339 			if (value)
340 				goto out;
341 			break;
342 		case TYPE_BOOLEAN:
343 			value = get_optbool(buf, options->name);
344 			if (value)
345 				goto out;
346 			break;
347 		case TYPE_DOUBLE:
348 			value = get_optdouble(buf, options->name);
349 			if (value)
350 				goto out;
351 			break;
352 		case TYPE_RANGE:
353 			value = get_optrange(buf, options->name);
354 			if (value)
355 				goto out;
356 			break;
357 		case TYPE_SIZEWEIGHT:
358 			value = get_optsizeweight(buf, options->name);
359 			if (value)
360 				goto out;
361 			break;
362 		case TYPE_DEPRECATED:
363 			value = get_deprecated(buf, options->name);
364 			if (value)
365 				goto out;
366 			break;
367 		case TYPE_SIZE32:
368 			value = get_optsize32(buf, options->name);
369 			if (value)
370 				goto out;
371 			break;
372 		case TYPE_SIZE64:
373 			value = get_optsize64(buf, options->name);
374 			if (value)
375 				goto out;
376 			break;
377 		default:
378 			printf("Unknown type\n");
379 			break;
380 		}
381 		options++;
382 	}
383 	return 0;
384 
385 out:
386 	if (options->storage_type == STORE_SINGLE)
387 		options->value = value;
388 	if (options->storage_type == STORE_LIST) {
389 		if (!options->value) {
390 			value_list_t *lhead;
391 			lhead = malloc(sizeof(struct value_list));
392 			INIT_LIST_HEAD(&lhead->list);
393 			options->value = lhead;
394 		}
395 		value_list_t *tmp_list, *tmp_list2;
396 		tmp_list = malloc(sizeof(struct value_list));
397 		INIT_LIST_HEAD(&tmp_list->list);
398 		tmp_list->value = value;
399 		tmp_list2 = (struct value_list *)options->value;
400 		list_add(&(tmp_list->list), &(tmp_list2->list));
401 	}
402 
403 	return 1;
404 }
405 
insert_container(container_t * container,container_t * new_container)406 void insert_container(container_t * container, container_t * new_container)
407 {
408 	while (container->next)
409 		container = container->next;
410 	container->next = new_container;
411 }
412 
413 container_t *search_group(char *, FILE *);
414 
handle_container(char * buf,FILE * f,uint32_t type,config_options_t * options)415 container_t *handle_container(char *buf, FILE * f, uint32_t type,
416 			      config_options_t * options)
417 {
418 	container_desc_t *desc = container_desc;
419 	container_t *ret_container;
420 	container_t *tmp_container, *tmp2_container;
421 	container_t *child = NULL;
422 	int is_option;
423 
424 	while (desc->name)
425 		if (desc->type == type)
426 			break;
427 		else
428 			desc++;
429 
430 	if (!desc->name)
431 		return NULL;
432 
433 	buf = get_next_line(f);
434 	while (buf) {
435 		is_option = set_option(buf, options);
436 		tmp_container = search_group(buf, f);
437 		if (tmp_container) {
438 			if (tmp_container->type == END) {
439 				free(tmp_container);
440 				break;
441 			} else {
442 				if (child == NULL)
443 					child = tmp_container;
444 				else {
445 					tmp2_container = child;
446 					while (tmp2_container->next)
447 						tmp2_container =
448 						    tmp2_container->next;
449 					tmp2_container->next = tmp_container;
450 				}
451 
452 			}
453 		}
454 		if (!is_option && !tmp_container) {
455 			printf("ERROR!!! Unknow option: %s", buf);
456 			exit(1);
457 		}
458 		buf = get_next_line(f);
459 	}
460 	ret_container = init_container();
461 	ret_container->config = options;
462 	ret_container->type = type;
463 	if (child)
464 		ret_container->child = child;
465 
466 	return ret_container;
467 }
468 
search_group(char * buf,FILE * f)469 container_t *search_group(char *buf, FILE * f)
470 {
471 	char temp[BUFSIZE];
472 	char *ptr;
473 	config_options_t *options;
474 	container_desc_t *desc = container_desc;
475 	container_t *ret_container;
476 
477 	if (1 == sscanf(buf, "[%s]\n", (char *)&temp))
478 		while (desc->name) {
479 			ptr = strstr(buf, desc->name);
480 			if (ptr)
481 				switch (desc->type) {
482 				case FILESYSTEM:
483 					options = malloc(sizeof(fs_options));
484 					memcpy(options, fs_options,
485 					       sizeof(fs_options));
486 					return handle_container(buf, f,
487 								desc->type,
488 								options);
489 					break;
490 				case THREAD_GROUP:
491 					options = malloc(sizeof(tg_options));
492 					memcpy(options, tg_options,
493 					       sizeof(tg_options));
494 					return handle_container(buf, f,
495 								desc->type,
496 								options);
497 					break;
498 				case STATS:
499 					options = malloc(sizeof(stats_options));
500 					memcpy(options, stats_options,
501 					       sizeof(stats_options));
502 					return handle_container(buf, f,
503 								desc->type,
504 								options);
505 					break;
506 				case END:
507 					ret_container = init_container();
508 					ret_container->type = END;
509 					return ret_container;
510 					break;
511 				}
512 			desc++;
513 		}
514 	return NULL;
515 }
516 
get_value(config_options_t * config,char * name)517 void *get_value(config_options_t * config, char *name)
518 {
519 	while (config->name) {
520 		if (!strcmp(config->name, name)) {
521 			if (config->value)
522 				return config->value;
523 			else
524 				return NULL;
525 		}
526 		config++;
527 	}
528 	return 0;
529 }
530 
get_config_str(config_options_t * config,char * name)531 char *get_config_str(config_options_t * config, char *name)
532 {
533 	return get_value(config, name);
534 }
535 
get_config_u32(config_options_t * config,char * name)536 uint32_t get_config_u32(config_options_t * config, char *name)
537 {
538 	void *value = get_value(config, name);
539 	if (value)
540 		return *(uint32_t *) value;
541 	return 0;
542 }
543 
get_config_bool(config_options_t * config,char * name)544 uint8_t get_config_bool(config_options_t * config, char *name)
545 {
546 	void *value = get_value(config, name);
547 	if (value)
548 		return *(uint8_t *) value;
549 	return 0;
550 }
551 
get_config_u64(config_options_t * config,char * name)552 uint64_t get_config_u64(config_options_t * config, char *name)
553 {
554 	void *value = get_value(config, name);
555 	if (value)
556 		return *(uint64_t *) value;
557 	return 0;
558 }
559 
get_config_double(config_options_t * config,char * name)560 double get_config_double(config_options_t * config, char *name)
561 {
562 	void *value = get_value(config, name);
563 	if (value)
564 		return *(double *)value;
565 	return 0;
566 }
567 
parse(FILE * f)568 static profile_config_t *parse(FILE * f)
569 {
570 	char *buf;
571 	profile_config_t *profile_conf;
572 	container_t *tmp_container;
573 
574 	profile_conf = malloc(sizeof(profile_config_t));
575 	profile_conf->global = malloc(sizeof(global_options));
576 	memcpy(profile_conf->global, global_options, sizeof(global_options));
577 	profile_conf->fs_container = NULL;
578 	profile_conf->tg_container = NULL;
579 	int is_option;
580 	buf = get_next_line(f);
581 
582 	while (buf) {
583 		is_option = set_option(buf, profile_conf->global);
584 		tmp_container = search_group(buf, f);
585 		if (tmp_container)
586 			switch (tmp_container->type) {
587 			case FILESYSTEM:
588 				if (profile_conf->fs_container == NULL)
589 					profile_conf->fs_container =
590 					    tmp_container;
591 				else
592 					insert_container(profile_conf->
593 							 fs_container,
594 							 tmp_container);
595 				break;
596 			case THREAD_GROUP:
597 				if (profile_conf->tg_container == NULL)
598 					profile_conf->tg_container =
599 					    tmp_container;
600 				else
601 					insert_container(profile_conf->
602 							 tg_container,
603 							 tmp_container);
604 				break;
605 			default:
606 				break;
607 			}
608 		if (!is_option && !tmp_container) {
609 			printf("ERROR!!! Unknow option: %s", buf);
610 			exit(1);
611 		}
612 		buf = get_next_line(f);
613 	}
614 	return profile_conf;
615 }
616 
set_weight(ffsb_tg_t * tg,config_options_t * config)617 void set_weight(ffsb_tg_t * tg, config_options_t * config)
618 {
619 	char *op;
620 	int len;
621 	config_options_t *tmp_config = config;
622 
623 	while (tmp_config->name) {
624 		if (tmp_config->type == TYPE_WEIGHT) {
625 			len = strlen(tmp_config->name);
626 			op = malloc(sizeof(char) * len - 6);
627 			memset(op, 0, sizeof(char) * len - 6);
628 			strncpy(op, tmp_config->name, len - 7);
629 			tg_set_op_weight(tg, op,
630 					 get_config_u32(config,
631 							tmp_config->name));
632 			free(op);
633 		}
634 		tmp_config++;
635 	}
636 }
637 
get_weight_total(ffsb_tg_t * tg)638 int get_weight_total(ffsb_tg_t * tg)
639 {
640 	char *op;
641 	int len;
642 	int total = 0;
643 	config_options_t *tmp_config = tg_options;
644 
645 	while (tmp_config->name) {
646 		if (tmp_config->type == TYPE_WEIGHT) {
647 			len = strlen(tmp_config->name);
648 			op = malloc(sizeof(char) * len - 6);
649 			memset(op, 0, sizeof(char) * len - 6);
650 			strncpy(op, tmp_config->name, len - 7);
651 			total += tg_get_op_weight(tg, op);
652 			free(op);
653 		}
654 		tmp_config++;
655 	}
656 	return total;
657 }
658 
659 /* !!! hackish verification function, we should somehow roll this into the */
660 /* op descriptions/struct themselves at some point with a callback verify */
661 /* op requirements: */
662 /* require tg->read_blocksize:  read, readall */
663 /* require tg->write_blocksize: write, create, append, rewritefsync */
664 /* */
665 
verify_tg(ffsb_tg_t * tg)666 static int verify_tg(ffsb_tg_t * tg)
667 {
668 	uint32_t read_weight = tg_get_op_weight(tg, "read");
669 	uint32_t readall_weight = tg_get_op_weight(tg, "readall");
670 	uint32_t write_weight = tg_get_op_weight(tg, "write");
671 	uint32_t create_weight = tg_get_op_weight(tg, "create");
672 	uint32_t append_weight = tg_get_op_weight(tg, "append");
673 	uint32_t createdir_weight = tg_get_op_weight(tg, "createdir");
674 	uint32_t delete_weight = tg_get_op_weight(tg, "delete");
675 	uint32_t writeall_weight = tg_get_op_weight(tg, "writeall");
676 	uint32_t writeall_fsync_weight = tg_get_op_weight(tg, "writeall_fsync");
677 
678 	uint32_t sum_weight = get_weight_total(tg);
679 
680 	uint32_t read_blocksize = tg_get_read_blocksize(tg);
681 	uint32_t write_blocksize = tg_get_write_blocksize(tg);
682 
683 	int read_random = tg_get_read_random(tg);
684 	int read_skip = tg_get_read_skip(tg);
685 	uint32_t read_skipsize = tg_get_read_skipsize(tg);
686 
687 	if (sum_weight == 0) {
688 		printf("Error: A threadgroup must have at least one weighted "
689 		       "operation\n");
690 		return 1;
691 	}
692 
693 	if ((read_weight || readall_weight) && !(read_blocksize)) {
694 		printf("Error: read and readall operations require a "
695 		       "read_blocksize\n");
696 		return 1;
697 	}
698 
699 	if ((write_weight || create_weight || append_weight || writeall_weight
700 	     || writeall_fsync_weight) && !(write_blocksize)) {
701 		printf("Error: write, writeall, create, append"
702 		       "operations require a write_blocksize\n");
703 		return 1;
704 	}
705 
706 	if (read_random && read_skip) {
707 		printf("Error: read_random and read_skip are mutually "
708 		       "exclusive\n");
709 		return 1;
710 	}
711 
712 	if (read_skip && !(read_skipsize)) {
713 		printf("Error: read_skip specified but read_skipsize is "
714 		       "zero\n");
715 		return 1;
716 	}
717 
718 	return 0;
719 }
720 
get_num_containers(container_t * container)721 static unsigned get_num_containers(container_t * container)
722 {
723 	int numtg = 0;
724 	while (container) {
725 		numtg++;
726 		container = container->next;
727 	}
728 	return numtg;
729 }
730 
get_num_threadgroups(profile_config_t * profile_conf)731 static unsigned get_num_threadgroups(profile_config_t * profile_conf)
732 {
733 	return get_num_containers(profile_conf->tg_container);
734 }
735 
get_num_filesystems(profile_config_t * profile_conf)736 static unsigned get_num_filesystems(profile_config_t * profile_conf)
737 {
738 	return get_num_containers(profile_conf->fs_container);
739 }
740 
get_num_totalthreads(profile_config_t * profile_conf)741 static int get_num_totalthreads(profile_config_t * profile_conf)
742 {
743 	int num_threads = 0;
744 	container_t *tg = profile_conf->tg_container;
745 	config_options_t *tg_config;
746 
747 	while (tg) {
748 		tg_config = tg->config;
749 		while (tg_config->name) {
750 			if (!strcmp(tg_config->name, "num_threads"))
751 				num_threads += *(uint32_t *) tg_config->value;
752 			tg_config++;
753 		}
754 		if (tg->next)
755 			tg = tg->next;
756 		else
757 			break;
758 	}
759 
760 	return num_threads;
761 }
762 
get_container(container_t * head_cont,int pos)763 container_t *get_container(container_t * head_cont, int pos)
764 {
765 	int count = 0;
766 	while (head_cont) {
767 		if (count == pos)
768 			return head_cont;
769 		head_cont = head_cont->next;
770 		count++;
771 	}
772 	return NULL;
773 }
774 
get_fs_config(ffsb_config_t * fc,int pos)775 config_options_t *get_fs_config(ffsb_config_t * fc, int pos)
776 {
777 	container_t *tmp_cont;
778 
779 	assert(pos < fc->num_filesys);
780 	tmp_cont = get_container(fc->profile_conf->fs_container, pos);
781 	if (tmp_cont)
782 		return tmp_cont->config;
783 	return NULL;
784 }
785 
get_fs_container(ffsb_config_t * fc,int pos)786 container_t *get_fs_container(ffsb_config_t * fc, int pos)
787 {
788 	assert(pos < fc->num_filesys);
789 	return get_container(fc->profile_conf->fs_container, pos);
790 }
791 
get_tg_config(ffsb_config_t * fc,int pos)792 config_options_t *get_tg_config(ffsb_config_t * fc, int pos)
793 {
794 	container_t *tmp_cont;
795 
796 	assert(pos < fc->num_threadgroups);
797 	tmp_cont = get_container(fc->profile_conf->tg_container, pos);
798 	if (tmp_cont)
799 		return tmp_cont->config;
800 	return NULL;
801 }
802 
get_tg_container(ffsb_config_t * fc,int pos)803 container_t *get_tg_container(ffsb_config_t * fc, int pos)
804 {
805 	assert(pos < fc->num_threadgroups);
806 	return get_container(fc->profile_conf->tg_container, pos);
807 }
808 
init_threadgroup(ffsb_config_t * fc,config_options_t * config,ffsb_tg_t * tg,int tg_num)809 static void init_threadgroup(ffsb_config_t * fc, config_options_t * config,
810 			     ffsb_tg_t * tg, int tg_num)
811 {
812 	int num_threads;
813 	memset(tg, 0, sizeof(ffsb_tg_t));
814 
815 	num_threads = get_config_u32(config, "num_threads");
816 
817 	init_ffsb_tg(tg, num_threads, tg_num);
818 
819 	if (get_config_str(config, "bindfs")) {
820 		int i;
821 		config_options_t *tmp_config;
822 		for (i = 0; i < fc->num_filesys; i++) {
823 			tmp_config = get_fs_config(fc, i);
824 			if (!strcmp(get_config_str(config, "bindfs"),
825 				    get_config_str(tmp_config, "location")))
826 				break;
827 		}
828 		if (strcmp(get_config_str(config, "bindfs"),
829 			   get_config_str(tmp_config, "location"))) {
830 			printf("Bind fs failed:  Base fs \"%s\" not found\n",
831 			       get_config_str(config, "bindfs"));
832 			exit(1);
833 		}
834 		printf("%d\n", i);
835 		tg->bindfs = i;
836 	}
837 
838 	tg->read_random = get_config_bool(config, "read_random");
839 	tg->read_size = get_config_u64(config, "read_size");
840 	tg->read_skip = get_config_bool(config, "read_skip");
841 	tg->read_skipsize = get_config_u32(config, "read_skipsize");
842 
843 	tg->write_random = get_config_bool(config, "write_random");
844 	tg->write_size = get_config_u64(config, "write_size");
845 	tg->fsync_file = get_config_bool(config, "fsync_file");
846 
847 	tg->wait_time = get_config_u32(config, "op_delay");
848 
849 	tg_set_read_blocksize(tg, get_config_u32(config, "read_blocksize"));
850 	tg_set_write_blocksize(tg, get_config_u32(config, "write_blocksize"));
851 
852 	set_weight(tg, config);
853 
854 	if (verify_tg(tg)) {
855 		printf("threadgroup %d verification failed\n", tg_num);
856 		exit(1);
857 	}
858 }
859 
init_filesys(ffsb_config_t * fc,int num)860 static void init_filesys(ffsb_config_t * fc, int num)
861 {
862 	config_options_t *config = get_fs_config(fc, num);
863 	profile_config_t *profile_conf = fc->profile_conf;
864 	ffsb_fs_t *fs = &fc->filesystems[num];
865 	value_list_t *tmp_list, *list_head;
866 
867 	memset(fs, 0, sizeof(ffsb_fs_t));
868 
869 	fs->basedir = get_config_str(config, "location");
870 
871 	if (get_config_str(config, "clone")) {
872 		int i;
873 		config_options_t *tmp_config;
874 		for (i = 0; i < fc->num_filesys; i++) {
875 			tmp_config = get_fs_config(fc, i);
876 			if (!strcmp(get_config_str(config, "clone"),
877 				    get_config_str(tmp_config, "location")))
878 				break;
879 		}
880 		if (strcmp(get_config_str(config, "clone"),
881 			   get_config_str(tmp_config, "location"))) {
882 			printf("Clone fs failed:  Base fs \"%s\" not found\n",
883 			       get_config_str(config, "clone"));
884 			exit(1);
885 		}
886 		config = tmp_config;
887 	}
888 
889 	fs->num_dirs = get_config_u32(config, "num_dirs");
890 	fs->num_start_files = get_config_u32(config, "num_files");
891 	fs->minfilesize = get_config_u64(config, "min_filesize");
892 	fs->maxfilesize = get_config_u64(config, "max_filesize");
893 	fs->desired_fsutil = get_config_double(config, "desired_util");
894 	fs->init_fsutil = get_config_double(config, "init_util");
895 	fs->init_size = get_config_u64(config, "init_size");
896 
897 	fs->flags = 0;
898 	if (get_config_bool(config, "reuse"))
899 		fs->flags |= FFSB_FS_REUSE_FS;
900 
901 	if (get_config_bool(profile_conf->global, "directio"))
902 		 fs->flags |= FFSB_FS_DIRECTIO | FFSB_FS_ALIGNIO4K;
903 
904 	if (get_config_bool(profile_conf->global, "bufferio"))
905 		 fs->flags |= FFSB_FS_LIBCIO;
906 
907 	if (get_config_bool(profile_conf->global, "alignio"))
908 		 fs->flags |= FFSB_FS_ALIGNIO4K;
909 
910 	if (get_config_bool(config, "agefs")) {
911 		container_t *age_cont = get_fs_container(fc, num);
912 		if (!age_cont->child) {
913 			printf("No age threaggroup in profile");
914 			exit(1);
915 		}
916 
917 		age_cont = age_cont->child;
918 		ffsb_tg_t *age_tg = ffsb_malloc(sizeof(ffsb_tg_t));
919 		init_threadgroup(fc, age_cont->config, age_tg, 0);
920 		fs->aging_tg = age_tg;
921 		fs->age_fs = 1;
922 	}
923 
924 	if (get_config_u32(config, "create_blocksize"))
925 		fs->create_blocksize = get_config_u32(config,
926 						      "create_blocksize");
927 	else
928 		fs->create_blocksize = FFSB_FS_DEFAULT_CREATE_BLOCKSIZE;
929 
930 	if (get_config_u32(config, "age_blocksize"))
931 		fs->age_blocksize = get_config_u32(config, "age_blocksize");
932 	else
933 		fs->age_blocksize = FFSB_FS_DEFAULT_AGE_BLOCKSIZE;
934 
935 	list_head = (value_list_t *) get_value(config, "size_weight");
936 	if (list_head) {
937 		int count = 0;
938 		size_weight_t *sizew;
939 		list_for_each_entry(tmp_list, &list_head->list, list)
940 		    count++;
941 
942 		fs->num_weights = count;
943 		fs->size_weights =
944 		    malloc(sizeof(size_weight_t) * fs->num_weights);
945 
946 		count = 0;
947 		list_for_each_entry(tmp_list, &list_head->list, list) {
948 			sizew = (size_weight_t *) tmp_list->value;
949 			fs->size_weights[count].size = sizew->size;
950 			fs->size_weights[count].weight = sizew->weight;
951 			fs->sum_weights += sizew->weight;
952 			count++;
953 		}
954 	}
955 }
956 
init_tg_stats(ffsb_config_t * fc,int num)957 static void init_tg_stats(ffsb_config_t * fc, int num)
958 {
959 	config_options_t *config;
960 	container_t *tmp_cont;
961 	value_list_t *tmp_list, *list_head;
962 	syscall_t sys;
963 	ffsb_statsc_t fsc = { 0, };
964 	char *sys_name;
965 	range_t *bucket_range;
966 	uint32_t min, max;
967 
968 	tmp_cont = get_tg_container(fc, num);
969 	if (tmp_cont->child) {
970 		if (tmp_cont->type == STATS) {
971 			config = tmp_cont->config;
972 			if (get_config_bool(config, "enable_stats")) {
973 
974 				list_head =
975 				    (value_list_t *) get_value(config,
976 							       "ignore");
977 				if (list_head)
978 					list_for_each_entry(tmp_list,
979 							    &list_head->list,
980 							    list) {
981 					sys_name = (char *)tmp_list->value;
982 					ffsb_stats_str2syscall(sys_name, &sys);
983 					ffsb_statsc_ignore_sys(&fsc, sys);
984 					}
985 
986 				list_head =
987 				    (value_list_t *) get_value(config,
988 							       "msec_range");
989 				if (list_head
990 				    && get_config_bool(config, "enable_range"))
991 					list_for_each_entry(tmp_list,
992 							    &list_head->list,
993 							    list) {
994 					bucket_range =
995 					    (range_t *) tmp_list->value;
996 					min =
997 					    (uint32_t) (bucket_range->a *
998 							1000.0f);
999 					max =
1000 					    (uint32_t) (bucket_range->b *
1001 							1000.0f);
1002 					ffsb_statsc_addbucket(&fsc, min, max);
1003 					}
1004 
1005 				tg_set_statsc(&fc->groups[num], &fsc);
1006 			}
1007 		}
1008 	}
1009 }
1010 
init_config(ffsb_config_t * fc,profile_config_t * profile_conf)1011 static void init_config(ffsb_config_t * fc, profile_config_t * profile_conf)
1012 {
1013 	config_options_t *config;
1014 	container_t *tmp_cont;
1015 	int i;
1016 
1017 	fc->time = get_config_u32(profile_conf->global, "time");
1018 	fc->num_filesys = get_num_filesystems(profile_conf);
1019 	fc->num_threadgroups = get_num_threadgroups(profile_conf);
1020 	fc->num_totalthreads = get_num_totalthreads(profile_conf);
1021 	fc->profile_conf = profile_conf;
1022 	fc->callout = get_config_str(profile_conf->global, "callout");
1023 
1024 	fc->filesystems = ffsb_malloc(sizeof(ffsb_fs_t) * fc->num_filesys);
1025 	for (i = 0; i < fc->num_filesys; i++)
1026 		init_filesys(fc, i);
1027 
1028 	fc->groups = ffsb_malloc(sizeof(ffsb_tg_t) * fc->num_threadgroups);
1029 	for (i = 0; i < fc->num_threadgroups; i++) {
1030 		config = get_tg_config(fc, i);
1031 		init_threadgroup(fc, config, &fc->groups[i], i);
1032 		init_tg_stats(fc, i);
1033 	}
1034 }
1035 
ffsb_parse_newconfig(ffsb_config_t * fc,char * filename)1036 void ffsb_parse_newconfig(ffsb_config_t * fc, char *filename)
1037 {
1038 	FILE *f;
1039 
1040 	profile_config_t *profile_conf;
1041 
1042 	f = fopen(filename, "r");
1043 	if (f == NULL) {
1044 		perror(filename);
1045 		exit(1);
1046 	}
1047 	profile_conf = parse(f);
1048 	fclose(f);
1049 
1050 	init_config(fc, profile_conf);
1051 }
1052