/*
|
* Copyright (c) International Business Machines Corp., 2001-2004
|
*
|
* This program is free software; you can redistribute it and/or modify
|
* it under the terms of the GNU General Public License as published by
|
* the Free Software Foundation; either version 2 of the License, or
|
* (at your option) any later version.
|
*
|
* This program is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
* the GNU General Public License for more details.
|
*
|
* You should have received a copy of the GNU General Public License
|
* along with this program; if not, write to the Free Software
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
*/
|
#include <stdio.h>
|
#include <string.h>
|
#include <assert.h>
|
#include <inttypes.h>
|
#include <ctype.h>
|
|
#include "ffsb.h"
|
#include "parser.h"
|
#include "ffsb_tg.h"
|
#include "ffsb_stats.h"
|
#include "util.h"
|
#include "list.h"
|
|
#define BUFSIZE 1024
|
|
config_options_t global_options[] = GLOBAL_OPTIONS;
|
config_options_t tg_options[] = THREADGROUP_OPTIONS;
|
config_options_t fs_options[] = FILESYSTEM_OPTIONS;
|
config_options_t stats_options[] = STATS_OPTIONS;
|
container_desc_t container_desc[] = CONTAINER_DESC;
|
|
/* strips out whitespace and comments, returns NULL on eof */
|
void parseerror(char *msg)
|
{
|
fprintf(stderr, "Error parsing %s\n", msg);
|
exit(1);
|
}
|
|
static char *get_next_line(FILE * f)
|
{
|
static char buf[BUFSIZE];
|
char *ret, *tmp;
|
int flag = 1;
|
while (flag) {
|
ret = fgets(buf, BUFSIZE, f);
|
if (ret == NULL)
|
return NULL;
|
ret = buf;
|
while (isspace(*ret))
|
ret++;
|
|
if ((*ret == COMMENT_CHAR) || (*ret == '\0'))
|
continue;
|
|
tmp = ret;
|
while (*tmp != '\0') {
|
if (*tmp == COMMENT_CHAR) {
|
*tmp = '\0';
|
break;
|
}
|
tmp++;
|
}
|
flag = 0;
|
}
|
return ret;
|
}
|
|
static char *strip_space(char *buf)
|
{
|
int len;
|
char *tmp, *tmp2;
|
int flag = 1;
|
|
len = strnlen(buf, BUFSIZE);
|
tmp = malloc(sizeof(char) * len);
|
memset(tmp, 0, sizeof(char) * len);
|
tmp2 = tmp;
|
while (flag) {
|
if (!isspace(*buf)) {
|
*tmp = *buf;
|
tmp++;
|
}
|
buf++;
|
if (*buf != '\0')
|
continue;
|
flag = 0;
|
}
|
return tmp2;
|
}
|
|
static uint64_t size64_convert(char *buf)
|
{
|
size_t buf_size = strlen(buf);
|
char unit[3] = { 0 };
|
char search_str[256];
|
uint64_t size;
|
uint64_t multiplier = 1;
|
int i;
|
|
if (buf_size == 1)
|
goto out;
|
|
strcpy(unit, buf + (buf_size - 2));
|
for (i = 0; i < 2; i++) {
|
if (isdigit(unit[i]))
|
goto try_single;
|
unit[i] = toupper(unit[i]);
|
}
|
goto do_multiplier;
|
|
try_single:
|
memset(unit, 0, sizeof(unit));
|
strcpy(unit, buf + (buf_size - 1));
|
if (isdigit(unit[0])) {
|
unit[0] = 0;
|
goto out;
|
}
|
unit[0] = toupper(unit[0]);
|
|
do_multiplier:
|
if (!strcmp("KB", unit) || !strcmp("K", unit))
|
multiplier = 1024;
|
if (!strcmp("MB", unit) || !strcmp("M", unit))
|
multiplier = 1048576;
|
if (!strcmp("GB", unit) || !strcmp("G", unit))
|
multiplier = 1073741824;
|
if (multiplier == 1) {
|
unit[0] = 0;
|
multiplier = 0;
|
}
|
out:
|
sprintf(search_str, "%%llu%s", unit);
|
if (1 == sscanf(buf, search_str, &size))
|
return size * multiplier;
|
return 0;
|
}
|
|
static uint64_t *get_opt64(char *buf, char string[])
|
{
|
char search_str[256];
|
char *line = strip_space(buf);
|
uint64_t temp;
|
uint64_t *ret;
|
|
sprintf(search_str, "%s=%%llu\\n", string);
|
if (1 == sscanf(line, search_str, &temp)) {
|
ret = malloc(sizeof(uint64_t));
|
*ret = temp;
|
return ret;
|
}
|
free(line);
|
return NULL;
|
}
|
|
static uint32_t *get_opt32(char *buf, char string[])
|
{
|
uint32_t *ret;
|
uint64_t *res;
|
res = get_opt64(buf, string);
|
if (res) {
|
ret = malloc(sizeof(uint32_t));
|
*ret = *res;
|
free(res);
|
return ret;
|
}
|
return NULL;
|
}
|
|
static uint8_t *get_optbool(char *buf, char string[])
|
{
|
uint8_t *ret;
|
uint64_t *res;
|
res = get_opt64(buf, string);
|
if (res) {
|
if ((int)*res < 0 || (int)*res > 1) {
|
printf("Error in: %s", buf);
|
printf("%llu not boolean\n", (long long unsigned)*res);
|
exit(1);
|
}
|
ret = malloc(sizeof(uint8_t));
|
*ret = *res;
|
free(res);
|
return ret;
|
}
|
return NULL;
|
}
|
|
static char *get_optstr(char *buf, char string[])
|
{
|
char search_str[256];
|
char *line = strip_space(buf);
|
char *ret_buf;
|
char temp[BUFSIZE];
|
int len;
|
|
len = strnlen(string, BUFSIZE);
|
sprintf(search_str, "%s=%%%ds\\n", string, BUFSIZE - len - 1);
|
if (1 == sscanf(line, search_str, &temp)) {
|
len = strnlen(temp, 4096);
|
ret_buf = malloc(len);
|
strncpy(ret_buf, temp, len);
|
return ret_buf;
|
}
|
free(line);
|
return NULL;
|
}
|
|
static double *get_optdouble(char *buf, char string[])
|
{
|
char search_str[256];
|
char *line = strip_space(buf);
|
double temp;
|
double *ret;
|
|
sprintf(search_str, "%s=%%lf\\n", string);
|
if (1 == sscanf(line, search_str, &temp)) {
|
ret = malloc(sizeof(double));
|
*ret = temp;
|
return ret;
|
}
|
free(line);
|
return NULL;
|
}
|
|
static range_t *get_optrange(char *buf, char string[])
|
{
|
char search_str[256];
|
double a, b;
|
range_t *ret;
|
|
sprintf(search_str, "%s %%lf %%lf\\n", string);
|
if (2 == sscanf(buf, search_str, &a, &b)) {
|
ret = malloc(sizeof(struct range));
|
ret->a = a;
|
ret->b = b;
|
return ret;
|
}
|
return NULL;
|
}
|
|
static size_weight_t *get_optsizeweight(char *buf, char string[])
|
{
|
char search_str[256];
|
char size[256];
|
int weight;
|
size_weight_t *ret;
|
|
sprintf(search_str, "%s %%s %%d\\n", string);
|
if (2 == sscanf(buf, search_str, &size, &weight)) {
|
ret = malloc(sizeof(struct size_weight));
|
ret->size = size64_convert(size);
|
ret->weight = weight;
|
return ret;
|
}
|
return NULL;
|
}
|
|
static uint64_t *get_optsize64(char *buf, char string[])
|
{
|
char search_str[256];
|
char *line = strip_space(buf);
|
char temp[256];
|
uint64_t size;
|
uint64_t *ret = NULL;
|
|
sprintf(search_str, "%s=%%s\\n", string);
|
if (1 == sscanf(line, search_str, &temp)) {
|
ret = malloc(sizeof(uint64_t));
|
*ret = size64_convert(temp);
|
}
|
free(line);
|
return ret;
|
}
|
|
static uint32_t *get_optsize32(char *buf, char string[])
|
{
|
uint32_t *ret;
|
uint64_t *res;
|
res = get_optsize64(buf, string);
|
if (res) {
|
ret = malloc(sizeof(uint32_t));
|
*ret = *res;
|
free(res);
|
return ret;
|
}
|
return NULL;
|
}
|
|
static uint64_t *get_deprecated(char *buf, char string[])
|
{
|
char search_str[256];
|
char temp[BUFSIZE];
|
int len;
|
|
len = strnlen(string, BUFSIZE);
|
sprintf(search_str, "%s%%%ds\\n", string, BUFSIZE - len - 1);
|
if (1 == sscanf(buf, search_str, &temp))
|
printf("WARNING: The \"%s\" option is deprecated!!!\n", string);
|
|
return NULL;
|
}
|
|
static container_t *init_container(void)
|
{
|
container_t *container;
|
container = malloc(sizeof(container_t));
|
container->config = NULL;
|
container->type = 0;
|
container->next = NULL;
|
return container;
|
}
|
|
static int set_option(char *buf, config_options_t * options)
|
{
|
void *value;
|
|
while (options->name) {
|
switch (options->type) {
|
case TYPE_WEIGHT:
|
case TYPE_U32:
|
value = get_opt32(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_U64:
|
value = get_opt64(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_STRING:
|
value = get_optstr(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_BOOLEAN:
|
value = get_optbool(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_DOUBLE:
|
value = get_optdouble(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_RANGE:
|
value = get_optrange(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_SIZEWEIGHT:
|
value = get_optsizeweight(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_DEPRECATED:
|
value = get_deprecated(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_SIZE32:
|
value = get_optsize32(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
case TYPE_SIZE64:
|
value = get_optsize64(buf, options->name);
|
if (value)
|
goto out;
|
break;
|
default:
|
printf("Unknown type\n");
|
break;
|
}
|
options++;
|
}
|
return 0;
|
|
out:
|
if (options->storage_type == STORE_SINGLE)
|
options->value = value;
|
if (options->storage_type == STORE_LIST) {
|
if (!options->value) {
|
value_list_t *lhead;
|
lhead = malloc(sizeof(struct value_list));
|
INIT_LIST_HEAD(&lhead->list);
|
options->value = lhead;
|
}
|
value_list_t *tmp_list, *tmp_list2;
|
tmp_list = malloc(sizeof(struct value_list));
|
INIT_LIST_HEAD(&tmp_list->list);
|
tmp_list->value = value;
|
tmp_list2 = (struct value_list *)options->value;
|
list_add(&(tmp_list->list), &(tmp_list2->list));
|
}
|
|
return 1;
|
}
|
|
void insert_container(container_t * container, container_t * new_container)
|
{
|
while (container->next)
|
container = container->next;
|
container->next = new_container;
|
}
|
|
container_t *search_group(char *, FILE *);
|
|
container_t *handle_container(char *buf, FILE * f, uint32_t type,
|
config_options_t * options)
|
{
|
container_desc_t *desc = container_desc;
|
container_t *ret_container;
|
container_t *tmp_container, *tmp2_container;
|
container_t *child = NULL;
|
int is_option;
|
|
while (desc->name)
|
if (desc->type == type)
|
break;
|
else
|
desc++;
|
|
if (!desc->name)
|
return NULL;
|
|
buf = get_next_line(f);
|
while (buf) {
|
is_option = set_option(buf, options);
|
tmp_container = search_group(buf, f);
|
if (tmp_container) {
|
if (tmp_container->type == END) {
|
free(tmp_container);
|
break;
|
} else {
|
if (child == NULL)
|
child = tmp_container;
|
else {
|
tmp2_container = child;
|
while (tmp2_container->next)
|
tmp2_container =
|
tmp2_container->next;
|
tmp2_container->next = tmp_container;
|
}
|
|
}
|
}
|
if (!is_option && !tmp_container) {
|
printf("ERROR!!! Unknow option: %s", buf);
|
exit(1);
|
}
|
buf = get_next_line(f);
|
}
|
ret_container = init_container();
|
ret_container->config = options;
|
ret_container->type = type;
|
if (child)
|
ret_container->child = child;
|
|
return ret_container;
|
}
|
|
container_t *search_group(char *buf, FILE * f)
|
{
|
char temp[BUFSIZE];
|
char *ptr;
|
config_options_t *options;
|
container_desc_t *desc = container_desc;
|
container_t *ret_container;
|
|
if (1 == sscanf(buf, "[%s]\n", (char *)&temp))
|
while (desc->name) {
|
ptr = strstr(buf, desc->name);
|
if (ptr)
|
switch (desc->type) {
|
case FILESYSTEM:
|
options = malloc(sizeof(fs_options));
|
memcpy(options, fs_options,
|
sizeof(fs_options));
|
return handle_container(buf, f,
|
desc->type,
|
options);
|
break;
|
case THREAD_GROUP:
|
options = malloc(sizeof(tg_options));
|
memcpy(options, tg_options,
|
sizeof(tg_options));
|
return handle_container(buf, f,
|
desc->type,
|
options);
|
break;
|
case STATS:
|
options = malloc(sizeof(stats_options));
|
memcpy(options, stats_options,
|
sizeof(stats_options));
|
return handle_container(buf, f,
|
desc->type,
|
options);
|
break;
|
case END:
|
ret_container = init_container();
|
ret_container->type = END;
|
return ret_container;
|
break;
|
}
|
desc++;
|
}
|
return NULL;
|
}
|
|
void *get_value(config_options_t * config, char *name)
|
{
|
while (config->name) {
|
if (!strcmp(config->name, name)) {
|
if (config->value)
|
return config->value;
|
else
|
return NULL;
|
}
|
config++;
|
}
|
return 0;
|
}
|
|
char *get_config_str(config_options_t * config, char *name)
|
{
|
return get_value(config, name);
|
}
|
|
uint32_t get_config_u32(config_options_t * config, char *name)
|
{
|
void *value = get_value(config, name);
|
if (value)
|
return *(uint32_t *) value;
|
return 0;
|
}
|
|
uint8_t get_config_bool(config_options_t * config, char *name)
|
{
|
void *value = get_value(config, name);
|
if (value)
|
return *(uint8_t *) value;
|
return 0;
|
}
|
|
uint64_t get_config_u64(config_options_t * config, char *name)
|
{
|
void *value = get_value(config, name);
|
if (value)
|
return *(uint64_t *) value;
|
return 0;
|
}
|
|
double get_config_double(config_options_t * config, char *name)
|
{
|
void *value = get_value(config, name);
|
if (value)
|
return *(double *)value;
|
return 0;
|
}
|
|
static profile_config_t *parse(FILE * f)
|
{
|
char *buf;
|
profile_config_t *profile_conf;
|
container_t *tmp_container;
|
|
profile_conf = malloc(sizeof(profile_config_t));
|
profile_conf->global = malloc(sizeof(global_options));
|
memcpy(profile_conf->global, global_options, sizeof(global_options));
|
profile_conf->fs_container = NULL;
|
profile_conf->tg_container = NULL;
|
int is_option;
|
buf = get_next_line(f);
|
|
while (buf) {
|
is_option = set_option(buf, profile_conf->global);
|
tmp_container = search_group(buf, f);
|
if (tmp_container)
|
switch (tmp_container->type) {
|
case FILESYSTEM:
|
if (profile_conf->fs_container == NULL)
|
profile_conf->fs_container =
|
tmp_container;
|
else
|
insert_container(profile_conf->
|
fs_container,
|
tmp_container);
|
break;
|
case THREAD_GROUP:
|
if (profile_conf->tg_container == NULL)
|
profile_conf->tg_container =
|
tmp_container;
|
else
|
insert_container(profile_conf->
|
tg_container,
|
tmp_container);
|
break;
|
default:
|
break;
|
}
|
if (!is_option && !tmp_container) {
|
printf("ERROR!!! Unknow option: %s", buf);
|
exit(1);
|
}
|
buf = get_next_line(f);
|
}
|
return profile_conf;
|
}
|
|
void set_weight(ffsb_tg_t * tg, config_options_t * config)
|
{
|
char *op;
|
int len;
|
config_options_t *tmp_config = config;
|
|
while (tmp_config->name) {
|
if (tmp_config->type == TYPE_WEIGHT) {
|
len = strlen(tmp_config->name);
|
op = malloc(sizeof(char) * len - 6);
|
memset(op, 0, sizeof(char) * len - 6);
|
strncpy(op, tmp_config->name, len - 7);
|
tg_set_op_weight(tg, op,
|
get_config_u32(config,
|
tmp_config->name));
|
free(op);
|
}
|
tmp_config++;
|
}
|
}
|
|
int get_weight_total(ffsb_tg_t * tg)
|
{
|
char *op;
|
int len;
|
int total = 0;
|
config_options_t *tmp_config = tg_options;
|
|
while (tmp_config->name) {
|
if (tmp_config->type == TYPE_WEIGHT) {
|
len = strlen(tmp_config->name);
|
op = malloc(sizeof(char) * len - 6);
|
memset(op, 0, sizeof(char) * len - 6);
|
strncpy(op, tmp_config->name, len - 7);
|
total += tg_get_op_weight(tg, op);
|
free(op);
|
}
|
tmp_config++;
|
}
|
return total;
|
}
|
|
/* !!! hackish verification function, we should somehow roll this into the */
|
/* op descriptions/struct themselves at some point with a callback verify */
|
/* op requirements: */
|
/* require tg->read_blocksize: read, readall */
|
/* require tg->write_blocksize: write, create, append, rewritefsync */
|
/* */
|
|
static int verify_tg(ffsb_tg_t * tg)
|
{
|
uint32_t read_weight = tg_get_op_weight(tg, "read");
|
uint32_t readall_weight = tg_get_op_weight(tg, "readall");
|
uint32_t write_weight = tg_get_op_weight(tg, "write");
|
uint32_t create_weight = tg_get_op_weight(tg, "create");
|
uint32_t append_weight = tg_get_op_weight(tg, "append");
|
uint32_t createdir_weight = tg_get_op_weight(tg, "createdir");
|
uint32_t delete_weight = tg_get_op_weight(tg, "delete");
|
uint32_t writeall_weight = tg_get_op_weight(tg, "writeall");
|
uint32_t writeall_fsync_weight = tg_get_op_weight(tg, "writeall_fsync");
|
|
uint32_t sum_weight = get_weight_total(tg);
|
|
uint32_t read_blocksize = tg_get_read_blocksize(tg);
|
uint32_t write_blocksize = tg_get_write_blocksize(tg);
|
|
int read_random = tg_get_read_random(tg);
|
int read_skip = tg_get_read_skip(tg);
|
uint32_t read_skipsize = tg_get_read_skipsize(tg);
|
|
if (sum_weight == 0) {
|
printf("Error: A threadgroup must have at least one weighted "
|
"operation\n");
|
return 1;
|
}
|
|
if ((read_weight || readall_weight) && !(read_blocksize)) {
|
printf("Error: read and readall operations require a "
|
"read_blocksize\n");
|
return 1;
|
}
|
|
if ((write_weight || create_weight || append_weight || writeall_weight
|
|| writeall_fsync_weight) && !(write_blocksize)) {
|
printf("Error: write, writeall, create, append"
|
"operations require a write_blocksize\n");
|
return 1;
|
}
|
|
if (read_random && read_skip) {
|
printf("Error: read_random and read_skip are mutually "
|
"exclusive\n");
|
return 1;
|
}
|
|
if (read_skip && !(read_skipsize)) {
|
printf("Error: read_skip specified but read_skipsize is "
|
"zero\n");
|
return 1;
|
}
|
|
return 0;
|
}
|
|
static unsigned get_num_containers(container_t * container)
|
{
|
int numtg = 0;
|
while (container) {
|
numtg++;
|
container = container->next;
|
}
|
return numtg;
|
}
|
|
static unsigned get_num_threadgroups(profile_config_t * profile_conf)
|
{
|
return get_num_containers(profile_conf->tg_container);
|
}
|
|
static unsigned get_num_filesystems(profile_config_t * profile_conf)
|
{
|
return get_num_containers(profile_conf->fs_container);
|
}
|
|
static int get_num_totalthreads(profile_config_t * profile_conf)
|
{
|
int num_threads = 0;
|
container_t *tg = profile_conf->tg_container;
|
config_options_t *tg_config;
|
|
while (tg) {
|
tg_config = tg->config;
|
while (tg_config->name) {
|
if (!strcmp(tg_config->name, "num_threads"))
|
num_threads += *(uint32_t *) tg_config->value;
|
tg_config++;
|
}
|
if (tg->next)
|
tg = tg->next;
|
else
|
break;
|
}
|
|
return num_threads;
|
}
|
|
container_t *get_container(container_t * head_cont, int pos)
|
{
|
int count = 0;
|
while (head_cont) {
|
if (count == pos)
|
return head_cont;
|
head_cont = head_cont->next;
|
count++;
|
}
|
return NULL;
|
}
|
|
config_options_t *get_fs_config(ffsb_config_t * fc, int pos)
|
{
|
container_t *tmp_cont;
|
|
assert(pos < fc->num_filesys);
|
tmp_cont = get_container(fc->profile_conf->fs_container, pos);
|
if (tmp_cont)
|
return tmp_cont->config;
|
return NULL;
|
}
|
|
container_t *get_fs_container(ffsb_config_t * fc, int pos)
|
{
|
assert(pos < fc->num_filesys);
|
return get_container(fc->profile_conf->fs_container, pos);
|
}
|
|
config_options_t *get_tg_config(ffsb_config_t * fc, int pos)
|
{
|
container_t *tmp_cont;
|
|
assert(pos < fc->num_threadgroups);
|
tmp_cont = get_container(fc->profile_conf->tg_container, pos);
|
if (tmp_cont)
|
return tmp_cont->config;
|
return NULL;
|
}
|
|
container_t *get_tg_container(ffsb_config_t * fc, int pos)
|
{
|
assert(pos < fc->num_threadgroups);
|
return get_container(fc->profile_conf->tg_container, pos);
|
}
|
|
static void init_threadgroup(ffsb_config_t * fc, config_options_t * config,
|
ffsb_tg_t * tg, int tg_num)
|
{
|
int num_threads;
|
memset(tg, 0, sizeof(ffsb_tg_t));
|
|
num_threads = get_config_u32(config, "num_threads");
|
|
init_ffsb_tg(tg, num_threads, tg_num);
|
|
if (get_config_str(config, "bindfs")) {
|
int i;
|
config_options_t *tmp_config;
|
for (i = 0; i < fc->num_filesys; i++) {
|
tmp_config = get_fs_config(fc, i);
|
if (!strcmp(get_config_str(config, "bindfs"),
|
get_config_str(tmp_config, "location")))
|
break;
|
}
|
if (strcmp(get_config_str(config, "bindfs"),
|
get_config_str(tmp_config, "location"))) {
|
printf("Bind fs failed: Base fs \"%s\" not found\n",
|
get_config_str(config, "bindfs"));
|
exit(1);
|
}
|
printf("%d\n", i);
|
tg->bindfs = i;
|
}
|
|
tg->read_random = get_config_bool(config, "read_random");
|
tg->read_size = get_config_u64(config, "read_size");
|
tg->read_skip = get_config_bool(config, "read_skip");
|
tg->read_skipsize = get_config_u32(config, "read_skipsize");
|
|
tg->write_random = get_config_bool(config, "write_random");
|
tg->write_size = get_config_u64(config, "write_size");
|
tg->fsync_file = get_config_bool(config, "fsync_file");
|
|
tg->wait_time = get_config_u32(config, "op_delay");
|
|
tg_set_read_blocksize(tg, get_config_u32(config, "read_blocksize"));
|
tg_set_write_blocksize(tg, get_config_u32(config, "write_blocksize"));
|
|
set_weight(tg, config);
|
|
if (verify_tg(tg)) {
|
printf("threadgroup %d verification failed\n", tg_num);
|
exit(1);
|
}
|
}
|
|
static void init_filesys(ffsb_config_t * fc, int num)
|
{
|
config_options_t *config = get_fs_config(fc, num);
|
profile_config_t *profile_conf = fc->profile_conf;
|
ffsb_fs_t *fs = &fc->filesystems[num];
|
value_list_t *tmp_list, *list_head;
|
|
memset(fs, 0, sizeof(ffsb_fs_t));
|
|
fs->basedir = get_config_str(config, "location");
|
|
if (get_config_str(config, "clone")) {
|
int i;
|
config_options_t *tmp_config;
|
for (i = 0; i < fc->num_filesys; i++) {
|
tmp_config = get_fs_config(fc, i);
|
if (!strcmp(get_config_str(config, "clone"),
|
get_config_str(tmp_config, "location")))
|
break;
|
}
|
if (strcmp(get_config_str(config, "clone"),
|
get_config_str(tmp_config, "location"))) {
|
printf("Clone fs failed: Base fs \"%s\" not found\n",
|
get_config_str(config, "clone"));
|
exit(1);
|
}
|
config = tmp_config;
|
}
|
|
fs->num_dirs = get_config_u32(config, "num_dirs");
|
fs->num_start_files = get_config_u32(config, "num_files");
|
fs->minfilesize = get_config_u64(config, "min_filesize");
|
fs->maxfilesize = get_config_u64(config, "max_filesize");
|
fs->desired_fsutil = get_config_double(config, "desired_util");
|
fs->init_fsutil = get_config_double(config, "init_util");
|
fs->init_size = get_config_u64(config, "init_size");
|
|
fs->flags = 0;
|
if (get_config_bool(config, "reuse"))
|
fs->flags |= FFSB_FS_REUSE_FS;
|
|
if (get_config_bool(profile_conf->global, "directio"))
|
fs->flags |= FFSB_FS_DIRECTIO | FFSB_FS_ALIGNIO4K;
|
|
if (get_config_bool(profile_conf->global, "bufferio"))
|
fs->flags |= FFSB_FS_LIBCIO;
|
|
if (get_config_bool(profile_conf->global, "alignio"))
|
fs->flags |= FFSB_FS_ALIGNIO4K;
|
|
if (get_config_bool(config, "agefs")) {
|
container_t *age_cont = get_fs_container(fc, num);
|
if (!age_cont->child) {
|
printf("No age threaggroup in profile");
|
exit(1);
|
}
|
|
age_cont = age_cont->child;
|
ffsb_tg_t *age_tg = ffsb_malloc(sizeof(ffsb_tg_t));
|
init_threadgroup(fc, age_cont->config, age_tg, 0);
|
fs->aging_tg = age_tg;
|
fs->age_fs = 1;
|
}
|
|
if (get_config_u32(config, "create_blocksize"))
|
fs->create_blocksize = get_config_u32(config,
|
"create_blocksize");
|
else
|
fs->create_blocksize = FFSB_FS_DEFAULT_CREATE_BLOCKSIZE;
|
|
if (get_config_u32(config, "age_blocksize"))
|
fs->age_blocksize = get_config_u32(config, "age_blocksize");
|
else
|
fs->age_blocksize = FFSB_FS_DEFAULT_AGE_BLOCKSIZE;
|
|
list_head = (value_list_t *) get_value(config, "size_weight");
|
if (list_head) {
|
int count = 0;
|
size_weight_t *sizew;
|
list_for_each_entry(tmp_list, &list_head->list, list)
|
count++;
|
|
fs->num_weights = count;
|
fs->size_weights =
|
malloc(sizeof(size_weight_t) * fs->num_weights);
|
|
count = 0;
|
list_for_each_entry(tmp_list, &list_head->list, list) {
|
sizew = (size_weight_t *) tmp_list->value;
|
fs->size_weights[count].size = sizew->size;
|
fs->size_weights[count].weight = sizew->weight;
|
fs->sum_weights += sizew->weight;
|
count++;
|
}
|
}
|
}
|
|
static void init_tg_stats(ffsb_config_t * fc, int num)
|
{
|
config_options_t *config;
|
container_t *tmp_cont;
|
value_list_t *tmp_list, *list_head;
|
syscall_t sys;
|
ffsb_statsc_t fsc = { 0, };
|
char *sys_name;
|
range_t *bucket_range;
|
uint32_t min, max;
|
|
tmp_cont = get_tg_container(fc, num);
|
if (tmp_cont->child) {
|
if (tmp_cont->type == STATS) {
|
config = tmp_cont->config;
|
if (get_config_bool(config, "enable_stats")) {
|
|
list_head =
|
(value_list_t *) get_value(config,
|
"ignore");
|
if (list_head)
|
list_for_each_entry(tmp_list,
|
&list_head->list,
|
list) {
|
sys_name = (char *)tmp_list->value;
|
ffsb_stats_str2syscall(sys_name, &sys);
|
ffsb_statsc_ignore_sys(&fsc, sys);
|
}
|
|
list_head =
|
(value_list_t *) get_value(config,
|
"msec_range");
|
if (list_head
|
&& get_config_bool(config, "enable_range"))
|
list_for_each_entry(tmp_list,
|
&list_head->list,
|
list) {
|
bucket_range =
|
(range_t *) tmp_list->value;
|
min =
|
(uint32_t) (bucket_range->a *
|
1000.0f);
|
max =
|
(uint32_t) (bucket_range->b *
|
1000.0f);
|
ffsb_statsc_addbucket(&fsc, min, max);
|
}
|
|
tg_set_statsc(&fc->groups[num], &fsc);
|
}
|
}
|
}
|
}
|
|
static void init_config(ffsb_config_t * fc, profile_config_t * profile_conf)
|
{
|
config_options_t *config;
|
container_t *tmp_cont;
|
int i;
|
|
fc->time = get_config_u32(profile_conf->global, "time");
|
fc->num_filesys = get_num_filesystems(profile_conf);
|
fc->num_threadgroups = get_num_threadgroups(profile_conf);
|
fc->num_totalthreads = get_num_totalthreads(profile_conf);
|
fc->profile_conf = profile_conf;
|
fc->callout = get_config_str(profile_conf->global, "callout");
|
|
fc->filesystems = ffsb_malloc(sizeof(ffsb_fs_t) * fc->num_filesys);
|
for (i = 0; i < fc->num_filesys; i++)
|
init_filesys(fc, i);
|
|
fc->groups = ffsb_malloc(sizeof(ffsb_tg_t) * fc->num_threadgroups);
|
for (i = 0; i < fc->num_threadgroups; i++) {
|
config = get_tg_config(fc, i);
|
init_threadgroup(fc, config, &fc->groups[i], i);
|
init_tg_stats(fc, i);
|
}
|
}
|
|
void ffsb_parse_newconfig(ffsb_config_t * fc, char *filename)
|
{
|
FILE *f;
|
|
profile_config_t *profile_conf;
|
|
f = fopen(filename, "r");
|
if (f == NULL) {
|
perror(filename);
|
exit(1);
|
}
|
profile_conf = parse(f);
|
fclose(f);
|
|
init_config(fc, profile_conf);
|
}
|