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 33config_options_t global_options[] = GLOBAL_OPTIONS; 34config_options_t tg_options[] = THREADGROUP_OPTIONS; 35config_options_t fs_options[] = FILESYSTEM_OPTIONS; 36config_options_t stats_options[] = STATS_OPTIONS; 37container_desc_t container_desc[] = CONTAINER_DESC; 38 39/* strips out whitespace and comments, returns NULL on eof */ 40void parseerror(char *msg) 41{ 42 fprintf(stderr, "Error parsing %s\n", msg); 43 exit(1); 44} 45 46static 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 75static 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 98static 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 118try_single: 119 memset(unit, 0, sizeof(unit)); 120 strcpy(unit, buf + (buf_size - 1)); 121 if (isdigit(unit[0])) { 122 unit[0] = 0; 123 goto out; 124 } 125 unit[0] = toupper(unit[0]); 126 127do_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 } 138out: 139 sprintf(search_str, "%%llu%s", unit); 140 if (1 == sscanf(buf, search_str, &size)) 141 return size * multiplier; 142 return 0; 143} 144 145static 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 162static 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 176static 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 195static 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 215static 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 232static 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 248static 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 265static 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 282static 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 296static 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 310static 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 320static 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 385out: 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 406void 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 413container_t *search_group(char *, FILE *); 414 415container_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 469container_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 517void *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 531char *get_config_str(config_options_t * config, char *name) 532{ 533 return get_value(config, name); 534} 535 536uint32_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 544uint8_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 552uint64_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 560double 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 568static 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 617void 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 638int 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 666static 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 721static 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 731static unsigned get_num_threadgroups(profile_config_t * profile_conf) 732{ 733 return get_num_containers(profile_conf->tg_container); 734} 735 736static unsigned get_num_filesystems(profile_config_t * profile_conf) 737{ 738 return get_num_containers(profile_conf->fs_container); 739} 740 741static 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 763container_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 775config_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 786container_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 792config_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 803container_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 809static 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 860static 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 957static 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 1011static 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 1036void 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