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