Merge pull request #3 from lxbsz/wip-52438
[ffsb.git] / parser.c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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         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
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, 4095) + 1;
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 = tmp2_container->next;
448                                         tmp2_container->next = tmp_container;
449                                 }
450
451                         }
452                 }
453                 if (!is_option && !tmp_container) {
454                         printf("ERROR!!! Unknow option: %s", buf);
455                         exit(1);
456                 }
457                 buf = get_next_line(f);
458         }
459         ret_container = init_container();
460         ret_container->config = options;
461         ret_container->type = type;
462         if (child)
463                 ret_container->child = child;
464
465         return ret_container;
466 }
467
468 container_t *search_group(char *buf, FILE *f)
469 {
470         char temp[BUFSIZE];
471         char *ptr;
472         config_options_t *options;
473         container_desc_t *desc = container_desc;
474         container_t *ret_container;
475
476         if (1 == sscanf(buf, "[%s]\n", (char *) &temp))
477                 while (desc->name) {
478                         ptr = strstr(buf, desc->name);
479                         if (ptr)
480                                 switch (desc->type) {
481                                 case FILESYSTEM:
482                                         options = malloc(sizeof(fs_options));
483                                         memcpy(options, fs_options,
484                                                sizeof(fs_options));
485                                         return handle_container(buf, f,
486                                                                 desc->type,
487                                                                 options);
488                                         break;
489                                 case THREAD_GROUP:
490                                         options = malloc(sizeof(tg_options));
491                                         memcpy(options, tg_options,
492                                                sizeof(tg_options));
493                                         return handle_container(buf, f,
494                                                                 desc->type,
495                                                                 options);
496                                         break;
497                                 case STATS:
498                                         options = malloc(sizeof(stats_options));
499                                         memcpy(options, stats_options,
500                                                sizeof(stats_options));
501                                         return handle_container(buf, f,
502                                                                 desc->type,
503                                                                 options);
504                                         break;
505                                 case END:
506                                         ret_container = init_container();
507                                         ret_container->type = END;
508                                         return ret_container;
509                                         break;
510                                 }
511                         desc++;
512                 }
513         return NULL;
514 }
515
516 void *get_value(config_options_t *config, char *name)
517 {
518         while (config->name) {
519                 if (!strcmp(config->name, name)) {
520                         if (config->value)
521                                 return config->value;
522                         else
523                                 return NULL;
524                 }
525                 config++;
526         }
527         return 0;
528 }
529
530 char *get_config_str(config_options_t *config, char *name)
531 {
532         return get_value(config, name);
533 }
534
535 uint32_t get_config_u32(config_options_t *config, char *name)
536 {
537         void *value = get_value(config, name);
538         if (value)
539                 return *(uint32_t *)value;
540         return 0;
541 }
542
543 uint8_t get_config_bool(config_options_t *config, char *name)
544 {
545         void *value = get_value(config, name);
546         if (value)
547                 return *(uint8_t *)value;
548         return 0;
549 }
550
551 uint64_t get_config_u64(config_options_t *config, char *name)
552 {
553         void *value = get_value(config, name);
554         if (value)
555                 return *(uint64_t *)value;
556         return 0;
557 }
558
559 double get_config_double(config_options_t *config, char *name)
560 {
561         void *value = get_value(config, name);
562         if (value)
563                 return *(double *)value;
564         return 0;
565 }
566
567 static profile_config_t *parse(FILE *f)
568 {
569         char *buf;
570         profile_config_t *profile_conf;
571         container_t *tmp_container;
572
573         profile_conf = malloc(sizeof(profile_config_t));
574         profile_conf->global = malloc(sizeof(global_options));
575         memcpy(profile_conf->global, global_options, sizeof(global_options));
576         profile_conf->fs_container = NULL;
577         profile_conf->tg_container = NULL;
578         int is_option;
579         buf = get_next_line(f);
580
581         while (buf) {
582                 is_option = set_option(buf, profile_conf->global);
583                 tmp_container = search_group(buf, f);
584                 if (tmp_container)
585                         switch (tmp_container->type) {
586                         case FILESYSTEM:
587                                 if (profile_conf->fs_container == NULL)
588                                         profile_conf->fs_container = tmp_container;
589                                 else
590                                         insert_container(profile_conf->fs_container,
591                                                          tmp_container);
592                                 break;
593                         case THREAD_GROUP:
594                                 if (profile_conf->tg_container == NULL)
595                                         profile_conf->tg_container = tmp_container;
596                                 else
597                                         insert_container(profile_conf->tg_container,
598                                                          tmp_container);
599                                 break;
600                         default:
601                                 break;
602                         }
603                 if (!is_option && !tmp_container) {
604                         printf("ERROR!!! Unknow option: %s", buf);
605                         exit(1);
606                 }
607                 buf = get_next_line(f);
608         }
609         return profile_conf;
610 }
611
612 void set_weight(ffsb_tg_t *tg, config_options_t *config)
613 {
614         char *op;
615         int len;
616         config_options_t *tmp_config = config;
617
618         while (tmp_config->name) {
619                 if (tmp_config->type == TYPE_WEIGHT) {
620                         len = strlen(tmp_config->name);
621                         op = malloc(sizeof(char) * len - 6);
622                         memset(op, 0, sizeof(char) * len - 6);
623                         strncpy (op, tmp_config->name, len - 7);
624                         tg_set_op_weight(tg, op,
625                                          get_config_u32(config,
626                                                         tmp_config->name));
627                         free(op);
628                 }
629                 tmp_config++;
630         }
631 }
632
633 int get_weight_total(ffsb_tg_t *tg)
634 {
635         char *op;
636         int len;
637         int total = 0;
638         config_options_t *tmp_config = tg_options;
639
640         while (tmp_config->name) {
641                 if (tmp_config->type == TYPE_WEIGHT) {
642                         len = strlen(tmp_config->name);
643                         op = malloc(sizeof(char) * len - 6);
644                         memset(op, 0, sizeof(char) * len - 6);
645                         strncpy (op, tmp_config->name, len - 7);
646                         total += tg_get_op_weight(tg, op);
647                         free(op);
648                 }
649                 tmp_config++;
650         }
651         return total;
652 }
653
654 /* !!! hackish verification function, we should somehow roll this into the */
655 /* op descriptions/struct themselves at some point with a callback verify */
656 /* op requirements: */
657 /* require tg->read_blocksize:  read, readall */
658 /* require tg->write_blocksize: write, create, append, rewritefsync */
659 /* */
660
661 static int verify_tg(ffsb_tg_t *tg)
662 {
663         uint32_t read_weight    = tg_get_op_weight(tg, "read");
664         uint32_t readall_weight = tg_get_op_weight(tg, "readall");
665         uint32_t write_weight   = tg_get_op_weight(tg, "write");
666         uint32_t create_weight  = tg_get_op_weight(tg, "create");
667         uint32_t append_weight  = tg_get_op_weight(tg, "append");
668         uint32_t createdir_weight = tg_get_op_weight(tg, "createdir");
669         uint32_t delete_weight    = tg_get_op_weight(tg, "delete");
670         uint32_t writeall_weight = tg_get_op_weight(tg, "writeall");
671         uint32_t writeall_fsync_weight = tg_get_op_weight(tg, "writeall_fsync");
672
673         uint32_t sum_weight = get_weight_total(tg);
674         
675         uint32_t read_blocksize  = tg_get_read_blocksize(tg);
676         uint32_t write_blocksize = tg_get_write_blocksize(tg);
677
678         int read_random          = tg_get_read_random(tg);
679         int read_skip            = tg_get_read_skip(tg);
680         uint32_t read_skipsize   = tg_get_read_skipsize(tg);
681
682         if (sum_weight == 0) {
683                 printf("Error: A threadgroup must have at least one weighted "
684                        "operation\n");
685                 return 1;
686         }
687
688         if ((read_weight || readall_weight) && !(read_blocksize)) {
689                 printf("Error: read and readall operations require a "
690                        "read_blocksize\n");
691                 return 1;
692         }
693
694         if ((write_weight || create_weight || append_weight || writeall_weight 
695              || writeall_fsync_weight) && !(write_blocksize)) {
696                 printf("Error: write, writeall, create, append"
697                        "operations require a write_blocksize\n");
698                 return 1;
699         }
700
701         if (read_random && read_skip) {
702                 printf("Error: read_random and read_skip are mutually "
703                        "exclusive\n");
704                 return 1;
705         }
706
707         if (read_skip && !(read_skipsize)) {
708                 printf("Error: read_skip specified but read_skipsize is "
709                        "zero\n");
710                 return 1;
711         }
712
713         return 0;
714 }
715
716 static unsigned get_num_containers(container_t *container)
717 {
718         int numtg = 0;
719         while (container) {
720                 numtg++;
721                 container = container->next;
722         }
723         return numtg;
724 }
725
726 static unsigned get_num_threadgroups(profile_config_t *profile_conf)
727 {
728         return get_num_containers(profile_conf->tg_container);
729 }
730
731 static unsigned get_num_filesystems(profile_config_t *profile_conf)
732 {
733         return get_num_containers(profile_conf->fs_container);
734 }
735
736 static int get_num_totalthreads(profile_config_t *profile_conf)
737 {
738         int num_threads = 0;
739         container_t *tg = profile_conf->tg_container;
740         config_options_t *tg_config;
741
742         while (tg) {
743                 tg_config = tg->config;
744                 while (tg_config->name) {
745                         if (!strcmp(tg_config->name, "num_threads"))
746                                 num_threads += *(uint32_t *) tg_config->value;
747                         tg_config++;
748                 }
749                 if (tg->next)
750                         tg = tg->next;
751                 else
752                         break;
753         }
754
755         return num_threads;
756 }
757
758 container_t *get_container(container_t *head_cont, int pos)
759 {
760         int count = 0;
761         while (head_cont) {
762                 if (count == pos)
763                         return head_cont;
764                 head_cont = head_cont->next;
765                 count++;
766         }
767         return NULL;
768 }
769
770 config_options_t *get_fs_config(ffsb_config_t *fc, int pos)
771 {
772         container_t *tmp_cont;
773
774         assert(pos < fc->num_filesys);
775         tmp_cont = get_container(fc->profile_conf->fs_container, pos);
776         if (tmp_cont)
777                 return tmp_cont->config;
778         return NULL;
779 }
780
781 container_t *get_fs_container(ffsb_config_t *fc, int pos)
782 {
783         assert(pos < fc->num_filesys);
784         return get_container(fc->profile_conf->fs_container, pos);
785 }
786
787 config_options_t *get_tg_config(ffsb_config_t *fc, int pos)
788 {
789         container_t *tmp_cont;
790
791         assert(pos < fc->num_threadgroups);
792         tmp_cont = get_container(fc->profile_conf->tg_container, pos);
793         if (tmp_cont)
794                 return tmp_cont->config;
795         return NULL;
796 }
797
798 container_t *get_tg_container(ffsb_config_t *fc, int pos)
799 {
800         assert(pos < fc->num_threadgroups);
801         return get_container(fc->profile_conf->tg_container, pos);
802 }
803
804 static void init_threadgroup(ffsb_config_t *fc, config_options_t *config,
805                             ffsb_tg_t *tg, int tg_num)
806 {
807         int num_threads;
808         memset(tg, 0, sizeof(ffsb_tg_t));
809
810         num_threads = get_config_u32(config, "num_threads");
811
812         init_ffsb_tg(tg, num_threads, tg_num);
813
814         if (get_config_str(config, "bindfs")) {
815                 int i;
816                 config_options_t *tmp_config;
817                 for (i = 0; i < fc->num_filesys; i++) {
818                         tmp_config = get_fs_config(fc, i);
819                         if (!strcmp(get_config_str(config, "bindfs"),
820                                     get_config_str(tmp_config, "location")))
821                                 break;
822                 }
823                 if (strcmp(get_config_str(config, "bindfs"),
824                            get_config_str(tmp_config, "location"))) {
825                         printf ("Bind fs failed:  Base fs \"%s\" not found\n",
826                                 get_config_str(config, "bindfs"));
827                         exit(1);
828                 }
829                 printf("%d\n", i);
830                 tg->bindfs = i;
831         }
832
833         tg->read_random = get_config_bool(config, "read_random");
834         tg->read_size = get_config_u64(config, "read_size");
835         tg->read_skip = get_config_bool(config, "read_skip");
836         tg->read_skipsize = get_config_u32(config, "read_skipsize");
837
838         tg->write_random = get_config_bool(config, "write_random");
839         tg->write_size = get_config_u64(config, "write_size");
840         tg->fsync_file = get_config_bool(config, "fsync_file");
841
842         tg->wait_time = get_config_u32(config, "op_delay");
843
844         tg_set_read_blocksize(tg, get_config_u32(config, "read_blocksize"));
845         tg_set_write_blocksize(tg, get_config_u32(config, "write_blocksize"));
846
847         set_weight(tg, config);
848
849         if (verify_tg(tg)) {
850                 printf("threadgroup %d verification failed\n", tg_num);
851                 exit(1);
852         }
853 }
854
855 static void init_filesys(ffsb_config_t *fc, int num)
856 {
857         config_options_t *config = get_fs_config(fc, num);
858         profile_config_t *profile_conf = fc->profile_conf;
859         ffsb_fs_t *fs = &fc->filesystems[num];
860         value_list_t *tmp_list, *list_head;
861
862         memset(fs, 0, sizeof(ffsb_fs_t));
863
864         fs->basedir = get_config_str(config, "location");
865
866         if (get_config_str(config, "clone")) {
867                 int i;
868                 config_options_t *tmp_config;
869                 for (i = 0; i < fc->num_filesys; i++) {
870                         tmp_config = get_fs_config(fc, i);
871                         if (!strcmp(get_config_str(config, "clone"),
872                                     get_config_str(tmp_config, "location")))
873                                 break;
874                 }
875                 if (strcmp(get_config_str(config, "clone"),
876                            get_config_str(tmp_config, "location"))) {
877                         printf ("Clone fs failed:  Base fs \"%s\" not found\n",
878                                 get_config_str(config, "clone"));
879                         exit(1);
880                 }
881                 config = tmp_config;
882         }
883
884         fs->num_dirs = get_config_u32(config, "num_dirs");
885         fs->num_start_files = get_config_u32(config, "num_files");
886         fs->minfilesize = get_config_u64(config, "min_filesize");
887         fs->maxfilesize = get_config_u64(config, "max_filesize");
888         fs->desired_fsutil = get_config_double(config, "desired_util");
889         fs->init_fsutil = get_config_double(config, "init_util");
890         fs->init_size = get_config_u64(config, "init_size");
891
892         fs->flags = 0;
893         if (get_config_bool(config, "reuse"))
894                 fs->flags |= FFSB_FS_REUSE_FS;
895
896         if (get_config_bool(profile_conf->global, "directio"))
897                 fs->flags |= FFSB_FS_DIRECTIO | FFSB_FS_ALIGNIO4K;
898
899         if (get_config_bool(profile_conf->global, "bufferio"))
900                 fs->flags |= FFSB_FS_LIBCIO;
901
902         if (get_config_bool(profile_conf->global, "alignio"))
903                 fs->flags |= FFSB_FS_ALIGNIO4K;
904
905         if (get_config_bool(config, "agefs")) {
906                 container_t *age_cont = get_fs_container(fc, num);
907                 if (!age_cont->child) {
908                         printf("No age threaggroup in profile");
909                         exit(1);
910                 }
911
912                 age_cont = age_cont->child;
913                 ffsb_tg_t *age_tg = ffsb_malloc(sizeof(ffsb_tg_t));
914                 init_threadgroup(fc, age_cont->config, age_tg, 0);
915                 fs->aging_tg = age_tg;
916                 fs->age_fs = 1;
917         }
918
919         if (get_config_u32(config, "create_blocksize"))
920                 fs->create_blocksize = get_config_u32(config,
921                                                         "create_blocksize");
922         else
923                 fs->create_blocksize = FFSB_FS_DEFAULT_CREATE_BLOCKSIZE;
924
925         if (get_config_u32(config, "age_blocksize"))
926                 fs->age_blocksize = get_config_u32(config, "age_blocksize");
927         else
928                 fs->age_blocksize = FFSB_FS_DEFAULT_AGE_BLOCKSIZE;
929
930         list_head = (value_list_t *) get_value(config, "size_weight");
931         if (list_head) {
932                 int count = 0;
933                 size_weight_t *sizew;
934                 list_for_each_entry(tmp_list, &list_head->list, list)
935                         count++;
936
937                 fs->num_weights=count;
938                 fs->size_weights = malloc(sizeof(size_weight_t) * fs->num_weights);
939
940                 count = 0;
941                 list_for_each_entry(tmp_list, &list_head->list, list) {
942                         sizew = (size_weight_t *)tmp_list->value;
943                         fs->size_weights[count].size = sizew->size;
944                         fs->size_weights[count].weight = sizew->weight;
945                         fs->sum_weights += sizew->weight;
946                         count++;
947                 }
948         }
949 }
950
951 static void init_tg_stats(ffsb_config_t *fc, int num)
952 {
953         config_options_t *config;
954         container_t *tmp_cont;
955         value_list_t *tmp_list, *list_head;
956         syscall_t sys;
957         ffsb_statsc_t fsc = { 0, };
958         char *sys_name;
959         range_t *bucket_range;
960         uint32_t min, max;
961
962         tmp_cont = get_tg_container(fc, num);
963         if (tmp_cont->child) {
964                 tmp_cont = tmp_cont->child;
965                 if (tmp_cont->type == STATS) {
966                         config = tmp_cont->config;
967                         if (get_config_bool(config, "enable_stats")) {
968
969                                 list_head = (value_list_t *) get_value(config, "ignore");
970                                 if (list_head)
971                                         list_for_each_entry(tmp_list,
972                                                             &list_head->list, list) {
973                                                 sys_name = (char *)tmp_list->value;
974                                                 ffsb_stats_str2syscall(sys_name, &sys);
975                                                 ffsb_statsc_ignore_sys(&fsc, sys);
976                                         }
977
978                                 list_head = (value_list_t *) get_value(config, "msec_range");
979                                 if (list_head && get_config_bool(config, "enable_range"))
980                                         list_for_each_entry(tmp_list,
981                                                             &list_head->list, list) {
982                                                 bucket_range = (range_t *)tmp_list->value;
983                                                 min = (uint32_t)(bucket_range->a * 1000.0f);
984                                                 max = (uint32_t)(bucket_range->b * 1000.0f);
985                                                 ffsb_statsc_addbucket(&fsc, min, max);
986                                         }
987
988                                 tg_set_statsc(&fc->groups[num], &fsc);
989                         }
990                 }
991         }
992 }
993
994 static void init_config(ffsb_config_t *fc, profile_config_t *profile_conf)
995 {
996         config_options_t *config;
997         container_t *tmp_cont;
998         int i;
999
1000         fc->time = get_config_u32(profile_conf->global, "time");
1001         fc->num_filesys = get_num_filesystems(profile_conf);
1002         fc->num_threadgroups = get_num_threadgroups(profile_conf);
1003         fc->num_totalthreads = get_num_totalthreads(profile_conf);
1004         fc->profile_conf = profile_conf;
1005         fc->callout = get_config_str(profile_conf->global, "callout");
1006
1007         fc->filesystems = ffsb_malloc(sizeof(ffsb_fs_t) * fc->num_filesys);
1008         for (i = 0; i < fc->num_filesys; i++)
1009                 init_filesys(fc, i);
1010
1011         fc->groups = ffsb_malloc(sizeof(ffsb_tg_t) * fc->num_threadgroups);
1012         for (i = 0; i < fc->num_threadgroups; i++) {
1013                 config = get_tg_config(fc, i);
1014                 init_threadgroup(fc, config, &fc->groups[i], i);
1015                 init_tg_stats(fc, i);
1016         }
1017 }
1018
1019 void ffsb_parse_newconfig(ffsb_config_t *fc, char *filename)
1020 {
1021         FILE *f;
1022
1023         profile_config_t *profile_conf;
1024
1025         f = fopen(filename, "r");
1026         if (f == NULL) {
1027                 perror(filename);
1028                 exit(1);
1029         }
1030         profile_conf = parse(f);
1031         fclose(f);
1032
1033         init_config(fc, profile_conf);
1034 }