Home | History | Annotate | Download | only in ffsb-6.0-rc2
      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 */
     40 void parseerror(char *msg)
     41 {
     42 	fprintf(stderr, "Error parsing %s\n", msg);
     43 	exit(1);
     44 }
     45 
     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 
     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 
     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 	memset(unit, 0, sizeof(unit));
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    531 char *get_config_str(config_options_t * config, char *name)
    532 {
    533 	return get_value(config, name);
    534 }
    535 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    731 static unsigned get_num_threadgroups(profile_config_t * profile_conf)
    732 {
    733 	return get_num_containers(profile_conf->tg_container);
    734 }
    735 
    736 static unsigned get_num_filesystems(profile_config_t * profile_conf)
    737 {
    738 	return get_num_containers(profile_conf->fs_container);
    739 }
    740 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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