init.c revision 896cac2a44de3725a6d615914e239cab4f382e1c
1/* 2 * This file contains job initialization and setup functions. 3 */ 4#include <stdio.h> 5#include <stdlib.h> 6#include <unistd.h> 7#include <fcntl.h> 8#include <ctype.h> 9#include <string.h> 10#include <errno.h> 11#include <getopt.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#include "parse.h" 19#include "smalloc.h" 20#include "filehash.h" 21#include "verify.h" 22 23static char fio_version_string[] = "fio 1.28"; 24 25#define FIO_RANDSEED (0xb1899bedUL) 26 27static char **ini_file; 28static int max_jobs = MAX_JOBS; 29static int dump_cmdline; 30 31static struct thread_data def_thread; 32struct thread_data *threads = NULL; 33 34int exitall_on_terminate = 0; 35int terse_output = 0; 36int eta_print; 37unsigned long long mlock_size = 0; 38FILE *f_out = NULL; 39FILE *f_err = NULL; 40char *job_section = NULL; 41 42int write_bw_log = 0; 43int read_only = 0; 44 45static int def_timeout; 46static int write_lat_log; 47 48static int prev_group_jobs; 49 50unsigned long fio_debug = 0; 51unsigned int fio_debug_jobno = -1; 52unsigned int *fio_debug_jobp = NULL; 53 54/* 55 * Command line options. These will contain the above, plus a few 56 * extra that only pertain to fio itself and not jobs. 57 */ 58static struct option l_opts[FIO_NR_OPTIONS] = { 59 { 60 .name = "output", 61 .has_arg = required_argument, 62 .val = 'o', 63 }, 64 { 65 .name = "timeout", 66 .has_arg = required_argument, 67 .val = 't', 68 }, 69 { 70 .name = "latency-log", 71 .has_arg = required_argument, 72 .val = 'l', 73 }, 74 { 75 .name = "bandwidth-log", 76 .has_arg = required_argument, 77 .val = 'b', 78 }, 79 { 80 .name = "minimal", 81 .has_arg = optional_argument, 82 .val = 'm', 83 }, 84 { 85 .name = "version", 86 .has_arg = no_argument, 87 .val = 'v', 88 }, 89 { 90 .name = "help", 91 .has_arg = no_argument, 92 .val = 'h', 93 }, 94 { 95 .name = "cmdhelp", 96 .has_arg = optional_argument, 97 .val = 'c', 98 }, 99 { 100 .name = "showcmd", 101 .has_arg = no_argument, 102 .val = 's', 103 }, 104 { 105 .name = "readonly", 106 .has_arg = no_argument, 107 .val = 'r', 108 }, 109 { 110 .name = "eta", 111 .has_arg = required_argument, 112 .val = 'e', 113 }, 114 { 115 .name = "debug", 116 .has_arg = required_argument, 117 .val = 'd', 118 }, 119 { 120 .name = "section", 121 .has_arg = required_argument, 122 .val = 'x', 123 }, 124 { 125 .name = "alloc-size", 126 .has_arg = required_argument, 127 .val = 'a', 128 }, 129 { 130 .name = NULL, 131 }, 132}; 133 134FILE *get_f_out() 135{ 136 return f_out; 137} 138 139FILE *get_f_err() 140{ 141 return f_err; 142} 143 144/* 145 * Return a free job structure. 146 */ 147static struct thread_data *get_new_job(int global, struct thread_data *parent) 148{ 149 struct thread_data *td; 150 151 if (global) 152 return &def_thread; 153 if (thread_number >= max_jobs) 154 return NULL; 155 156 td = &threads[thread_number++]; 157 *td = *parent; 158 159 dup_files(td, parent); 160 options_mem_dupe(td); 161 162 td->thread_number = thread_number; 163 return td; 164} 165 166static void put_job(struct thread_data *td) 167{ 168 if (td == &def_thread) 169 return; 170 171 if (td->error) 172 log_info("fio: %s\n", td->verror); 173 174 memset(&threads[td->thread_number - 1], 0, sizeof(*td)); 175 thread_number--; 176} 177 178static int __setup_rate(struct thread_data *td, enum fio_ddir ddir) 179{ 180 unsigned int bs = td->o.min_bs[ddir]; 181 unsigned long long rate; 182 unsigned long ios_per_msec; 183 184 if (td->o.rate[ddir]) { 185 rate = td->o.rate[ddir]; 186 ios_per_msec = (rate * 1000LL) / bs; 187 } else 188 ios_per_msec = td->o.rate_iops[ddir] * 1000UL; 189 190 if (!ios_per_msec) { 191 log_err("rate lower than supported\n"); 192 return -1; 193 } 194 195 td->rate_usec_cycle[ddir] = 1000000000ULL / ios_per_msec; 196 td->rate_pending_usleep[ddir] = 0; 197 return 0; 198} 199 200static int setup_rate(struct thread_data *td) 201{ 202 int ret = 0; 203 204 if (td->o.rate[DDIR_READ] || td->o.rate_iops[DDIR_READ]) 205 ret = __setup_rate(td, DDIR_READ); 206 if (td->o.rate[DDIR_WRITE] || td->o.rate_iops[DDIR_WRITE]) 207 ret |= __setup_rate(td, DDIR_WRITE); 208 209 return ret; 210} 211 212static int fixed_block_size(struct thread_options *o) 213{ 214 return o->min_bs[DDIR_READ] == o->max_bs[DDIR_READ] && 215 o->min_bs[DDIR_WRITE] == o->max_bs[DDIR_WRITE] && 216 o->min_bs[DDIR_READ] == o->min_bs[DDIR_WRITE]; 217} 218 219/* 220 * Lazy way of fixing up options that depend on each other. We could also 221 * define option callback handlers, but this is easier. 222 */ 223static int fixup_options(struct thread_data *td) 224{ 225 struct thread_options *o = &td->o; 226 227#ifndef FIO_HAVE_PSHARED_MUTEX 228 if (!td->o.use_thread) { 229 log_info("fio: this platform does not support process shared" 230 " mutexes, forcing use of threads. Use the 'thread'" 231 " option to get rid of this warning.\n"); 232 td->o.use_thread = 1; 233 } 234#endif 235 236#ifndef FIO_HAVE_CPU_AFFINITY 237 if (td->o.gtod_cpu) { 238 log_err("fio: platform must support CPU affinity for" 239 "gettimeofday() offloading\n"); 240 return 1; 241 } 242#endif 243 244#if 0 245 if (read_only && td_write(td)) { 246 log_err("fio: job <%s> has write bit set, but fio is in" 247 " read-only mode\n", td->o.name); 248 return 1; 249 } 250#endif 251 252 if (o->write_iolog_file && o->read_iolog_file) { 253 log_err("fio: read iolog overrides write_iolog\n"); 254 free(o->write_iolog_file); 255 o->write_iolog_file = NULL; 256 } 257 258 /* 259 * only really works for sequential io for now, and with 1 file 260 */ 261 if (o->zone_size && td_random(td) && o->open_files == 1) 262 o->zone_size = 0; 263 264 /* 265 * Reads can do overwrites, we always need to pre-create the file 266 */ 267 if (td_read(td) || td_rw(td)) 268 o->overwrite = 1; 269 270 if (!o->min_bs[DDIR_READ]) 271 o->min_bs[DDIR_READ] = o->bs[DDIR_READ]; 272 if (!o->max_bs[DDIR_READ]) 273 o->max_bs[DDIR_READ] = o->bs[DDIR_READ]; 274 if (!o->min_bs[DDIR_WRITE]) 275 o->min_bs[DDIR_WRITE] = o->bs[DDIR_WRITE]; 276 if (!o->max_bs[DDIR_WRITE]) 277 o->max_bs[DDIR_WRITE] = o->bs[DDIR_WRITE]; 278 279 o->rw_min_bs = min(o->min_bs[DDIR_READ], o->min_bs[DDIR_WRITE]); 280 281 /* 282 * For random IO, allow blockalign offset other than min_bs. 283 */ 284 if (!o->ba[DDIR_READ] || !td_random(td)) 285 o->ba[DDIR_READ] = o->min_bs[DDIR_READ]; 286 if (!o->ba[DDIR_WRITE] || !td_random(td)) 287 o->ba[DDIR_WRITE] = o->min_bs[DDIR_WRITE]; 288 289 if ((o->ba[DDIR_READ] != o->min_bs[DDIR_READ] || 290 o->ba[DDIR_WRITE] != o->min_bs[DDIR_WRITE]) && 291 !td->o.norandommap) { 292 log_err("fio: Any use of blockalign= turns off randommap\n"); 293 td->o.norandommap = 1; 294 } 295 296 if (!o->file_size_high) 297 o->file_size_high = o->file_size_low; 298 299 if (o->norandommap && o->verify != VERIFY_NONE 300 && !fixed_block_size(o)) { 301 log_err("fio: norandommap given for variable block sizes, " 302 "verify disabled\n"); 303 o->verify = VERIFY_NONE; 304 } 305 if (o->bs_unaligned && (o->odirect || td->io_ops->flags & FIO_RAWIO)) 306 log_err("fio: bs_unaligned may not work with raw io\n"); 307 308 /* 309 * thinktime_spin must be less than thinktime 310 */ 311 if (o->thinktime_spin > o->thinktime) 312 o->thinktime_spin = o->thinktime; 313 314 /* 315 * The low water mark cannot be bigger than the iodepth 316 */ 317 if (o->iodepth_low > o->iodepth || !o->iodepth_low) { 318 /* 319 * syslet work around - if the workload is sequential, 320 * we want to let the queue drain all the way down to 321 * avoid seeking between async threads 322 */ 323 if (!strcmp(td->io_ops->name, "syslet-rw") && !td_random(td)) 324 o->iodepth_low = 1; 325 else 326 o->iodepth_low = o->iodepth; 327 } 328 329 /* 330 * If batch number isn't set, default to the same as iodepth 331 */ 332 if (o->iodepth_batch > o->iodepth || !o->iodepth_batch) 333 o->iodepth_batch = o->iodepth; 334 335 if (o->nr_files > td->files_index) 336 o->nr_files = td->files_index; 337 338 if (o->open_files > o->nr_files || !o->open_files) 339 o->open_files = o->nr_files; 340 341 if (((o->rate[0] + o->rate[1]) && (o->rate_iops[0] + o->rate_iops[1]))|| 342 ((o->ratemin[0] + o->ratemin[1]) && (o->rate_iops_min[0] + 343 o->rate_iops_min[1]))) { 344 log_err("fio: rate and rate_iops are mutually exclusive\n"); 345 return 1; 346 } 347 if ((o->rate[0] < o->ratemin[0]) || (o->rate[1] < o->ratemin[1]) || 348 (o->rate_iops[0] < o->rate_iops_min[0]) || 349 (o->rate_iops[1] < o->rate_iops_min[1])) { 350 log_err("fio: minimum rate exceeds rate\n"); 351 return 1; 352 } 353 354 if (!o->timeout && o->time_based) { 355 log_err("fio: time_based requires a runtime/timeout setting\n"); 356 o->time_based = 0; 357 } 358 359 if (o->fill_device && !o->size) 360 o->size = -1ULL; 361 362 if (td_rw(td) && td->o.verify != VERIFY_NONE) 363 log_info("fio: mixed read/write workload with verify. May not " 364 "work as expected, unless you pre-populated the file\n"); 365 366 if (td->o.verify != VERIFY_NONE) 367 td->o.refill_buffers = 1; 368 369 if (td->o.pre_read) 370 td->o.invalidate_cache = 0; 371 372 if (td->o.mem_align) { 373 if (td->o.odirect && !is_power_of_2(td->o.mem_align)) { 374 log_err("fio: given IO mem alignment conflicts with" 375 " direct=1. Resetting.\n"); 376 td->o.mem_align = page_mask; 377 } 378 } 379 380 return 0; 381} 382 383/* 384 * This function leaks the buffer 385 */ 386static char *to_kmg(unsigned int val) 387{ 388 char *buf = malloc(32); 389 char post[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 }; 390 char *p = post; 391 392 do { 393 if (val & 1023) 394 break; 395 396 val >>= 10; 397 p++; 398 } while (*p); 399 400 snprintf(buf, 31, "%u%c", val, *p); 401 return buf; 402} 403 404/* External engines are specified by "external:name.o") */ 405static const char *get_engine_name(const char *str) 406{ 407 char *p = strstr(str, ":"); 408 409 if (!p) 410 return str; 411 412 p++; 413 strip_blank_front(&p); 414 strip_blank_end(p); 415 return p; 416} 417 418static int exists_and_not_file(const char *filename) 419{ 420 struct stat sb; 421 422 if (lstat(filename, &sb) == -1) 423 return 0; 424 425 if (S_ISREG(sb.st_mode)) 426 return 0; 427 428 return 1; 429} 430 431void td_fill_rand_seeds(struct thread_data *td) 432{ 433 os_random_seed(td->rand_seeds[0], &td->bsrange_state); 434 os_random_seed(td->rand_seeds[1], &td->verify_state); 435 os_random_seed(td->rand_seeds[2], &td->rwmix_state); 436 437 if (td->o.file_service_type == FIO_FSERVICE_RANDOM) 438 os_random_seed(td->rand_seeds[3], &td->next_file_state); 439 440 os_random_seed(td->rand_seeds[5], &td->file_size_state); 441 442 if (!td_random(td)) 443 return; 444 445 if (td->o.rand_repeatable) 446 td->rand_seeds[4] = FIO_RANDSEED * td->thread_number; 447 448 os_random_seed(td->rand_seeds[4], &td->random_state); 449} 450 451/* 452 * Initialize the various random states we need (random io, block size ranges, 453 * read/write mix, etc). 454 */ 455static int init_random_state(struct thread_data *td) 456{ 457 int fd; 458 459 fd = open("/dev/urandom", O_RDONLY); 460 if (fd == -1) { 461 td_verror(td, errno, "open"); 462 return 1; 463 } 464 465 if (read(fd, td->rand_seeds, sizeof(td->rand_seeds)) < 466 (int) sizeof(td->rand_seeds)) { 467 td_verror(td, EIO, "read"); 468 close(fd); 469 return 1; 470 } 471 472 close(fd); 473 td_fill_rand_seeds(td); 474 return 0; 475} 476 477/* 478 * Adds a job to the list of things todo. Sanitizes the various options 479 * to make sure we don't have conflicts, and initializes various 480 * members of td. 481 */ 482static int add_job(struct thread_data *td, const char *jobname, int job_add_num) 483{ 484 const char *ddir_str[] = { NULL, "read", "write", "rw", NULL, 485 "randread", "randwrite", "randrw" }; 486 unsigned int i; 487 const char *engine; 488 char fname[PATH_MAX]; 489 int numjobs, file_alloced; 490 491 /* 492 * the def_thread is just for options, it's not a real job 493 */ 494 if (td == &def_thread) 495 return 0; 496 497 /* 498 * if we are just dumping the output command line, don't add the job 499 */ 500 if (dump_cmdline) { 501 put_job(td); 502 return 0; 503 } 504 505 engine = get_engine_name(td->o.ioengine); 506 td->io_ops = load_ioengine(td, engine); 507 if (!td->io_ops) { 508 log_err("fio: failed to load engine %s\n", engine); 509 goto err; 510 } 511 512 if (td->o.use_thread) 513 nr_thread++; 514 else 515 nr_process++; 516 517 if (td->o.odirect) 518 td->io_ops->flags |= FIO_RAWIO; 519 520 file_alloced = 0; 521 if (!td->o.filename && !td->files_index && !td->o.read_iolog_file) { 522 file_alloced = 1; 523 524 if (td->o.nr_files == 1 && exists_and_not_file(jobname)) 525 add_file(td, jobname); 526 else { 527 for (i = 0; i < td->o.nr_files; i++) { 528 sprintf(fname, "%s.%d.%d", jobname, 529 td->thread_number, i); 530 add_file(td, fname); 531 } 532 } 533 } 534 535 if (fixup_options(td)) 536 goto err; 537 538 if (td->io_ops->flags & FIO_DISKLESSIO) { 539 struct fio_file *f; 540 541 for_each_file(td, f, i) 542 f->real_file_size = -1ULL; 543 } 544 545 td->mutex = fio_mutex_init(0); 546 547 td->ts.clat_stat[0].min_val = td->ts.clat_stat[1].min_val = ULONG_MAX; 548 td->ts.slat_stat[0].min_val = td->ts.slat_stat[1].min_val = ULONG_MAX; 549 td->ts.bw_stat[0].min_val = td->ts.bw_stat[1].min_val = ULONG_MAX; 550 td->ddir_nr = td->o.ddir_nr; 551 552 if ((td->o.stonewall || td->o.numjobs > 1 || td->o.new_group) 553 && prev_group_jobs) { 554 prev_group_jobs = 0; 555 groupid++; 556 } 557 558 td->groupid = groupid; 559 prev_group_jobs++; 560 561 if (init_random_state(td)) 562 goto err; 563 564 if (setup_rate(td)) 565 goto err; 566 567 if (td->o.write_lat_log) { 568 setup_log(&td->ts.slat_log); 569 setup_log(&td->ts.clat_log); 570 } 571 if (td->o.write_bw_log) 572 setup_log(&td->ts.bw_log); 573 574 if (!td->o.name) 575 td->o.name = strdup(jobname); 576 577 if (!terse_output) { 578 if (!job_add_num) { 579 if (!strcmp(td->io_ops->name, "cpuio")) { 580 log_info("%s: ioengine=cpu, cpuload=%u," 581 " cpucycle=%u\n", td->o.name, 582 td->o.cpuload, 583 td->o.cpucycle); 584 } else { 585 char *c1, *c2, *c3, *c4; 586 587 c1 = to_kmg(td->o.min_bs[DDIR_READ]); 588 c2 = to_kmg(td->o.max_bs[DDIR_READ]); 589 c3 = to_kmg(td->o.min_bs[DDIR_WRITE]); 590 c4 = to_kmg(td->o.max_bs[DDIR_WRITE]); 591 592 log_info("%s: (g=%d): rw=%s, bs=%s-%s/%s-%s," 593 " ioengine=%s, iodepth=%u\n", 594 td->o.name, td->groupid, 595 ddir_str[td->o.td_ddir], 596 c1, c2, c3, c4, 597 td->io_ops->name, 598 td->o.iodepth); 599 600 free(c1); 601 free(c2); 602 free(c3); 603 free(c4); 604 } 605 } else if (job_add_num == 1) 606 log_info("...\n"); 607 } 608 609 /* 610 * recurse add identical jobs, clear numjobs and stonewall options 611 * as they don't apply to sub-jobs 612 */ 613 numjobs = td->o.numjobs; 614 while (--numjobs) { 615 struct thread_data *td_new = get_new_job(0, td); 616 617 if (!td_new) 618 goto err; 619 620 td_new->o.numjobs = 1; 621 td_new->o.stonewall = 0; 622 td_new->o.new_group = 0; 623 624 if (file_alloced) { 625 td_new->o.filename = NULL; 626 td_new->files_index = 0; 627 td_new->files_size = 0; 628 td_new->files = NULL; 629 } 630 631 job_add_num = numjobs - 1; 632 633 if (add_job(td_new, jobname, job_add_num)) 634 goto err; 635 } 636 637 return 0; 638err: 639 put_job(td); 640 return -1; 641} 642 643static int skip_this_section(const char *name) 644{ 645 if (!job_section) 646 return 0; 647 if (!strncmp(name, "global", 6)) 648 return 0; 649 650 return strcmp(job_section, name); 651} 652 653static int is_empty_or_comment(char *line) 654{ 655 unsigned int i; 656 657 for (i = 0; i < strlen(line); i++) { 658 if (line[i] == ';') 659 return 1; 660 if (line[i] == '#') 661 return 1; 662 if (!isspace(line[i]) && !iscntrl(line[i])) 663 return 0; 664 } 665 666 return 1; 667} 668 669/* 670 * This is our [ini] type file parser. 671 */ 672static int parse_jobs_ini(char *file, int stonewall_flag) 673{ 674 unsigned int global; 675 struct thread_data *td; 676 char *string, *name; 677 FILE *f; 678 char *p; 679 int ret = 0, stonewall; 680 int first_sect = 1; 681 int skip_fgets = 0; 682 int inside_skip = 0; 683 char **opts; 684 int i, alloc_opts, num_opts; 685 686 if (!strcmp(file, "-")) 687 f = stdin; 688 else 689 f = fopen(file, "r"); 690 691 if (!f) { 692 perror("fopen job file"); 693 return 1; 694 } 695 696 string = malloc(4096); 697 698 /* 699 * it's really 256 + small bit, 280 should suffice 700 */ 701 name = malloc(280); 702 memset(name, 0, 280); 703 704 alloc_opts = 8; 705 opts = malloc(sizeof(char *) * alloc_opts); 706 num_opts = 0; 707 708 stonewall = stonewall_flag; 709 do { 710 /* 711 * if skip_fgets is set, we already have loaded a line we 712 * haven't handled. 713 */ 714 if (!skip_fgets) { 715 p = fgets(string, 4095, f); 716 if (!p) 717 break; 718 } 719 720 skip_fgets = 0; 721 strip_blank_front(&p); 722 strip_blank_end(p); 723 724 if (is_empty_or_comment(p)) 725 continue; 726 if (sscanf(p, "[%255s]", name) != 1) { 727 if (inside_skip) 728 continue; 729 log_err("fio: option <%s> outside of [] job section\n", 730 p); 731 break; 732 } 733 734 if (skip_this_section(name)) { 735 inside_skip = 1; 736 continue; 737 } else 738 inside_skip = 0; 739 740 global = !strncmp(name, "global", 6); 741 742 name[strlen(name) - 1] = '\0'; 743 744 if (dump_cmdline) { 745 if (first_sect) 746 log_info("fio "); 747 if (!global) 748 log_info("--name=%s ", name); 749 first_sect = 0; 750 } 751 752 td = get_new_job(global, &def_thread); 753 if (!td) { 754 ret = 1; 755 break; 756 } 757 758 /* 759 * Seperate multiple job files by a stonewall 760 */ 761 if (!global && stonewall) { 762 td->o.stonewall = stonewall; 763 stonewall = 0; 764 } 765 766 num_opts = 0; 767 memset(opts, 0, alloc_opts * sizeof(char *)); 768 769 while ((p = fgets(string, 4096, f)) != NULL) { 770 if (is_empty_or_comment(p)) 771 continue; 772 773 strip_blank_front(&p); 774 775 /* 776 * new section, break out and make sure we don't 777 * fgets() a new line at the top. 778 */ 779 if (p[0] == '[') { 780 skip_fgets = 1; 781 break; 782 } 783 784 strip_blank_end(p); 785 786 if (num_opts == alloc_opts) { 787 alloc_opts <<= 1; 788 opts = realloc(opts, 789 alloc_opts * sizeof(char *)); 790 } 791 792 opts[num_opts] = strdup(p); 793 num_opts++; 794 } 795 796 ret = fio_options_parse(td, opts, num_opts); 797 if (!ret) { 798 if (dump_cmdline) 799 for (i = 0; i < num_opts; i++) 800 log_info("--%s ", opts[i]); 801 802 ret = add_job(td, name, 0); 803 } else { 804 log_err("fio: job %s dropped\n", name); 805 put_job(td); 806 } 807 808 for (i = 0; i < num_opts; i++) 809 free(opts[i]); 810 num_opts = 0; 811 } while (!ret); 812 813 if (dump_cmdline) 814 log_info("\n"); 815 816 for (i = 0; i < num_opts; i++) 817 free(opts[i]); 818 819 free(string); 820 free(name); 821 free(opts); 822 if (f != stdin) 823 fclose(f); 824 return ret; 825} 826 827static int fill_def_thread(void) 828{ 829 memset(&def_thread, 0, sizeof(def_thread)); 830 831 fio_getaffinity(getpid(), &def_thread.o.cpumask); 832 833 /* 834 * fill default options 835 */ 836 fio_fill_default_options(&def_thread); 837 838 def_thread.o.timeout = def_timeout; 839 def_thread.o.write_bw_log = write_bw_log; 840 def_thread.o.write_lat_log = write_lat_log; 841 842 return 0; 843} 844 845static void free_shm(void) 846{ 847 struct shmid_ds sbuf; 848 849 if (threads) { 850 void *tp = threads; 851 852 threads = NULL; 853 file_hash_exit(); 854 fio_debug_jobp = NULL; 855 shmdt(tp); 856 shmctl(shm_id, IPC_RMID, &sbuf); 857 } 858 859 scleanup(); 860} 861 862/* 863 * The thread area is shared between the main process and the job 864 * threads/processes. So setup a shared memory segment that will hold 865 * all the job info. We use the end of the region for keeping track of 866 * open files across jobs, for file sharing. 867 */ 868static int setup_thread_area(void) 869{ 870 void *hash; 871 872 /* 873 * 1024 is too much on some machines, scale max_jobs if 874 * we get a failure that looks like too large a shm segment 875 */ 876 do { 877 size_t size = max_jobs * sizeof(struct thread_data); 878 879 size += file_hash_size; 880 size += sizeof(unsigned int); 881 882 shm_id = shmget(0, size, IPC_CREAT | 0600); 883 if (shm_id != -1) 884 break; 885 if (errno != EINVAL) { 886 perror("shmget"); 887 break; 888 } 889 890 max_jobs >>= 1; 891 } while (max_jobs); 892 893 if (shm_id == -1) 894 return 1; 895 896 threads = shmat(shm_id, NULL, 0); 897 if (threads == (void *) -1) { 898 perror("shmat"); 899 return 1; 900 } 901 902 memset(threads, 0, max_jobs * sizeof(struct thread_data)); 903 hash = (void *) threads + max_jobs * sizeof(struct thread_data); 904 fio_debug_jobp = (void *) hash + file_hash_size; 905 *fio_debug_jobp = -1; 906 file_hash_init(hash); 907 atexit(free_shm); 908 return 0; 909} 910 911static void usage(const char *name) 912{ 913 printf("%s\n", fio_version_string); 914 printf("%s [options] [job options] <job file(s)>\n", name); 915 printf("\t--debug=options\tEnable debug logging\n"); 916 printf("\t--output\tWrite output to file\n"); 917 printf("\t--timeout\tRuntime in seconds\n"); 918 printf("\t--latency-log\tGenerate per-job latency logs\n"); 919 printf("\t--bandwidth-log\tGenerate per-job bandwidth logs\n"); 920 printf("\t--minimal\tMinimal (terse) output\n"); 921 printf("\t--version\tPrint version info and exit\n"); 922 printf("\t--help\t\tPrint this page\n"); 923 printf("\t--cmdhelp=cmd\tPrint command help, \"all\" for all of" 924 " them\n"); 925 printf("\t--showcmd\tTurn a job file into command line options\n"); 926 printf("\t--eta=when\tWhen ETA estimate should be printed\n"); 927 printf("\t \tMay be \"always\", \"never\" or \"auto\"\n"); 928 printf("\t--readonly\tTurn on safety read-only checks, preventing" 929 " writes\n"); 930 printf("\t--section=name\tOnly run specified section in job file\n"); 931 printf("\t--alloc-size=kb\tSet smalloc pool to this size in kb" 932 " (def 1024)\n"); 933 printf("\nFio was written by Jens Axboe <jens.axboe@oracle.com>\n"); 934} 935 936#ifdef FIO_INC_DEBUG 937struct debug_level debug_levels[] = { 938 { .name = "process", .shift = FD_PROCESS, }, 939 { .name = "file", .shift = FD_FILE, }, 940 { .name = "io", .shift = FD_IO, }, 941 { .name = "mem", .shift = FD_MEM, }, 942 { .name = "blktrace", .shift = FD_BLKTRACE }, 943 { .name = "verify", .shift = FD_VERIFY }, 944 { .name = "random", .shift = FD_RANDOM }, 945 { .name = "parse", .shift = FD_PARSE }, 946 { .name = "diskutil", .shift = FD_DISKUTIL }, 947 { .name = "job", .shift = FD_JOB }, 948 { .name = "mutex", .shift = FD_MUTEX }, 949 { .name = NULL, }, 950}; 951 952static int set_debug(const char *string) 953{ 954 struct debug_level *dl; 955 char *p = (char *) string; 956 char *opt; 957 int i; 958 959 if (!strcmp(string, "?") || !strcmp(string, "help")) { 960 int i; 961 962 log_info("fio: dumping debug options:"); 963 for (i = 0; debug_levels[i].name; i++) { 964 dl = &debug_levels[i]; 965 log_info("%s,", dl->name); 966 } 967 log_info("all\n"); 968 return 1; 969 } 970 971 while ((opt = strsep(&p, ",")) != NULL) { 972 int found = 0; 973 974 if (!strncmp(opt, "all", 3)) { 975 log_info("fio: set all debug options\n"); 976 fio_debug = ~0UL; 977 continue; 978 } 979 980 for (i = 0; debug_levels[i].name; i++) { 981 dl = &debug_levels[i]; 982 found = !strncmp(opt, dl->name, strlen(dl->name)); 983 if (!found) 984 continue; 985 986 if (dl->shift == FD_JOB) { 987 opt = strchr(opt, ':'); 988 if (!opt) { 989 log_err("fio: missing job number\n"); 990 break; 991 } 992 opt++; 993 fio_debug_jobno = atoi(opt); 994 log_info("fio: set debug jobno %d\n", 995 fio_debug_jobno); 996 } else { 997 log_info("fio: set debug option %s\n", opt); 998 fio_debug |= (1UL << dl->shift); 999 } 1000 break; 1001 } 1002 1003 if (!found) 1004 log_err("fio: debug mask %s not found\n", opt); 1005 } 1006 return 0; 1007} 1008#else 1009static int set_debug(const char *string) 1010{ 1011 log_err("fio: debug tracing not included in build\n"); 1012 return 1; 1013} 1014#endif 1015 1016static int parse_cmd_line(int argc, char *argv[]) 1017{ 1018 struct thread_data *td = NULL; 1019 int c, ini_idx = 0, lidx, ret = 0, do_exit = 0, exit_val = 0; 1020 1021 while ((c = getopt_long_only(argc, argv, "", l_opts, &lidx)) != -1) { 1022 switch (c) { 1023 case 'a': 1024 smalloc_pool_size = atoi(optarg); 1025 break; 1026 case 't': 1027 def_timeout = atoi(optarg); 1028 break; 1029 case 'l': 1030 write_lat_log = 1; 1031 break; 1032 case 'w': 1033 write_bw_log = 1; 1034 break; 1035 case 'o': 1036 f_out = fopen(optarg, "w+"); 1037 if (!f_out) { 1038 perror("fopen output"); 1039 exit(1); 1040 } 1041 f_err = f_out; 1042 break; 1043 case 'm': 1044 terse_output = 1; 1045 break; 1046 case 'h': 1047 usage(argv[0]); 1048 exit(0); 1049 case 'c': 1050 exit(fio_show_option_help(optarg)); 1051 case 's': 1052 dump_cmdline = 1; 1053 break; 1054 case 'r': 1055 read_only = 1; 1056 break; 1057 case 'v': 1058 printf("%s\n", fio_version_string); 1059 exit(0); 1060 case 'e': 1061 if (!strcmp("always", optarg)) 1062 eta_print = FIO_ETA_ALWAYS; 1063 else if (!strcmp("never", optarg)) 1064 eta_print = FIO_ETA_NEVER; 1065 break; 1066 case 'd': 1067 if (set_debug(optarg)) 1068 do_exit++; 1069 break; 1070 case 'x': 1071 if (!strcmp(optarg, "global")) { 1072 log_err("fio: can't use global as only " 1073 "section\n"); 1074 do_exit++; 1075 exit_val = 1; 1076 break; 1077 } 1078 if (job_section) 1079 free(job_section); 1080 job_section = strdup(optarg); 1081 break; 1082 case FIO_GETOPT_JOB: { 1083 const char *opt = l_opts[lidx].name; 1084 char *val = optarg; 1085 1086 if (!strncmp(opt, "name", 4) && td) { 1087 ret = add_job(td, td->o.name ?: "fio", 0); 1088 if (ret) { 1089 put_job(td); 1090 return 0; 1091 } 1092 td = NULL; 1093 } 1094 if (!td) { 1095 int is_section = !strncmp(opt, "name", 4); 1096 int global = 0; 1097 1098 if (!is_section || !strncmp(val, "global", 6)) 1099 global = 1; 1100 1101 if (is_section && skip_this_section(val)) 1102 continue; 1103 1104 td = get_new_job(global, &def_thread); 1105 if (!td) 1106 return 0; 1107 } 1108 1109 ret = fio_cmd_option_parse(td, opt, val); 1110 break; 1111 } 1112 default: 1113 do_exit++; 1114 exit_val = 1; 1115 break; 1116 } 1117 } 1118 1119 if (do_exit) 1120 exit(exit_val); 1121 1122 if (td) { 1123 if (!ret) 1124 ret = add_job(td, td->o.name ?: "fio", 0); 1125 if (ret) 1126 put_job(td); 1127 } 1128 1129 while (optind < argc) { 1130 ini_idx++; 1131 ini_file = realloc(ini_file, ini_idx * sizeof(char *)); 1132 ini_file[ini_idx - 1] = strdup(argv[optind]); 1133 optind++; 1134 } 1135 1136 return ini_idx; 1137} 1138 1139int parse_options(int argc, char *argv[]) 1140{ 1141 int job_files, i; 1142 1143 f_out = stdout; 1144 f_err = stderr; 1145 1146 fio_options_dup_and_init(l_opts); 1147 1148 if (setup_thread_area()) 1149 return 1; 1150 if (fill_def_thread()) 1151 return 1; 1152 1153 job_files = parse_cmd_line(argc, argv); 1154 1155 for (i = 0; i < job_files; i++) { 1156 if (fill_def_thread()) 1157 return 1; 1158 if (parse_jobs_ini(ini_file[i], i)) 1159 return 1; 1160 free(ini_file[i]); 1161 } 1162 1163 free(ini_file); 1164 options_mem_free(&def_thread); 1165 1166 if (!thread_number) { 1167 if (dump_cmdline) 1168 return 0; 1169 1170 log_err("No jobs defined(s)\n\n"); 1171 usage(argv[0]); 1172 return 1; 1173 } 1174 1175 if (def_thread.o.gtod_offload) { 1176 fio_gtod_init(); 1177 fio_gtod_offload = 1; 1178 fio_gtod_cpu = def_thread.o.gtod_cpu; 1179 } 1180 1181 return 0; 1182} 1183