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