2 * Copyright (c) International Business Machines Corp., 2001-2004
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.
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.
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
27 #include "ffsb_stats.h"
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;
39 /* strips out whitespace and comments, returns NULL on eof */
40 void parseerror(char *msg)
42 fprintf(stderr, "Error parsing %s\n", msg);
46 static char *get_next_line(FILE *f)
48 static char buf[BUFSIZE];
52 ret = fgets(buf, BUFSIZE, f);
59 if ((*ret == COMMENT_CHAR) || (*ret == '\0'))
63 while (*tmp != '\0') {
64 if (*tmp == COMMENT_CHAR) {
75 static char *strip_space(char *buf)
81 len = strnlen(buf, BUFSIZE);
82 tmp = malloc(sizeof(char) * len);
83 memset(tmp, 0, sizeof(char) * len);
98 static uint64_t size64_convert(char *buf)
100 size_t buf_size = strlen(buf);
102 char search_str[256];
104 uint64_t multiplier = 1;
110 strcpy(unit, buf + (buf_size - 2));
111 for (i = 0; i < 2; i++) {
112 if (isdigit(unit[i]))
114 unit[i] = toupper(unit[i]);
119 memcpy(unit, "\0", 3);
120 strcpy(unit, buf + (buf_size - 1));
121 if (isdigit(unit[0])) {
125 unit[0] = toupper(unit[0]);
128 if (!strcmp("KB", unit) || !strcmp("K", unit))
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) {
139 sprintf(search_str, "%%llu%s", unit);
140 if (1 == sscanf(buf, search_str, &size))
141 return size * multiplier;
145 static uint64_t *get_opt64(char *buf, char string[])
147 char search_str[256];
148 char *line = strip_space(buf);
152 sprintf(search_str, "%s=%%llu\\n", string);
153 if (1 == sscanf(line, search_str, &temp)) {
154 ret = malloc(sizeof(uint64_t));
162 static uint32_t *get_opt32(char *buf, char string[])
166 res = get_opt64(buf, string);
168 ret = malloc(sizeof(uint32_t));
176 static uint8_t *get_optbool(char *buf, char string[])
180 res = get_opt64(buf, string);
182 if ((int)*res < 0 || (int)*res > 1) {
183 printf("Error in: %s", buf);
184 printf("%llu not boolean\n", (long long unsigned) *res);
187 ret = malloc(sizeof(uint8_t));
195 static char *get_optstr(char *buf, char string[])
197 char search_str[256];
198 char *line = strip_space(buf);
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);
215 static double *get_optdouble(char *buf, char string[])
217 char search_str[256];
218 char *line = strip_space(buf);
222 sprintf(search_str, "%s=%%lf\\n", string);
223 if (1 == sscanf(line, search_str, &temp)) {
224 ret = malloc(sizeof(double));
232 static range_t *get_optrange(char *buf, char string[])
234 char search_str[256];
238 sprintf(search_str, "%s %%lf %%lf\\n", string);
239 if (2 == sscanf(buf, search_str, &a, &b)) {
240 ret = malloc(sizeof(struct range));
248 static size_weight_t *get_optsizeweight(char *buf, char string[])
250 char search_str[256];
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;
265 static uint64_t * get_optsize64(char *buf, char string[])
267 char search_str[256];
268 char *line = strip_space(buf);
271 uint64_t *ret = NULL;
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);
282 static uint32_t * get_optsize32(char *buf, char string [])
286 res = get_optsize64(buf, string);
288 ret = malloc(sizeof(uint32_t));
296 static uint64_t *get_deprecated(char *buf, char string[])
298 char search_str[256];
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);
310 static container_t *init_container(void)
312 container_t *container;
313 container = malloc(sizeof(container_t));
314 container->config = NULL;
316 container->next = NULL;
320 static int set_option(char *buf, config_options_t *options)
324 while (options->name) {
325 switch (options->type) {
328 value = get_opt32(buf, options->name);
333 value = get_opt64(buf, options->name);
338 value = get_optstr(buf, options->name);
343 value = get_optbool(buf, options->name);
348 value = get_optdouble(buf, options->name);
353 value = get_optrange(buf, options->name);
357 case TYPE_SIZEWEIGHT:
358 value = get_optsizeweight(buf, options->name);
362 case TYPE_DEPRECATED:
363 value = get_deprecated(buf, options->name);
368 value = get_optsize32(buf, options->name);
373 value = get_optsize64(buf, options->name);
378 printf("Unknown type\n");
386 if (options->storage_type == STORE_SINGLE)
387 options->value = value;
388 if (options->storage_type == STORE_LIST) {
389 if (!options->value) {
391 lhead = malloc(sizeof(struct value_list));
392 INIT_LIST_HEAD(&lhead->list);
393 options->value = lhead;
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));
406 void insert_container(container_t *container, container_t *new_container)
408 while (container->next)
409 container = container->next;
410 container->next = new_container;
413 container_t *search_group(char *, FILE *);
415 container_t *handle_container(char *buf, FILE *f, uint32_t type,
416 config_options_t *options)
418 container_desc_t *desc = container_desc;
419 container_t *ret_container;
420 container_t *tmp_container, *tmp2_container;
421 container_t *child = NULL;
425 if (desc->type == type)
433 buf = get_next_line(f);
435 is_option = set_option(buf, options);
436 tmp_container = search_group(buf, f);
438 if (tmp_container->type == END) {
443 child = tmp_container;
445 tmp2_container = child;
446 while (tmp2_container->next)
447 tmp2_container = tmp2_container->next;
448 tmp2_container->next = tmp_container;
453 if (!is_option && !tmp_container) {
454 printf("ERROR!!! Unknow option: %s", buf);
457 buf = get_next_line(f);
459 ret_container = init_container();
460 ret_container->config = options;
461 ret_container->type = type;
463 ret_container->child = child;
465 return ret_container;
468 container_t *search_group(char *buf, FILE *f)
472 config_options_t *options;
473 container_desc_t *desc = container_desc;
474 container_t *ret_container;
476 if (1 == sscanf(buf, "[%s]\n", (char *) &temp))
478 ptr = strstr(buf, desc->name);
480 switch (desc->type) {
482 options = malloc(sizeof(fs_options));
483 memcpy(options, fs_options,
485 return handle_container(buf, f,
490 options = malloc(sizeof(tg_options));
491 memcpy(options, tg_options,
493 return handle_container(buf, f,
498 options = malloc(sizeof(stats_options));
499 memcpy(options, stats_options,
500 sizeof(stats_options));
501 return handle_container(buf, f,
506 ret_container = init_container();
507 ret_container->type = END;
508 return ret_container;
516 void *get_value(config_options_t *config, char *name)
518 while (config->name) {
519 if (!strcmp(config->name, name)) {
521 return config->value;
530 char *get_config_str(config_options_t *config, char *name)
532 return get_value(config, name);
535 uint32_t get_config_u32(config_options_t *config, char *name)
537 void *value = get_value(config, name);
539 return *(uint32_t *)value;
543 uint8_t get_config_bool(config_options_t *config, char *name)
545 void *value = get_value(config, name);
547 return *(uint8_t *)value;
551 uint64_t get_config_u64(config_options_t *config, char *name)
553 void *value = get_value(config, name);
555 return *(uint64_t *)value;
559 double get_config_double(config_options_t *config, char *name)
561 void *value = get_value(config, name);
563 return *(double *)value;
567 static profile_config_t *parse(FILE *f)
570 profile_config_t *profile_conf;
571 container_t *tmp_container;
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;
579 buf = get_next_line(f);
582 is_option = set_option(buf, profile_conf->global);
583 tmp_container = search_group(buf, f);
585 switch (tmp_container->type) {
587 if (profile_conf->fs_container == NULL)
588 profile_conf->fs_container = tmp_container;
590 insert_container(profile_conf->fs_container,
594 if (profile_conf->tg_container == NULL)
595 profile_conf->tg_container = tmp_container;
597 insert_container(profile_conf->tg_container,
603 if (!is_option && !tmp_container) {
604 printf("ERROR!!! Unknow option: %s", buf);
607 buf = get_next_line(f);
612 void set_weight(ffsb_tg_t *tg, config_options_t *config)
616 config_options_t *tmp_config = config;
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,
633 int get_weight_total(ffsb_tg_t *tg)
638 config_options_t *tmp_config = tg_options;
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);
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 */
661 static int verify_tg(ffsb_tg_t *tg)
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");
673 uint32_t sum_weight = get_weight_total(tg);
675 uint32_t read_blocksize = tg_get_read_blocksize(tg);
676 uint32_t write_blocksize = tg_get_write_blocksize(tg);
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);
682 if (sum_weight == 0) {
683 printf("Error: A threadgroup must have at least one weighted "
688 if ((read_weight || readall_weight) && !(read_blocksize)) {
689 printf("Error: read and readall operations require a "
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");
701 if (read_random && read_skip) {
702 printf("Error: read_random and read_skip are mutually "
707 if (read_skip && !(read_skipsize)) {
708 printf("Error: read_skip specified but read_skipsize is "
716 static unsigned get_num_containers(container_t *container)
721 container = container->next;
726 static unsigned get_num_threadgroups(profile_config_t *profile_conf)
728 return get_num_containers(profile_conf->tg_container);
731 static unsigned get_num_filesystems(profile_config_t *profile_conf)
733 return get_num_containers(profile_conf->fs_container);
736 static int get_num_totalthreads(profile_config_t *profile_conf)
739 container_t *tg = profile_conf->tg_container;
740 config_options_t *tg_config;
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;
758 container_t *get_container(container_t *head_cont, int pos)
764 head_cont = head_cont->next;
770 config_options_t *get_fs_config(ffsb_config_t *fc, int pos)
772 container_t *tmp_cont;
774 assert(pos < fc->num_filesys);
775 tmp_cont = get_container(fc->profile_conf->fs_container, pos);
777 return tmp_cont->config;
781 container_t *get_fs_container(ffsb_config_t *fc, int pos)
783 assert(pos < fc->num_filesys);
784 return get_container(fc->profile_conf->fs_container, pos);
787 config_options_t *get_tg_config(ffsb_config_t *fc, int pos)
789 container_t *tmp_cont;
791 assert(pos < fc->num_threadgroups);
792 tmp_cont = get_container(fc->profile_conf->tg_container, pos);
794 return tmp_cont->config;
798 container_t *get_tg_container(ffsb_config_t *fc, int pos)
800 assert(pos < fc->num_threadgroups);
801 return get_container(fc->profile_conf->tg_container, pos);
804 static void init_threadgroup(ffsb_config_t *fc, config_options_t *config,
805 ffsb_tg_t *tg, int tg_num)
808 memset(tg, 0, sizeof(ffsb_tg_t));
810 num_threads = get_config_u32(config, "num_threads");
812 init_ffsb_tg(tg, num_threads, tg_num);
814 if (get_config_str(config, "bindfs")) {
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")))
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"));
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");
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");
842 tg->wait_time = get_config_u32(config, "op_delay");
844 tg_set_read_blocksize(tg, get_config_u32(config, "read_blocksize"));
845 tg_set_write_blocksize(tg, get_config_u32(config, "write_blocksize"));
847 set_weight(tg, config);
850 printf("threadgroup %d verification failed\n", tg_num);
855 static void init_filesys(ffsb_config_t *fc, int num)
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;
862 memset(fs, 0, sizeof(ffsb_fs_t));
864 fs->basedir = get_config_str(config, "location");
866 if (get_config_str(config, "clone")) {
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")))
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"));
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");
893 if (get_config_bool(config, "reuse"))
894 fs->flags |= FFSB_FS_REUSE_FS;
896 if (get_config_bool(profile_conf->global, "directio"))
897 fs->flags |= FFSB_FS_DIRECTIO | FFSB_FS_ALIGNIO4K;
899 if (get_config_bool(profile_conf->global, "bufferio"))
900 fs->flags |= FFSB_FS_LIBCIO;
902 if (get_config_bool(profile_conf->global, "alignio"))
903 fs->flags |= FFSB_FS_ALIGNIO4K;
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");
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;
919 if (get_config_u32(config, "create_blocksize"))
920 fs->create_blocksize = get_config_u32(config,
923 fs->create_blocksize = FFSB_FS_DEFAULT_CREATE_BLOCKSIZE;
925 if (get_config_u32(config, "age_blocksize"))
926 fs->age_blocksize = get_config_u32(config, "age_blocksize");
928 fs->age_blocksize = FFSB_FS_DEFAULT_AGE_BLOCKSIZE;
930 list_head = (value_list_t *) get_value(config, "size_weight");
933 size_weight_t *sizew;
934 list_for_each_entry(tmp_list, &list_head->list, list)
937 fs->num_weights=count;
938 fs->size_weights = malloc(sizeof(size_weight_t) * fs->num_weights);
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;
951 static void init_tg_stats(ffsb_config_t *fc, int num)
953 config_options_t *config;
954 container_t *tmp_cont;
955 value_list_t *tmp_list, *list_head;
957 ffsb_statsc_t fsc = { 0, };
959 range_t *bucket_range;
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")) {
969 list_head = (value_list_t *) get_value(config, "ignore");
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);
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);
988 tg_set_statsc(&fc->groups[num], &fsc);
994 static void init_config(ffsb_config_t *fc, profile_config_t *profile_conf)
996 config_options_t *config;
997 container_t *tmp_cont;
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");
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);
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);
1019 void ffsb_parse_newconfig(ffsb_config_t *fc, char *filename)
1023 profile_config_t *profile_conf;
1025 f = fopen(filename, "r");
1030 profile_conf = parse(f);
1033 init_config(fc, profile_conf);