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