init.c revision 2e77841b9bc7f99ffd1caa2c2c84af2a66731658
1/* 2 * This file contains the ini and command liner parser. It will create 3 * and initialize the specified jobs. 4 */ 5#include <stdio.h> 6#include <stdlib.h> 7#include <unistd.h> 8#include <fcntl.h> 9#include <ctype.h> 10#include <string.h> 11#include <errno.h> 12#include <sys/ipc.h> 13#include <sys/shm.h> 14#include <sys/types.h> 15#include <sys/stat.h> 16 17#include "fio.h" 18 19/* 20 * The default options 21 */ 22#define DEF_BS (4096) 23#define DEF_TIMEOUT (0) 24#define DEF_RATE_CYCLE (1000) 25#define DEF_ODIRECT (1) 26#define DEF_IO_ENGINE (FIO_SYNCIO) 27#define DEF_IO_ENGINE_NAME "sync" 28#define DEF_SEQUENTIAL (1) 29#define DEF_RAND_REPEAT (1) 30#define DEF_OVERWRITE (1) 31#define DEF_CREATE (1) 32#define DEF_INVALIDATE (1) 33#define DEF_SYNCIO (0) 34#define DEF_RANDSEED (0xb1899bedUL) 35#define DEF_BWAVGTIME (500) 36#define DEF_CREATE_SER (1) 37#define DEF_CREATE_FSYNC (1) 38#define DEF_LOOPS (1) 39#define DEF_VERIFY (0) 40#define DEF_STONEWALL (0) 41#define DEF_NUMJOBS (1) 42#define DEF_USE_THREAD (0) 43#define DEF_FILE_SIZE (1024 * 1024 * 1024UL) 44#define DEF_ZONE_SIZE (0) 45#define DEF_ZONE_SKIP (0) 46#define DEF_RWMIX_CYCLE (500) 47#define DEF_RWMIX_READ (50) 48#define DEF_NICE (0) 49 50static int def_timeout = DEF_TIMEOUT; 51 52static char fio_version_string[] = "fio 1.5"; 53 54static char **ini_file; 55static int max_jobs = MAX_JOBS; 56 57struct thread_data def_thread; 58struct thread_data *threads = NULL; 59 60int rate_quit = 0; 61int write_lat_log = 0; 62int write_bw_log = 0; 63int exitall_on_terminate = 0; 64int terse_output = 0; 65unsigned long long mlock_size = 0; 66FILE *f_out = NULL; 67FILE *f_err = NULL; 68 69/* 70 * Return a free job structure. 71 */ 72static struct thread_data *get_new_job(int global, struct thread_data *parent) 73{ 74 struct thread_data *td; 75 76 if (global) 77 return &def_thread; 78 if (thread_number >= max_jobs) 79 return NULL; 80 81 td = &threads[thread_number++]; 82 *td = *parent; 83 td->name[0] = '\0'; 84 85 td->fd = -1; 86 td->thread_number = thread_number; 87 return td; 88} 89 90static void put_job(struct thread_data *td) 91{ 92 memset(&threads[td->thread_number - 1], 0, sizeof(*td)); 93 thread_number--; 94} 95 96/* 97 * Adds a job to the list of things todo. Sanitizes the various options 98 * to make sure we don't have conflicts, and initializes various 99 * members of td. 100 */ 101static int add_job(struct thread_data *td, const char *jobname, int job_add_num) 102{ 103 char *ddir_str[] = { "read", "write", "randread", "randwrite", 104 "rw", NULL, "randrw" }; 105 struct stat sb; 106 int numjobs, ddir; 107 108#ifndef FIO_HAVE_LIBAIO 109 if (td->io_engine == FIO_LIBAIO) { 110 log_err("Linux libaio not available\n"); 111 return 1; 112 } 113#endif 114#ifndef FIO_HAVE_POSIXAIO 115 if (td->io_engine == FIO_POSIXAIO) { 116 log_err("posix aio not available\n"); 117 return 1; 118 } 119#endif 120 121 /* 122 * the def_thread is just for options, it's not a real job 123 */ 124 if (td == &def_thread) 125 return 0; 126 127 if (td->io_engine & FIO_SYNCIO) 128 td->iodepth = 1; 129 else { 130 if (!td->iodepth) 131 td->iodepth = 1; 132 } 133 134 /* 135 * only really works for sequential io for now 136 */ 137 if (td->zone_size && !td->sequential) 138 td->zone_size = 0; 139 140 /* 141 * Reads can do overwrites, we always need to pre-create the file 142 */ 143 if (td_read(td) || td_rw(td)) 144 td->overwrite = 1; 145 146 td->filetype = FIO_TYPE_FILE; 147 if (!stat(jobname, &sb)) { 148 if (S_ISBLK(sb.st_mode)) 149 td->filetype = FIO_TYPE_BD; 150 else if (S_ISCHR(sb.st_mode)) 151 td->filetype = FIO_TYPE_CHAR; 152 } 153 154 if (td->filetype == FIO_TYPE_FILE) { 155 char tmp[PATH_MAX]; 156 157 if (td->directory && td->directory[0] != '\0') 158 sprintf(tmp, "%s/%s.%d", td->directory, jobname, td->thread_number); 159 else 160 sprintf(tmp, "%s.%d", jobname, td->thread_number); 161 td->file_name = strdup(tmp); 162 } else 163 td->file_name = strdup(jobname); 164 165 fio_sem_init(&td->mutex, 0); 166 167 td->clat_stat[0].min_val = td->clat_stat[1].min_val = ULONG_MAX; 168 td->slat_stat[0].min_val = td->slat_stat[1].min_val = ULONG_MAX; 169 td->bw_stat[0].min_val = td->bw_stat[1].min_val = ULONG_MAX; 170 171 if (td->min_bs == -1U) 172 td->min_bs = td->bs; 173 if (td->max_bs == -1U) 174 td->max_bs = td->bs; 175 if (td_read(td) && !td_rw(td)) 176 td->verify = 0; 177 178 if (td->stonewall && td->thread_number > 1) 179 groupid++; 180 181 td->groupid = groupid; 182 183 if (setup_rate(td)) 184 goto err; 185 186 if (write_lat_log) { 187 setup_log(&td->slat_log); 188 setup_log(&td->clat_log); 189 } 190 if (write_bw_log) 191 setup_log(&td->bw_log); 192 193 if (td->name[0] == '\0') 194 snprintf(td->name, sizeof(td->name)-1, "client%d", td->thread_number); 195 196 ddir = td->ddir + (!td->sequential << 1) + (td->iomix << 2); 197 198 if (!terse_output) { 199 if (!job_add_num) 200 fprintf(f_out, "%s: (g=%d): rw=%s, odir=%d, bs=%d-%d, rate=%d, ioengine=%s, iodepth=%d\n", td->name, td->groupid, ddir_str[ddir], td->odirect, td->min_bs, td->max_bs, td->rate, td->io_engine_name, td->iodepth); 201 else if (job_add_num == 1) 202 fprintf(f_out, "...\n"); 203 } 204 205 /* 206 * recurse add identical jobs, clear numjobs and stonewall options 207 * as they don't apply to sub-jobs 208 */ 209 numjobs = td->numjobs; 210 while (--numjobs) { 211 struct thread_data *td_new = get_new_job(0, td); 212 213 if (!td_new) 214 goto err; 215 216 td_new->numjobs = 1; 217 td_new->stonewall = 0; 218 job_add_num = numjobs - 1; 219 220 if (add_job(td_new, jobname, job_add_num)) 221 goto err; 222 } 223 return 0; 224err: 225 put_job(td); 226 return -1; 227} 228 229/* 230 * Initialize the various random states we need (random io, block size ranges, 231 * read/write mix, etc). 232 */ 233int init_random_state(struct thread_data *td) 234{ 235 unsigned long seeds[4]; 236 int fd, num_maps, blocks; 237 238 fd = open("/dev/urandom", O_RDONLY); 239 if (fd == -1) { 240 td_verror(td, errno); 241 return 1; 242 } 243 244 if (read(fd, seeds, sizeof(seeds)) < (int) sizeof(seeds)) { 245 td_verror(td, EIO); 246 close(fd); 247 return 1; 248 } 249 250 close(fd); 251 252 os_random_seed(seeds[0], &td->bsrange_state); 253 os_random_seed(seeds[1], &td->verify_state); 254 os_random_seed(seeds[2], &td->rwmix_state); 255 256 if (td->sequential) 257 return 0; 258 259 if (td->rand_repeatable) 260 seeds[3] = DEF_RANDSEED; 261 262 blocks = (td->io_size + td->min_bs - 1) / td->min_bs; 263 num_maps = blocks / BLOCKS_PER_MAP; 264 td->file_map = malloc(num_maps * sizeof(long)); 265 td->num_maps = num_maps; 266 memset(td->file_map, 0, num_maps * sizeof(long)); 267 268 os_random_seed(seeds[3], &td->random_state); 269 return 0; 270} 271 272static void fill_cpu_mask(os_cpu_mask_t cpumask, int cpu) 273{ 274#ifdef FIO_HAVE_CPU_AFFINITY 275 unsigned int i; 276 277 CPU_ZERO(&cpumask); 278 279 for (i = 0; i < sizeof(int) * 8; i++) { 280 if ((1 << i) & cpu) 281 CPU_SET(i, &cpumask); 282 } 283#endif 284} 285 286static unsigned long get_mult_time(char c) 287{ 288 switch (c) { 289 case 'm': 290 case 'M': 291 return 60; 292 case 'h': 293 case 'H': 294 return 60 * 60; 295 case 'd': 296 case 'D': 297 return 24 * 60 * 60; 298 default: 299 return 1; 300 } 301} 302 303static unsigned long get_mult_bytes(char c) 304{ 305 switch (c) { 306 case 'k': 307 case 'K': 308 return 1024; 309 case 'm': 310 case 'M': 311 return 1024 * 1024; 312 case 'g': 313 case 'G': 314 return 1024 * 1024 * 1024; 315 default: 316 return 1; 317 } 318} 319 320/* 321 * convert string after '=' into decimal value, noting any size suffix 322 */ 323static int str_to_decimal(char *p, unsigned long long *val, int kilo) 324{ 325 char *str; 326 int len; 327 328 str = strchr(p, '='); 329 if (!str) 330 return 1; 331 332 str++; 333 len = strlen(str); 334 335 *val = strtoul(str, NULL, 10); 336 if (*val == ULONG_MAX && errno == ERANGE) 337 return 1; 338 339 if (kilo) 340 *val *= get_mult_bytes(str[len - 1]); 341 else 342 *val *= get_mult_time(str[len - 1]); 343 return 0; 344} 345 346static int check_str_bytes(char *p, char *name, unsigned long long *val) 347{ 348 if (strncmp(p, name, strlen(name) - 1)) 349 return 1; 350 351 return str_to_decimal(p, val, 1); 352} 353 354static int check_str_time(char *p, char *name, unsigned long long *val) 355{ 356 if (strncmp(p, name, strlen(name) - 1)) 357 return 1; 358 359 return str_to_decimal(p, val, 0); 360} 361 362static void strip_blank_front(char **p) 363{ 364 char *s = *p; 365 366 while (isspace(*s)) 367 s++; 368} 369 370static void strip_blank_end(char *p) 371{ 372 char *s = p + strlen(p) - 1; 373 374 while (isspace(*s) || iscntrl(*s)) 375 s--; 376 377 *(s + 1) = '\0'; 378} 379 380typedef int (str_cb_fn)(struct thread_data *, char *); 381 382static int check_str(char *p, char *name, str_cb_fn *cb, struct thread_data *td) 383{ 384 char *s; 385 386 if (strncmp(p, name, strlen(name))) 387 return 1; 388 389 s = strstr(p, name); 390 if (!s) 391 return 1; 392 393 s = strchr(s, '='); 394 if (!s) 395 return 1; 396 397 s++; 398 strip_blank_front(&s); 399 return cb(td, s); 400} 401 402static int check_strstore(char *p, char *name, char *dest) 403{ 404 char *s; 405 406 if (strncmp(p, name, strlen(name))) 407 return 1; 408 409 s = strstr(p, name); 410 if (!s) 411 return 1; 412 413 s = strchr(p, '='); 414 if (!s) 415 return 1; 416 417 s++; 418 strip_blank_front(&s); 419 420 strcpy(dest, s); 421 return 0; 422} 423 424static int __check_range_bytes(char *str, unsigned long *val) 425{ 426 char suffix; 427 428 if (sscanf(str, "%lu%c", val, &suffix) == 2) { 429 *val *= get_mult_bytes(suffix); 430 return 0; 431 } 432 433 if (sscanf(str, "%lu", val) == 1) 434 return 0; 435 436 return 1; 437} 438 439static int check_range_bytes(char *p, char *name, unsigned long *s, 440 unsigned long *e) 441{ 442 char option[128]; 443 char *str, *p1, *p2; 444 445 if (strncmp(p, name, strlen(name))) 446 return 1; 447 448 strcpy(option, p); 449 p = option; 450 451 str = strstr(p, name); 452 if (!str) 453 return 1; 454 455 p += strlen(name); 456 457 str = strchr(p, '='); 458 if (!str) 459 return 1; 460 461 /* 462 * 'p' now holds whatever is after the '=' sign 463 */ 464 p1 = str + 1; 465 466 /* 467 * terminate p1 at the '-' sign 468 */ 469 p = strchr(p1, '-'); 470 if (!p) 471 return 1; 472 473 p2 = p + 1; 474 *p = '\0'; 475 476 if (!__check_range_bytes(p1, s) && !__check_range_bytes(p2, e)) 477 return 0; 478 479 return 1; 480} 481 482static int check_int(char *p, char *name, unsigned int *val) 483{ 484 char *str; 485 486 if (strncmp(p, name, strlen(name))) 487 return 1; 488 489 str = strstr(p, name); 490 if (!str) 491 return 1; 492 493 str = strchr(p, '='); 494 if (!str) 495 return 1; 496 497 str++; 498 499 if (sscanf(str, "%u", val) == 1) 500 return 0; 501 502 return 1; 503} 504 505static int check_strset(char *p, char *name) 506{ 507 return strncmp(p, name, strlen(name)); 508} 509 510static int is_empty_or_comment(char *line) 511{ 512 unsigned int i; 513 514 for (i = 0; i < strlen(line); i++) { 515 if (line[i] == ';') 516 return 1; 517 if (!isspace(line[i]) && !iscntrl(line[i])) 518 return 0; 519 } 520 521 return 1; 522} 523 524static int str_rw_cb(struct thread_data *td, char *mem) 525{ 526 if (!strncmp(mem, "read", 4) || !strncmp(mem, "0", 1)) { 527 td->ddir = DDIR_READ; 528 td->sequential = 1; 529 return 0; 530 } else if (!strncmp(mem, "randread", 8)) { 531 td->ddir = DDIR_READ; 532 td->sequential = 0; 533 return 0; 534 } else if (!strncmp(mem, "write", 5) || !strncmp(mem, "1", 1)) { 535 td->ddir = DDIR_WRITE; 536 td->sequential = 1; 537 return 0; 538 } else if (!strncmp(mem, "randwrite", 9)) { 539 td->ddir = DDIR_WRITE; 540 td->sequential = 0; 541 return 0; 542 } else if (!strncmp(mem, "rw", 2)) { 543 td->ddir = 0; 544 td->iomix = 1; 545 td->sequential = 1; 546 return 0; 547 } else if (!strncmp(mem, "randrw", 6)) { 548 td->ddir = 0; 549 td->iomix = 1; 550 td->sequential = 0; 551 return 0; 552 } 553 554 log_err("fio: data direction: read, write, randread, randwrite, rw, randrw\n"); 555 return 1; 556} 557 558static int str_verify_cb(struct thread_data *td, char *mem) 559{ 560 if (!strncmp(mem, "0", 1)) { 561 td->verify = VERIFY_NONE; 562 return 0; 563 } else if (!strncmp(mem, "md5", 3) || !strncmp(mem, "1", 1)) { 564 td->verify = VERIFY_MD5; 565 return 0; 566 } else if (!strncmp(mem, "crc32", 5)) { 567 td->verify = VERIFY_CRC32; 568 return 0; 569 } 570 571 log_err("fio: verify types: md5, crc32\n"); 572 return 1; 573} 574 575static int str_mem_cb(struct thread_data *td, char *mem) 576{ 577 if (!strncmp(mem, "malloc", 6)) { 578 td->mem_type = MEM_MALLOC; 579 return 0; 580 } else if (!strncmp(mem, "shm", 3)) { 581 td->mem_type = MEM_SHM; 582 return 0; 583 } else if (!strncmp(mem, "mmap", 4)) { 584 td->mem_type = MEM_MMAP; 585 return 0; 586 } 587 588 log_err("fio: mem type: malloc, shm, mmap\n"); 589 return 1; 590} 591 592static int str_ioengine_cb(struct thread_data *td, char *str) 593{ 594 if (!strncmp(str, "linuxaio", 8) || !strncmp(str, "aio", 3) || 595 !strncmp(str, "libaio", 6)) { 596 strcpy(td->io_engine_name, "libaio"); 597 td->io_engine = FIO_LIBAIO; 598 return 0; 599 } else if (!strncmp(str, "posixaio", 8)) { 600 strcpy(td->io_engine_name, "posixaio"); 601 td->io_engine = FIO_POSIXAIO; 602 return 0; 603 } else if (!strncmp(str, "sync", 4)) { 604 strcpy(td->io_engine_name, "sync"); 605 td->io_engine = FIO_SYNCIO; 606 return 0; 607 } else if (!strncmp(str, "mmap", 4)) { 608 strcpy(td->io_engine_name, "mmap"); 609 td->io_engine = FIO_MMAPIO; 610 return 0; 611 } else if (!strncmp(str, "sgio", 4)) { 612 strcpy(td->io_engine_name, "sgio"); 613 td->io_engine = FIO_SGIO; 614 return 0; 615 } else if (!strncmp(str, "splice", 6)) { 616 strcpy(td->io_engine_name, "splice"); 617 td->io_engine = FIO_SPLICEIO; 618 return 0; 619 } 620 621 log_err("fio: ioengine: { linuxaio, aio, libaio }, posixaio, sync, mmap, sgio, splice\n"); 622 return 1; 623} 624 625/* 626 * This is our [ini] type file parser. 627 */ 628int parse_jobs_ini(char *file, int stonewall_flag) 629{ 630 unsigned int prioclass, prio, cpu, global, il; 631 unsigned long long ull; 632 unsigned long ul1, ul2; 633 struct thread_data *td; 634 char *string, *name, *tmpbuf; 635 fpos_t off; 636 FILE *f; 637 char *p; 638 int ret = 0, stonewall; 639 640 f = fopen(file, "r"); 641 if (!f) { 642 perror("fopen job file"); 643 return 1; 644 } 645 646 string = malloc(4096); 647 name = malloc(256); 648 tmpbuf = malloc(4096); 649 650 stonewall = stonewall_flag; 651 while ((p = fgets(string, 4096, f)) != NULL) { 652 if (ret) 653 break; 654 if (is_empty_or_comment(p)) 655 continue; 656 if (sscanf(p, "[%s]", name) != 1) 657 continue; 658 659 global = !strncmp(name, "global", 6); 660 661 name[strlen(name) - 1] = '\0'; 662 663 td = get_new_job(global, &def_thread); 664 if (!td) { 665 ret = 1; 666 break; 667 } 668 669 /* 670 * Seperate multiple job files by a stonewall 671 */ 672 if (!global && stonewall) { 673 td->stonewall = stonewall; 674 stonewall = 0; 675 } 676 677 fgetpos(f, &off); 678 while ((p = fgets(string, 4096, f)) != NULL) { 679 if (is_empty_or_comment(p)) 680 continue; 681 if (strstr(p, "[")) 682 break; 683 strip_blank_front(&p); 684 strip_blank_end(p); 685 686 if (!check_int(p, "prio", &prio)) { 687#ifndef FIO_HAVE_IOPRIO 688 log_err("io priorities not available\n"); 689 ret = 1; 690 break; 691#endif 692 td->ioprio |= prio; 693 fgetpos(f, &off); 694 continue; 695 } 696 if (!check_int(p, "prioclass", &prioclass)) { 697#ifndef FIO_HAVE_IOPRIO 698 log_err("io priorities not available\n"); 699 ret = 1; 700 break; 701#else 702 td->ioprio |= prioclass << IOPRIO_CLASS_SHIFT; 703 fgetpos(f, &off); 704 continue; 705#endif 706 } 707 if (!check_int(p, "direct", &il)) { 708 td->odirect = il; 709 fgetpos(f, &off); 710 continue; 711 } 712 if (!check_int(p, "rand_repeatable", &il)) { 713 td->rand_repeatable = il; 714 fgetpos(f, &off); 715 continue; 716 } 717 if (!check_int(p, "rate", &td->rate)) { 718 fgetpos(f, &off); 719 continue; 720 } 721 if (!check_int(p, "ratemin", &td->ratemin)) { 722 fgetpos(f, &off); 723 continue; 724 } 725 if (!check_int(p, "ratecycle", &td->ratecycle)) { 726 fgetpos(f, &off); 727 continue; 728 } 729 if (!check_int(p, "thinktime", &td->thinktime)) { 730 fgetpos(f, &off); 731 continue; 732 } 733 if (!check_int(p, "cpumask", &cpu)) { 734#ifndef FIO_HAVE_CPU_AFFINITY 735 log_err("cpu affinity not available\n"); 736 ret = 1; 737 break; 738#endif 739 fill_cpu_mask(td->cpumask, cpu); 740 fgetpos(f, &off); 741 continue; 742 } 743 if (!check_int(p, "fsync", &td->fsync_blocks)) { 744 fgetpos(f, &off); 745 td->end_fsync = 1; 746 continue; 747 } 748 if (!check_int(p, "startdelay", &td->start_delay)) { 749 fgetpos(f, &off); 750 continue; 751 } 752 if (!check_str_time(p, "timeout", &ull)) { 753 td->timeout = ul1; 754 fgetpos(f, &off); 755 continue; 756 } 757 if (!check_int(p, "invalidate", &il)) { 758 td->invalidate_cache = il; 759 fgetpos(f, &off); 760 continue; 761 } 762 if (!check_int(p, "iodepth", &td->iodepth)) { 763 fgetpos(f, &off); 764 continue; 765 } 766 if (!check_int(p, "sync", &il)) { 767 td->sync_io = il; 768 fgetpos(f, &off); 769 continue; 770 } 771 if (!check_int(p, "bwavgtime", &td->bw_avg_time)) { 772 fgetpos(f, &off); 773 continue; 774 } 775 if (!check_int(p, "create_serialize", &il)) { 776 td->create_serialize = il; 777 fgetpos(f, &off); 778 continue; 779 } 780 if (!check_int(p, "create_fsync", &il)) { 781 td->create_fsync = il; 782 fgetpos(f, &off); 783 continue; 784 } 785 if (!check_int(p, "end_fsync", &il)) { 786 td->end_fsync = il; 787 fgetpos(f, &off); 788 continue; 789 } 790 if (!check_int(p, "loops", &td->loops)) { 791 fgetpos(f, &off); 792 continue; 793 } 794 if (!check_int(p, "numjobs", &td->numjobs)) { 795 fgetpos(f, &off); 796 continue; 797 } 798 if (!check_int(p, "overwrite", &il)) { 799 td->overwrite = il; 800 fgetpos(f, &off); 801 continue; 802 } 803 if (!check_int(p, "rwmixcycle", &td->rwmixcycle)) { 804 fgetpos(f, &off); 805 continue; 806 } 807 if (!check_int(p, "rwmixread", &il)) { 808 if (il > 100) 809 il = 100; 810 td->rwmixread = il; 811 fgetpos(f, &off); 812 continue; 813 } 814 if (!check_int(p, "rwmixwrite", &il)) { 815 if (il > 100) 816 il = 100; 817 td->rwmixread = 100 - il; 818 fgetpos(f, &off); 819 continue; 820 } 821 if (!check_int(p, "nice", &td->nice)) { 822 fgetpos(f, &off); 823 continue; 824 } 825 if (!check_range_bytes(p, "bsrange", &ul1, &ul2)) { 826 if (ul1 > ul2) { 827 td->max_bs = ul1; 828 td->min_bs = ul2; 829 } else { 830 td->max_bs = ul2; 831 td->min_bs = ul1; 832 } 833 fgetpos(f, &off); 834 continue; 835 } 836 if (!check_str_bytes(p, "bs", &ull)) { 837 td->bs = ull; 838 fgetpos(f, &off); 839 continue; 840 } 841 if (!check_str_bytes(p, "size", &td->file_size)) { 842 fgetpos(f, &off); 843 continue; 844 } 845 if (!check_str_bytes(p, "offset", &td->file_offset)) { 846 fgetpos(f, &off); 847 continue; 848 } 849 if (!check_str_bytes(p, "zonesize", &td->zone_size)) { 850 fgetpos(f, &off); 851 continue; 852 } 853 if (!check_str_bytes(p, "zoneskip", &td->zone_skip)) { 854 fgetpos(f, &off); 855 continue; 856 } 857 if (!check_str_bytes(p, "lockmem", &mlock_size)) { 858 fgetpos(f, &off); 859 continue; 860 } 861 if (!check_strstore(p, "directory", tmpbuf)) { 862 td->directory = strdup(tmpbuf); 863 fgetpos(f, &off); 864 continue; 865 } 866 if (!check_strstore(p, "name", tmpbuf)) { 867 snprintf(td->name, sizeof(td->name)-1, "%s%d", tmpbuf, td->thread_number); 868 fgetpos(f, &off); 869 continue; 870 } 871 if (!check_str(p, "mem", str_mem_cb, td)) { 872 fgetpos(f, &off); 873 continue; 874 } 875 if (!check_str(p, "verify", str_verify_cb, td)) { 876 fgetpos(f, &off); 877 continue; 878 } 879 if (!check_str(p, "rw", str_rw_cb, td)) { 880 fgetpos(f, &off); 881 continue; 882 } 883 if (!check_str(p, "ioengine", str_ioengine_cb, td)) { 884 fgetpos(f, &off); 885 continue; 886 } 887 if (!check_strset(p, "create")) { 888 td->create_file = 1; 889 fgetpos(f, &off); 890 continue; 891 } 892 if (!check_strset(p, "exitall")) { 893 exitall_on_terminate = 1; 894 fgetpos(f, &off); 895 continue; 896 } 897 if (!check_strset(p, "stonewall")) { 898 td->stonewall = 1; 899 fgetpos(f, &off); 900 continue; 901 } 902 if (!check_strset(p, "thread")) { 903 td->use_thread = 1; 904 fgetpos(f, &off); 905 continue; 906 } 907 if (!check_strstore(p, "iolog", tmpbuf)) { 908 if (td->write_iolog) { 909 log_err("fio: read iolog overrides given write_iolog\n"); 910 free(td->iolog_file); 911 td->write_iolog = 0; 912 } 913 td->iolog_file = strdup(tmpbuf); 914 td->read_iolog = 1; 915 fgetpos(f, &off); 916 continue; 917 } 918 if (!check_strstore(p, "write_iolog", tmpbuf)) { 919 if (!td->read_iolog) { 920 td->iolog_file = strdup(tmpbuf); 921 td->write_iolog = 1; 922 } else 923 log_err("fio: read iolog overrides given write_iolog\n"); 924 fgetpos(f, &off); 925 continue; 926 } 927 if (!check_strstore(p, "exec_prerun", tmpbuf)) { 928 td->exec_prerun = strdup(tmpbuf); 929 fgetpos(f, &off); 930 continue; 931 } 932 if (!check_strstore(p, "exec_postrun", tmpbuf)) { 933 td->exec_postrun = strdup(tmpbuf); 934 fgetpos(f, &off); 935 continue; 936 } 937 if (!check_strstore(p, "ioscheduler", tmpbuf)) { 938#ifndef FIO_HAVE_IOSCHED_SWITCH 939 log_err("io scheduler switching not available\n"); 940 ret = 1; 941 break; 942#else 943 td->ioscheduler = strdup(tmpbuf); 944 fgetpos(f, &off); 945 continue; 946#endif 947 } 948 949 /* 950 * Don't break here, continue parsing options so we 951 * dump all the bad ones. Makes trial/error fixups 952 * easier on the user. 953 */ 954 printf("Client%d: bad option %s\n",td->thread_number,p); 955 ret = 1; 956 } 957 958 if (!ret) { 959 fsetpos(f, &off); 960 ret = add_job(td, name, 0); 961 } 962 if (ret) 963 break; 964 } 965 966 free(string); 967 free(name); 968 free(tmpbuf); 969 fclose(f); 970 return ret; 971} 972 973static int fill_def_thread(void) 974{ 975 memset(&def_thread, 0, sizeof(def_thread)); 976 977 if (fio_getaffinity(getpid(), &def_thread.cpumask) == -1) { 978 perror("sched_getaffinity"); 979 return 1; 980 } 981 982 /* 983 * fill globals 984 */ 985 def_thread.ddir = DDIR_READ; 986 def_thread.iomix = 0; 987 def_thread.bs = DEF_BS; 988 def_thread.min_bs = -1; 989 def_thread.max_bs = -1; 990 def_thread.io_engine = DEF_IO_ENGINE; 991 strcpy(def_thread.io_engine_name, DEF_IO_ENGINE_NAME); 992 def_thread.odirect = DEF_ODIRECT; 993 def_thread.ratecycle = DEF_RATE_CYCLE; 994 def_thread.sequential = DEF_SEQUENTIAL; 995 def_thread.timeout = def_timeout; 996 def_thread.create_file = DEF_CREATE; 997 def_thread.overwrite = DEF_OVERWRITE; 998 def_thread.invalidate_cache = DEF_INVALIDATE; 999 def_thread.sync_io = DEF_SYNCIO; 1000 def_thread.mem_type = MEM_MALLOC; 1001 def_thread.bw_avg_time = DEF_BWAVGTIME; 1002 def_thread.create_serialize = DEF_CREATE_SER; 1003 def_thread.create_fsync = DEF_CREATE_FSYNC; 1004 def_thread.loops = DEF_LOOPS; 1005 def_thread.verify = DEF_VERIFY; 1006 def_thread.stonewall = DEF_STONEWALL; 1007 def_thread.numjobs = DEF_NUMJOBS; 1008 def_thread.use_thread = DEF_USE_THREAD; 1009 def_thread.rwmixcycle = DEF_RWMIX_CYCLE; 1010 def_thread.rwmixread = DEF_RWMIX_READ; 1011 def_thread.nice = DEF_NICE; 1012 def_thread.rand_repeatable = DEF_RAND_REPEAT; 1013#ifdef FIO_HAVE_DISK_UTIL 1014 def_thread.do_disk_util = 1; 1015#endif 1016 1017 return 0; 1018} 1019 1020static void usage(char *name) 1021{ 1022 printf("%s\n", fio_version_string); 1023 printf("\t-o Write output to file\n"); 1024 printf("\t-t Runtime in seconds\n"); 1025 printf("\t-l Generate per-job latency logs\n"); 1026 printf("\t-w Generate per-job bandwidth logs\n"); 1027 printf("\t-m Minimal (terse) output\n"); 1028 printf("\t-f Job file (Required)\n"); 1029 printf("\t-v Print version info and exit\n"); 1030} 1031 1032static int parse_cmd_line(int argc, char *argv[]) 1033{ 1034 int c, idx = 1, ini_idx = 0; 1035 1036 while ((c = getopt(argc, argv, "t:o:lwvhm")) != EOF) { 1037 switch (c) { 1038 case 't': 1039 def_timeout = atoi(optarg); 1040 idx++; 1041 break; 1042 case 'l': 1043 write_lat_log = 1; 1044 idx++; 1045 break; 1046 case 'w': 1047 write_bw_log = 1; 1048 idx++; 1049 break; 1050 case 'o': 1051 f_out = fopen(optarg, "w+"); 1052 if (!f_out) { 1053 perror("fopen output"); 1054 exit(1); 1055 } 1056 f_err = f_out; 1057 idx++; 1058 break; 1059 case 'm': 1060 terse_output = 1; 1061 idx++; 1062 break; 1063 case 'h': 1064 usage(argv[0]); 1065 exit(0); 1066 case 'v': 1067 printf("%s\n", fio_version_string); 1068 exit(0); 1069 } 1070 } 1071 1072 while (idx < argc) { 1073 ini_idx++; 1074 ini_file = realloc(ini_file, ini_idx * sizeof(char *)); 1075 ini_file[ini_idx - 1] = strdup(argv[idx]); 1076 idx++; 1077 } 1078 1079 if (!f_out) { 1080 f_out = stdout; 1081 f_err = stderr; 1082 } 1083 1084 return ini_idx; 1085} 1086 1087static void free_shm(void) 1088{ 1089 struct shmid_ds sbuf; 1090 1091 if (threads) { 1092 shmdt((void *) threads); 1093 threads = NULL; 1094 shmctl(shm_id, IPC_RMID, &sbuf); 1095 } 1096} 1097 1098/* 1099 * The thread area is shared between the main process and the job 1100 * threads/processes. So setup a shared memory segment that will hold 1101 * all the job info. 1102 */ 1103static int setup_thread_area(void) 1104{ 1105 /* 1106 * 1024 is too much on some machines, scale max_jobs if 1107 * we get a failure that looks like too large a shm segment 1108 */ 1109 do { 1110 size_t size = max_jobs * sizeof(struct thread_data); 1111 1112 shm_id = shmget(0, size, IPC_CREAT | 0600); 1113 if (shm_id != -1) 1114 break; 1115 if (errno != EINVAL) { 1116 perror("shmget"); 1117 break; 1118 } 1119 1120 max_jobs >>= 1; 1121 } while (max_jobs); 1122 1123 if (shm_id == -1) 1124 return 1; 1125 1126 threads = shmat(shm_id, NULL, 0); 1127 if (threads == (void *) -1) { 1128 perror("shmat"); 1129 return 1; 1130 } 1131 1132 atexit(free_shm); 1133 return 0; 1134} 1135 1136int parse_options(int argc, char *argv[]) 1137{ 1138 int job_files, i; 1139 1140 if (setup_thread_area()) 1141 return 1; 1142 if (fill_def_thread()) 1143 return 1; 1144 1145 job_files = parse_cmd_line(argc, argv); 1146 if (!job_files) { 1147 log_err("Need job file(s)\n"); 1148 usage(argv[0]); 1149 return 1; 1150 } 1151 1152 for (i = 0; i < job_files; i++) { 1153 if (fill_def_thread()) 1154 return 1; 1155 if (parse_jobs_ini(ini_file[i], i)) 1156 return 1; 1157 free(ini_file[i]); 1158 } 1159 1160 free(ini_file); 1161 return 0; 1162} 1163