init.c revision 38a812d7fa79a673855efb6324c8fc68b92b89c1
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 <sys/ipc.h> 12#include <sys/types.h> 13#include <sys/stat.h> 14 15#include "fio.h" 16#ifndef FIO_NO_HAVE_SHM_H 17#include <sys/shm.h> 18#endif 19 20#include "parse.h" 21#include "smalloc.h" 22#include "filehash.h" 23#include "verify.h" 24#include "profile.h" 25#include "server.h" 26#include "idletime.h" 27#include "filelock.h" 28 29#include "lib/getopt.h" 30#include "lib/strcasestr.h" 31 32#include "crc/test.h" 33 34const char fio_version_string[] = FIO_VERSION; 35 36#define FIO_RANDSEED (0xb1899bedUL) 37 38static char **ini_file; 39static int max_jobs = FIO_MAX_JOBS; 40static int dump_cmdline; 41static long long def_timeout; 42static int parse_only; 43 44static struct thread_data def_thread; 45struct thread_data *threads = NULL; 46static char **job_sections; 47static int nr_job_sections; 48 49int exitall_on_terminate = 0; 50int output_format = FIO_OUTPUT_NORMAL; 51int append_terse_output = 0; 52int eta_print = FIO_ETA_AUTO; 53int eta_new_line = 0; 54FILE *f_out = NULL; 55FILE *f_err = NULL; 56char *exec_profile = NULL; 57int warnings_fatal = 0; 58int terse_version = 3; 59int is_backend = 0; 60int nr_clients = 0; 61int log_syslog = 0; 62 63int write_bw_log = 0; 64int read_only = 0; 65int status_interval = 0; 66 67static int prev_group_jobs; 68 69unsigned long fio_debug = 0; 70unsigned int fio_debug_jobno = -1; 71unsigned int *fio_debug_jobp = NULL; 72 73static char cmd_optstr[256]; 74static int did_arg; 75 76#define FIO_CLIENT_FLAG (1 << 16) 77 78/* 79 * Command line options. These will contain the above, plus a few 80 * extra that only pertain to fio itself and not jobs. 81 */ 82static struct option l_opts[FIO_NR_OPTIONS] = { 83 { 84 .name = (char *) "output", 85 .has_arg = required_argument, 86 .val = 'o' | FIO_CLIENT_FLAG, 87 }, 88 { 89 .name = (char *) "timeout", 90 .has_arg = required_argument, 91 .val = 't' | FIO_CLIENT_FLAG, 92 }, 93 { 94 .name = (char *) "latency-log", 95 .has_arg = required_argument, 96 .val = 'l' | FIO_CLIENT_FLAG, 97 }, 98 { 99 .name = (char *) "bandwidth-log", 100 .has_arg = required_argument, 101 .val = 'b' | FIO_CLIENT_FLAG, 102 }, 103 { 104 .name = (char *) "minimal", 105 .has_arg = no_argument, 106 .val = 'm' | FIO_CLIENT_FLAG, 107 }, 108 { 109 .name = (char *) "output-format", 110 .has_arg = optional_argument, 111 .val = 'F' | FIO_CLIENT_FLAG, 112 }, 113 { 114 .name = (char *) "append-terse", 115 .has_arg = optional_argument, 116 .val = 'f', 117 }, 118 { 119 .name = (char *) "version", 120 .has_arg = no_argument, 121 .val = 'v' | FIO_CLIENT_FLAG, 122 }, 123 { 124 .name = (char *) "help", 125 .has_arg = no_argument, 126 .val = 'h' | FIO_CLIENT_FLAG, 127 }, 128 { 129 .name = (char *) "cmdhelp", 130 .has_arg = optional_argument, 131 .val = 'c' | FIO_CLIENT_FLAG, 132 }, 133 { 134 .name = (char *) "enghelp", 135 .has_arg = optional_argument, 136 .val = 'i' | FIO_CLIENT_FLAG, 137 }, 138 { 139 .name = (char *) "showcmd", 140 .has_arg = no_argument, 141 .val = 's' | FIO_CLIENT_FLAG, 142 }, 143 { 144 .name = (char *) "readonly", 145 .has_arg = no_argument, 146 .val = 'r' | FIO_CLIENT_FLAG, 147 }, 148 { 149 .name = (char *) "eta", 150 .has_arg = required_argument, 151 .val = 'e' | FIO_CLIENT_FLAG, 152 }, 153 { 154 .name = (char *) "eta-newline", 155 .has_arg = required_argument, 156 .val = 'E' | FIO_CLIENT_FLAG, 157 }, 158 { 159 .name = (char *) "debug", 160 .has_arg = required_argument, 161 .val = 'd' | FIO_CLIENT_FLAG, 162 }, 163 { 164 .name = (char *) "parse-only", 165 .has_arg = no_argument, 166 .val = 'P' | FIO_CLIENT_FLAG, 167 }, 168 { 169 .name = (char *) "section", 170 .has_arg = required_argument, 171 .val = 'x' | FIO_CLIENT_FLAG, 172 }, 173 { 174 .name = (char *) "alloc-size", 175 .has_arg = required_argument, 176 .val = 'a' | FIO_CLIENT_FLAG, 177 }, 178 { 179 .name = (char *) "profile", 180 .has_arg = required_argument, 181 .val = 'p' | FIO_CLIENT_FLAG, 182 }, 183 { 184 .name = (char *) "warnings-fatal", 185 .has_arg = no_argument, 186 .val = 'w' | FIO_CLIENT_FLAG, 187 }, 188 { 189 .name = (char *) "max-jobs", 190 .has_arg = required_argument, 191 .val = 'j' | FIO_CLIENT_FLAG, 192 }, 193 { 194 .name = (char *) "terse-version", 195 .has_arg = required_argument, 196 .val = 'V' | FIO_CLIENT_FLAG, 197 }, 198 { 199 .name = (char *) "server", 200 .has_arg = optional_argument, 201 .val = 'S', 202 }, 203 { .name = (char *) "daemonize", 204 .has_arg = required_argument, 205 .val = 'D', 206 }, 207 { 208 .name = (char *) "client", 209 .has_arg = required_argument, 210 .val = 'C', 211 }, 212 { 213 .name = (char *) "cpuclock-test", 214 .has_arg = no_argument, 215 .val = 'T', 216 }, 217 { 218 .name = (char *) "crctest", 219 .has_arg = optional_argument, 220 .val = 'G', 221 }, 222 { 223 .name = (char *) "idle-prof", 224 .has_arg = required_argument, 225 .val = 'I', 226 }, 227 { 228 .name = (char *) "status-interval", 229 .has_arg = required_argument, 230 .val = 'L', 231 }, 232 { 233 .name = NULL, 234 }, 235}; 236 237void free_threads_shm(void) 238{ 239 if (threads) { 240 void *tp = threads; 241#ifndef CONFIG_NO_SHM 242 struct shmid_ds sbuf; 243 244 threads = NULL; 245 shmdt(tp); 246 shmctl(shm_id, IPC_RMID, &sbuf); 247 shm_id = -1; 248#else 249 threads = NULL; 250 free(tp); 251#endif 252 } 253} 254 255static void free_shm(void) 256{ 257 if (threads) { 258 file_hash_exit(); 259 flow_exit(); 260 fio_debug_jobp = NULL; 261 free_threads_shm(); 262 } 263 264 options_free(fio_options, &def_thread); 265 fio_filelock_exit(); 266 scleanup(); 267} 268 269/* 270 * The thread area is shared between the main process and the job 271 * threads/processes. So setup a shared memory segment that will hold 272 * all the job info. We use the end of the region for keeping track of 273 * open files across jobs, for file sharing. 274 */ 275static int setup_thread_area(void) 276{ 277 void *hash; 278 279 if (threads) 280 return 0; 281 282 /* 283 * 1024 is too much on some machines, scale max_jobs if 284 * we get a failure that looks like too large a shm segment 285 */ 286 do { 287 size_t size = max_jobs * sizeof(struct thread_data); 288 289 size += file_hash_size; 290 size += sizeof(unsigned int); 291 292#ifndef CONFIG_NO_SHM 293 shm_id = shmget(0, size, IPC_CREAT | 0600); 294 if (shm_id != -1) 295 break; 296 if (errno != EINVAL && errno != ENOMEM && errno != ENOSPC) { 297 perror("shmget"); 298 break; 299 } 300#else 301 threads = malloc(size); 302 if (threads) 303 break; 304#endif 305 306 max_jobs >>= 1; 307 } while (max_jobs); 308 309#ifndef CONFIG_NO_SHM 310 if (shm_id == -1) 311 return 1; 312 313 threads = shmat(shm_id, NULL, 0); 314 if (threads == (void *) -1) { 315 perror("shmat"); 316 return 1; 317 } 318#endif 319 320 memset(threads, 0, max_jobs * sizeof(struct thread_data)); 321 hash = (void *) threads + max_jobs * sizeof(struct thread_data); 322 fio_debug_jobp = (void *) hash + file_hash_size; 323 *fio_debug_jobp = -1; 324 file_hash_init(hash); 325 326 flow_init(); 327 328 return 0; 329} 330 331static void set_cmd_options(struct thread_data *td) 332{ 333 struct thread_options *o = &td->o; 334 335 if (!o->timeout) 336 o->timeout = def_timeout; 337} 338 339/* 340 * Return a free job structure. 341 */ 342static struct thread_data *get_new_job(int global, struct thread_data *parent, 343 int preserve_eo, const char *jobname) 344{ 345 struct thread_data *td; 346 347 if (global) { 348 set_cmd_options(&def_thread); 349 return &def_thread; 350 } 351 if (setup_thread_area()) { 352 log_err("error: failed to setup shm segment\n"); 353 return NULL; 354 } 355 if (thread_number >= max_jobs) { 356 log_err("error: maximum number of jobs (%d) reached.\n", 357 max_jobs); 358 return NULL; 359 } 360 361 td = &threads[thread_number++]; 362 *td = *parent; 363 364 td->io_ops = NULL; 365 if (!preserve_eo) 366 td->eo = NULL; 367 368 td->o.uid = td->o.gid = -1U; 369 370 dup_files(td, parent); 371 fio_options_mem_dupe(td); 372 373 profile_add_hooks(td); 374 375 td->thread_number = thread_number; 376 377 if (jobname) 378 td->o.name = strdup(jobname); 379 380 if (!parent->o.group_reporting) 381 stat_number++; 382 383 set_cmd_options(td); 384 return td; 385} 386 387static void put_job(struct thread_data *td) 388{ 389 if (td == &def_thread) 390 return; 391 392 profile_td_exit(td); 393 flow_exit_job(td); 394 395 if (td->error) 396 log_info("fio: %s\n", td->verror); 397 398 fio_options_free(td); 399 if (td->io_ops) 400 free_ioengine(td); 401 402 if (td->o.name) 403 free(td->o.name); 404 405 memset(&threads[td->thread_number - 1], 0, sizeof(*td)); 406 thread_number--; 407} 408 409static int __setup_rate(struct thread_data *td, enum fio_ddir ddir) 410{ 411 unsigned int bs = td->o.min_bs[ddir]; 412 413 assert(ddir_rw(ddir)); 414 415 if (td->o.rate[ddir]) 416 td->rate_bps[ddir] = td->o.rate[ddir]; 417 else 418 td->rate_bps[ddir] = td->o.rate_iops[ddir] * bs; 419 420 if (!td->rate_bps[ddir]) { 421 log_err("rate lower than supported\n"); 422 return -1; 423 } 424 425 td->rate_pending_usleep[ddir] = 0; 426 return 0; 427} 428 429static int setup_rate(struct thread_data *td) 430{ 431 int ret = 0; 432 433 if (td->o.rate[DDIR_READ] || td->o.rate_iops[DDIR_READ]) 434 ret = __setup_rate(td, DDIR_READ); 435 if (td->o.rate[DDIR_WRITE] || td->o.rate_iops[DDIR_WRITE]) 436 ret |= __setup_rate(td, DDIR_WRITE); 437 if (td->o.rate[DDIR_TRIM] || td->o.rate_iops[DDIR_TRIM]) 438 ret |= __setup_rate(td, DDIR_TRIM); 439 440 return ret; 441} 442 443static int fixed_block_size(struct thread_options *o) 444{ 445 return o->min_bs[DDIR_READ] == o->max_bs[DDIR_READ] && 446 o->min_bs[DDIR_WRITE] == o->max_bs[DDIR_WRITE] && 447 o->min_bs[DDIR_TRIM] == o->max_bs[DDIR_TRIM] && 448 o->min_bs[DDIR_READ] == o->min_bs[DDIR_WRITE] && 449 o->min_bs[DDIR_READ] == o->min_bs[DDIR_TRIM]; 450} 451 452 453static unsigned long long get_rand_start_delay(struct thread_data *td) 454{ 455 unsigned long long delayrange; 456 unsigned long r; 457 458 delayrange = td->o.start_delay_high - td->o.start_delay; 459 460 if (td->o.use_os_rand) { 461 r = os_random_long(&td->delay_state); 462 delayrange = (unsigned long long) ((double) delayrange * (r / (OS_RAND_MAX + 1.0))); 463 } else { 464 r = __rand(&td->__delay_state); 465 delayrange = (unsigned long long) ((double) delayrange * (r / (FRAND_MAX + 1.0))); 466 } 467 468 delayrange += td->o.start_delay; 469 return delayrange; 470} 471 472/* 473 * Lazy way of fixing up options that depend on each other. We could also 474 * define option callback handlers, but this is easier. 475 */ 476static int fixup_options(struct thread_data *td) 477{ 478 struct thread_options *o = &td->o; 479 int ret = 0; 480 481#ifndef FIO_HAVE_PSHARED_MUTEX 482 if (!o->use_thread) { 483 log_info("fio: this platform does not support process shared" 484 " mutexes, forcing use of threads. Use the 'thread'" 485 " option to get rid of this warning.\n"); 486 o->use_thread = 1; 487 ret = warnings_fatal; 488 } 489#endif 490 491 if (o->write_iolog_file && o->read_iolog_file) { 492 log_err("fio: read iolog overrides write_iolog\n"); 493 free(o->write_iolog_file); 494 o->write_iolog_file = NULL; 495 ret = warnings_fatal; 496 } 497 498 /* 499 * only really works with 1 file 500 */ 501 if (o->zone_size && o->open_files > 1) 502 o->zone_size = 0; 503 504 /* 505 * If zone_range isn't specified, backward compatibility dictates it 506 * should be made equal to zone_size. 507 */ 508 if (o->zone_size && !o->zone_range) 509 o->zone_range = o->zone_size; 510 511 /* 512 * Reads can do overwrites, we always need to pre-create the file 513 */ 514 if (td_read(td) || td_rw(td)) 515 o->overwrite = 1; 516 517 if (!o->min_bs[DDIR_READ]) 518 o->min_bs[DDIR_READ] = o->bs[DDIR_READ]; 519 if (!o->max_bs[DDIR_READ]) 520 o->max_bs[DDIR_READ] = o->bs[DDIR_READ]; 521 if (!o->min_bs[DDIR_WRITE]) 522 o->min_bs[DDIR_WRITE] = o->bs[DDIR_WRITE]; 523 if (!o->max_bs[DDIR_WRITE]) 524 o->max_bs[DDIR_WRITE] = o->bs[DDIR_WRITE]; 525 if (!o->min_bs[DDIR_TRIM]) 526 o->min_bs[DDIR_TRIM] = o->bs[DDIR_TRIM]; 527 if (!o->max_bs[DDIR_TRIM]) 528 o->max_bs[DDIR_TRIM] = o->bs[DDIR_TRIM]; 529 530 531 o->rw_min_bs = min(o->min_bs[DDIR_READ], o->min_bs[DDIR_WRITE]); 532 o->rw_min_bs = min(o->min_bs[DDIR_TRIM], o->rw_min_bs); 533 534 /* 535 * For random IO, allow blockalign offset other than min_bs. 536 */ 537 if (!o->ba[DDIR_READ] || !td_random(td)) 538 o->ba[DDIR_READ] = o->min_bs[DDIR_READ]; 539 if (!o->ba[DDIR_WRITE] || !td_random(td)) 540 o->ba[DDIR_WRITE] = o->min_bs[DDIR_WRITE]; 541 if (!o->ba[DDIR_TRIM] || !td_random(td)) 542 o->ba[DDIR_TRIM] = o->min_bs[DDIR_TRIM]; 543 544 if ((o->ba[DDIR_READ] != o->min_bs[DDIR_READ] || 545 o->ba[DDIR_WRITE] != o->min_bs[DDIR_WRITE] || 546 o->ba[DDIR_TRIM] != o->min_bs[DDIR_TRIM]) && 547 !o->norandommap) { 548 log_err("fio: Any use of blockalign= turns off randommap\n"); 549 o->norandommap = 1; 550 ret = warnings_fatal; 551 } 552 553 if (!o->file_size_high) 554 o->file_size_high = o->file_size_low; 555 556 if (o->start_delay_high) 557 o->start_delay = get_rand_start_delay(td); 558 559 if (o->norandommap && o->verify != VERIFY_NONE 560 && !fixed_block_size(o)) { 561 log_err("fio: norandommap given for variable block sizes, " 562 "verify disabled\n"); 563 o->verify = VERIFY_NONE; 564 ret = warnings_fatal; 565 } 566 if (o->bs_unaligned && (o->odirect || td->io_ops->flags & FIO_RAWIO)) 567 log_err("fio: bs_unaligned may not work with raw io\n"); 568 569 /* 570 * thinktime_spin must be less than thinktime 571 */ 572 if (o->thinktime_spin > o->thinktime) 573 o->thinktime_spin = o->thinktime; 574 575 /* 576 * The low water mark cannot be bigger than the iodepth 577 */ 578 if (o->iodepth_low > o->iodepth || !o->iodepth_low) 579 o->iodepth_low = o->iodepth; 580 581 /* 582 * If batch number isn't set, default to the same as iodepth 583 */ 584 if (o->iodepth_batch > o->iodepth || !o->iodepth_batch) 585 o->iodepth_batch = o->iodepth; 586 587 if (o->nr_files > td->files_index) 588 o->nr_files = td->files_index; 589 590 if (o->open_files > o->nr_files || !o->open_files) 591 o->open_files = o->nr_files; 592 593 if (((o->rate[DDIR_READ] + o->rate[DDIR_WRITE] + o->rate[DDIR_TRIM]) && 594 (o->rate_iops[DDIR_READ] + o->rate_iops[DDIR_WRITE] + o->rate_iops[DDIR_TRIM])) || 595 ((o->ratemin[DDIR_READ] + o->ratemin[DDIR_WRITE] + o->ratemin[DDIR_TRIM]) && 596 (o->rate_iops_min[DDIR_READ] + o->rate_iops_min[DDIR_WRITE] + o->rate_iops_min[DDIR_TRIM]))) { 597 log_err("fio: rate and rate_iops are mutually exclusive\n"); 598 ret = 1; 599 } 600 if ((o->rate[DDIR_READ] < o->ratemin[DDIR_READ]) || 601 (o->rate[DDIR_WRITE] < o->ratemin[DDIR_WRITE]) || 602 (o->rate[DDIR_TRIM] < o->ratemin[DDIR_TRIM]) || 603 (o->rate_iops[DDIR_READ] < o->rate_iops_min[DDIR_READ]) || 604 (o->rate_iops[DDIR_WRITE] < o->rate_iops_min[DDIR_WRITE]) || 605 (o->rate_iops[DDIR_TRIM] < o->rate_iops_min[DDIR_TRIM])) { 606 log_err("fio: minimum rate exceeds rate\n"); 607 ret = 1; 608 } 609 610 if (!o->timeout && o->time_based) { 611 log_err("fio: time_based requires a runtime/timeout setting\n"); 612 o->time_based = 0; 613 ret = warnings_fatal; 614 } 615 616 if (o->fill_device && !o->size) 617 o->size = -1ULL; 618 619 if (o->verify != VERIFY_NONE) { 620 if (td_write(td) && o->do_verify && o->numjobs > 1) { 621 log_info("Multiple writers may overwrite blocks that " 622 "belong to other jobs. This can cause " 623 "verification failures.\n"); 624 ret = warnings_fatal; 625 } 626 627 o->refill_buffers = 1; 628 if (o->max_bs[DDIR_WRITE] != o->min_bs[DDIR_WRITE] && 629 !o->verify_interval) 630 o->verify_interval = o->min_bs[DDIR_WRITE]; 631 } 632 633 if (o->pre_read) { 634 o->invalidate_cache = 0; 635 if (td->io_ops->flags & FIO_PIPEIO) { 636 log_info("fio: cannot pre-read files with an IO engine" 637 " that isn't seekable. Pre-read disabled.\n"); 638 ret = warnings_fatal; 639 } 640 } 641 642 if (!o->unit_base) { 643 if (td->io_ops->flags & FIO_BIT_BASED) 644 o->unit_base = 1; 645 else 646 o->unit_base = 8; 647 } 648 649#ifndef CONFIG_FDATASYNC 650 if (o->fdatasync_blocks) { 651 log_info("fio: this platform does not support fdatasync()" 652 " falling back to using fsync(). Use the 'fsync'" 653 " option instead of 'fdatasync' to get rid of" 654 " this warning\n"); 655 o->fsync_blocks = o->fdatasync_blocks; 656 o->fdatasync_blocks = 0; 657 ret = warnings_fatal; 658 } 659#endif 660 661#ifdef WIN32 662 /* 663 * Windows doesn't support O_DIRECT or O_SYNC with the _open interface, 664 * so fail if we're passed those flags 665 */ 666 if ((td->io_ops->flags & FIO_SYNCIO) && (td->o.odirect || td->o.sync_io)) { 667 log_err("fio: Windows does not support direct or non-buffered io with" 668 " the synchronous ioengines. Use the 'windowsaio' ioengine" 669 " with 'direct=1' and 'iodepth=1' instead.\n"); 670 ret = 1; 671 } 672#endif 673 674 /* 675 * For fully compressible data, just zero them at init time. 676 * It's faster than repeatedly filling it. 677 */ 678 if (td->o.compress_percentage == 100) { 679 td->o.zero_buffers = 1; 680 td->o.compress_percentage = 0; 681 } 682 683 /* 684 * Using a non-uniform random distribution excludes usage of 685 * a random map 686 */ 687 if (td->o.random_distribution != FIO_RAND_DIST_RANDOM) 688 td->o.norandommap = 1; 689 690 /* 691 * If size is set but less than the min block size, complain 692 */ 693 if (o->size && o->size < td_min_bs(td)) { 694 log_err("fio: size too small, must be larger than the IO size: %llu\n", (unsigned long long) o->size); 695 ret = 1; 696 } 697 698 /* 699 * O_ATOMIC implies O_DIRECT 700 */ 701 if (td->o.oatomic) 702 td->o.odirect = 1; 703 704 /* 705 * If randseed is set, that overrides randrepeat 706 */ 707 if (td->o.rand_seed) 708 td->o.rand_repeatable = 0; 709 710 if ((td->io_ops->flags & FIO_NOEXTEND) && td->o.file_append) { 711 log_err("fio: can't append/extent with IO engine %s\n", td->io_ops->name); 712 ret = 1; 713 } 714 715 return ret; 716} 717 718/* 719 * This function leaks the buffer 720 */ 721char *fio_uint_to_kmg(unsigned int val) 722{ 723 char *buf = malloc(32); 724 char post[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 }; 725 char *p = post; 726 727 do { 728 if (val & 1023) 729 break; 730 731 val >>= 10; 732 p++; 733 } while (*p); 734 735 snprintf(buf, 32, "%u%c", val, *p); 736 return buf; 737} 738 739/* External engines are specified by "external:name.o") */ 740static const char *get_engine_name(const char *str) 741{ 742 char *p = strstr(str, ":"); 743 744 if (!p) 745 return str; 746 747 p++; 748 strip_blank_front(&p); 749 strip_blank_end(p); 750 return p; 751} 752 753static int exists_and_not_file(const char *filename) 754{ 755 struct stat sb; 756 757 if (lstat(filename, &sb) == -1) 758 return 0; 759 760 /* \\.\ is the device namespace in Windows, where every file 761 * is a device node */ 762 if (S_ISREG(sb.st_mode) && strncmp(filename, "\\\\.\\", 4) != 0) 763 return 0; 764 765 return 1; 766} 767 768static void td_fill_rand_seeds_os(struct thread_data *td) 769{ 770 os_random_seed(td->rand_seeds[FIO_RAND_BS_OFF], &td->bsrange_state); 771 os_random_seed(td->rand_seeds[FIO_RAND_VER_OFF], &td->verify_state); 772 os_random_seed(td->rand_seeds[FIO_RAND_MIX_OFF], &td->rwmix_state); 773 774 if (td->o.file_service_type == FIO_FSERVICE_RANDOM) 775 os_random_seed(td->rand_seeds[FIO_RAND_FILE_OFF], &td->next_file_state); 776 777 os_random_seed(td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], &td->file_size_state); 778 os_random_seed(td->rand_seeds[FIO_RAND_TRIM_OFF], &td->trim_state); 779 os_random_seed(td->rand_seeds[FIO_RAND_START_DELAY], &td->delay_state); 780 781 if (!td_random(td)) 782 return; 783 784 if (td->o.rand_repeatable) 785 td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number; 786 787 os_random_seed(td->rand_seeds[FIO_RAND_BLOCK_OFF], &td->random_state); 788 789 os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF], &td->seq_rand_state[DDIR_READ]); 790 os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_WRITE_OFF], &td->seq_rand_state[DDIR_WRITE]); 791 os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_TRIM_OFF], &td->seq_rand_state[DDIR_TRIM]); 792} 793 794static void td_fill_rand_seeds_internal(struct thread_data *td) 795{ 796 init_rand_seed(&td->__bsrange_state, td->rand_seeds[FIO_RAND_BS_OFF]); 797 init_rand_seed(&td->__verify_state, td->rand_seeds[FIO_RAND_VER_OFF]); 798 init_rand_seed(&td->__rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF]); 799 800 if (td->o.file_service_type == FIO_FSERVICE_RANDOM) 801 init_rand_seed(&td->__next_file_state, td->rand_seeds[FIO_RAND_FILE_OFF]); 802 803 init_rand_seed(&td->__file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF]); 804 init_rand_seed(&td->__trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF]); 805 init_rand_seed(&td->__delay_state, td->rand_seeds[FIO_RAND_START_DELAY]); 806 807 if (!td_random(td)) 808 return; 809 810 if (td->o.rand_repeatable) 811 td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number; 812 813 init_rand_seed(&td->__random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF]); 814 init_rand_seed(&td->__seq_rand_state[DDIR_READ], td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF]); 815 init_rand_seed(&td->__seq_rand_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_SEQ_RAND_WRITE_OFF]); 816 init_rand_seed(&td->__seq_rand_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_SEQ_RAND_TRIM_OFF]); 817} 818 819void td_fill_rand_seeds(struct thread_data *td) 820{ 821 if (td->o.allrand_repeatable) { 822 for (int i = 0; i < FIO_RAND_NR_OFFS; i++) 823 td->rand_seeds[i] = FIO_RANDSEED * td->thread_number 824 + i; 825 } 826 827 if (td->o.use_os_rand) 828 td_fill_rand_seeds_os(td); 829 else 830 td_fill_rand_seeds_internal(td); 831 832 init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF]); 833} 834 835/* 836 * Initializes the ioengine configured for a job, if it has not been done so 837 * already. 838 */ 839int ioengine_load(struct thread_data *td) 840{ 841 const char *engine; 842 843 /* 844 * Engine has already been loaded. 845 */ 846 if (td->io_ops) 847 return 0; 848 if (!td->o.ioengine) { 849 log_err("fio: internal fault, no IO engine specified\n"); 850 return 1; 851 } 852 853 engine = get_engine_name(td->o.ioengine); 854 td->io_ops = load_ioengine(td, engine); 855 if (!td->io_ops) { 856 log_err("fio: failed to load engine %s\n", engine); 857 return 1; 858 } 859 860 if (td->io_ops->option_struct_size && td->io_ops->options) { 861 /* 862 * In cases where td->eo is set, clone it for a child thread. 863 * This requires that the parent thread has the same ioengine, 864 * but that requirement must be enforced by the code which 865 * cloned the thread. 866 */ 867 void *origeo = td->eo; 868 /* 869 * Otherwise use the default thread options. 870 */ 871 if (!origeo && td != &def_thread && def_thread.eo && 872 def_thread.io_ops->options == td->io_ops->options) 873 origeo = def_thread.eo; 874 875 options_init(td->io_ops->options); 876 td->eo = malloc(td->io_ops->option_struct_size); 877 /* 878 * Use the default thread as an option template if this uses the 879 * same options structure and there are non-default options 880 * used. 881 */ 882 if (origeo) { 883 memcpy(td->eo, origeo, td->io_ops->option_struct_size); 884 options_mem_dupe(td->eo, td->io_ops->options); 885 } else { 886 memset(td->eo, 0, td->io_ops->option_struct_size); 887 fill_default_options(td->eo, td->io_ops->options); 888 } 889 *(struct thread_data **)td->eo = td; 890 } 891 892 return 0; 893} 894 895static void init_flags(struct thread_data *td) 896{ 897 struct thread_options *o = &td->o; 898 899 if (o->verify_backlog) 900 td->flags |= TD_F_VER_BACKLOG; 901 if (o->trim_backlog) 902 td->flags |= TD_F_TRIM_BACKLOG; 903 if (o->read_iolog_file) 904 td->flags |= TD_F_READ_IOLOG; 905 if (o->refill_buffers) 906 td->flags |= TD_F_REFILL_BUFFERS; 907 if (o->scramble_buffers) 908 td->flags |= TD_F_SCRAMBLE_BUFFERS; 909 if (o->verify != VERIFY_NONE) 910 td->flags |= TD_F_VER_NONE; 911} 912 913static int setup_random_seeds(struct thread_data *td) 914{ 915 unsigned long seed; 916 unsigned int i; 917 918 if (!td->o.rand_repeatable && !td->o.rand_seed) 919 return init_random_state(td, td->rand_seeds, sizeof(td->rand_seeds)); 920 921 if (!td->o.rand_seed) 922 seed = 0x89; 923 else 924 seed = td->o.rand_seed; 925 926 for (i = 0; i < 4; i++) 927 seed *= 0x9e370001UL; 928 929 for (i = 0; i < FIO_RAND_NR_OFFS; i++) { 930 td->rand_seeds[i] = seed; 931 seed *= 0x9e370001UL; 932 } 933 934 td_fill_rand_seeds(td); 935 return 0; 936} 937 938enum { 939 FPRE_NONE = 0, 940 FPRE_JOBNAME, 941 FPRE_JOBNUM, 942 FPRE_FILENUM 943}; 944 945static struct fpre_keyword { 946 const char *keyword; 947 size_t strlen; 948 int key; 949} fpre_keywords[] = { 950 { .keyword = "$jobname", .key = FPRE_JOBNAME, }, 951 { .keyword = "$jobnum", .key = FPRE_JOBNUM, }, 952 { .keyword = "$filenum", .key = FPRE_FILENUM, }, 953 { .keyword = NULL, }, 954 }; 955 956static char *make_filename(char *buf, size_t buf_size,struct thread_options *o, 957 const char *jobname, int jobnum, int filenum) 958{ 959 struct fpre_keyword *f; 960 char copy[PATH_MAX]; 961 size_t dst_left = PATH_MAX - 1; 962 963 if (!o->filename_format || !strlen(o->filename_format)) { 964 sprintf(buf, "%s.%d.%d", jobname, jobnum, filenum); 965 return NULL; 966 } 967 968 for (f = &fpre_keywords[0]; f->keyword; f++) 969 f->strlen = strlen(f->keyword); 970 971 buf[buf_size - 1] = '\0'; 972 strncpy(buf, o->filename_format, buf_size - 1); 973 974 memset(copy, 0, sizeof(copy)); 975 for (f = &fpre_keywords[0]; f->keyword; f++) { 976 do { 977 size_t pre_len, post_start = 0; 978 char *str, *dst = copy; 979 980 str = strcasestr(buf, f->keyword); 981 if (!str) 982 break; 983 984 pre_len = str - buf; 985 if (strlen(str) != f->strlen) 986 post_start = pre_len + f->strlen; 987 988 if (pre_len) { 989 strncpy(dst, buf, pre_len); 990 dst += pre_len; 991 dst_left -= pre_len; 992 } 993 994 switch (f->key) { 995 case FPRE_JOBNAME: { 996 int ret; 997 998 ret = snprintf(dst, dst_left, "%s", jobname); 999 if (ret < 0) 1000 break; 1001 dst += ret; 1002 dst_left -= ret; 1003 break; 1004 } 1005 case FPRE_JOBNUM: { 1006 int ret; 1007 1008 ret = snprintf(dst, dst_left, "%d", jobnum); 1009 if (ret < 0) 1010 break; 1011 dst += ret; 1012 dst_left -= ret; 1013 break; 1014 } 1015 case FPRE_FILENUM: { 1016 int ret; 1017 1018 ret = snprintf(dst, dst_left, "%d", filenum); 1019 if (ret < 0) 1020 break; 1021 dst += ret; 1022 dst_left -= ret; 1023 break; 1024 } 1025 default: 1026 assert(0); 1027 break; 1028 } 1029 1030 if (post_start) 1031 strncpy(dst, buf + post_start, dst_left); 1032 1033 strncpy(buf, copy, buf_size - 1); 1034 } while (1); 1035 } 1036 1037 return buf; 1038} 1039 1040int parse_dryrun(void) 1041{ 1042 return dump_cmdline || parse_only; 1043} 1044 1045/* 1046 * Adds a job to the list of things todo. Sanitizes the various options 1047 * to make sure we don't have conflicts, and initializes various 1048 * members of td. 1049 */ 1050static int add_job(struct thread_data *td, const char *jobname, int job_add_num, 1051 int recursed, int client_type) 1052{ 1053 unsigned int i; 1054 char fname[PATH_MAX]; 1055 int numjobs, file_alloced; 1056 struct thread_options *o = &td->o; 1057 char logname[PATH_MAX + 32]; 1058 1059 /* 1060 * the def_thread is just for options, it's not a real job 1061 */ 1062 if (td == &def_thread) 1063 return 0; 1064 1065 init_flags(td); 1066 1067 /* 1068 * if we are just dumping the output command line, don't add the job 1069 */ 1070 if (parse_dryrun()) { 1071 put_job(td); 1072 return 0; 1073 } 1074 1075 td->client_type = client_type; 1076 1077 if (profile_td_init(td)) 1078 goto err; 1079 1080 if (ioengine_load(td)) 1081 goto err; 1082 1083 if (o->odirect) 1084 td->io_ops->flags |= FIO_RAWIO; 1085 1086 file_alloced = 0; 1087 if (!o->filename && !td->files_index && !o->read_iolog_file) { 1088 file_alloced = 1; 1089 1090 if (o->nr_files == 1 && exists_and_not_file(jobname)) 1091 add_file(td, jobname, job_add_num, 0); 1092 else { 1093 for (i = 0; i < o->nr_files; i++) 1094 add_file(td, make_filename(fname, sizeof(fname), o, jobname, job_add_num, i), job_add_num, 0); 1095 } 1096 } 1097 1098 if (fixup_options(td)) 1099 goto err; 1100 1101 flow_init_job(td); 1102 1103 /* 1104 * IO engines only need this for option callbacks, and the address may 1105 * change in subprocesses. 1106 */ 1107 if (td->eo) 1108 *(struct thread_data **)td->eo = NULL; 1109 1110 if (td->io_ops->flags & FIO_DISKLESSIO) { 1111 struct fio_file *f; 1112 1113 for_each_file(td, f, i) 1114 f->real_file_size = -1ULL; 1115 } 1116 1117 td->mutex = fio_mutex_init(FIO_MUTEX_LOCKED); 1118 1119 td->ts.clat_percentiles = o->clat_percentiles; 1120 td->ts.percentile_precision = o->percentile_precision; 1121 memcpy(td->ts.percentile_list, o->percentile_list, sizeof(o->percentile_list)); 1122 1123 for (i = 0; i < DDIR_RWDIR_CNT; i++) { 1124 td->ts.clat_stat[i].min_val = ULONG_MAX; 1125 td->ts.slat_stat[i].min_val = ULONG_MAX; 1126 td->ts.lat_stat[i].min_val = ULONG_MAX; 1127 td->ts.bw_stat[i].min_val = ULONG_MAX; 1128 } 1129 td->ddir_seq_nr = o->ddir_seq_nr; 1130 1131 if ((o->stonewall || o->new_group) && prev_group_jobs) { 1132 prev_group_jobs = 0; 1133 groupid++; 1134 } 1135 1136 td->groupid = groupid; 1137 prev_group_jobs++; 1138 1139 if (setup_random_seeds(td)) { 1140 td_verror(td, errno, "init_random_state"); 1141 goto err; 1142 } 1143 1144 if (setup_rate(td)) 1145 goto err; 1146 1147 if (o->lat_log_file) { 1148 struct log_params p = { 1149 .td = td, 1150 .avg_msec = o->log_avg_msec, 1151 .log_type = IO_LOG_TYPE_LAT, 1152 .log_offset = o->log_offset, 1153 .log_gz = o->log_gz, 1154 }; 1155 1156 snprintf(logname, sizeof(logname), "%s_lat.log", 1157 o->lat_log_file); 1158 setup_log(&td->lat_log, &p, logname); 1159 snprintf(logname, sizeof(logname), "%s_slat.log", 1160 o->lat_log_file); 1161 setup_log(&td->slat_log, &p, logname); 1162 snprintf(logname, sizeof(logname), "%s_clat.log", 1163 o->lat_log_file); 1164 setup_log(&td->clat_log, &p, logname); 1165 } 1166 if (o->bw_log_file) { 1167 struct log_params p = { 1168 .td = td, 1169 .avg_msec = o->log_avg_msec, 1170 .log_type = IO_LOG_TYPE_BW, 1171 .log_offset = o->log_offset, 1172 .log_gz = o->log_gz, 1173 }; 1174 1175 snprintf(logname, sizeof(logname), "%s_bw.log", 1176 o->bw_log_file); 1177 setup_log(&td->bw_log, &p, logname); 1178 } 1179 if (o->iops_log_file) { 1180 struct log_params p = { 1181 .td = td, 1182 .avg_msec = o->log_avg_msec, 1183 .log_type = IO_LOG_TYPE_IOPS, 1184 .log_offset = o->log_offset, 1185 .log_gz = o->log_gz, 1186 }; 1187 1188 snprintf(logname, sizeof(logname), "%s_iops.log", 1189 o->iops_log_file); 1190 setup_log(&td->iops_log, &p, logname); 1191 } 1192 1193 if (!o->name) 1194 o->name = strdup(jobname); 1195 1196 if (output_format == FIO_OUTPUT_NORMAL) { 1197 if (!job_add_num) { 1198 if (is_backend && !recursed) 1199 fio_server_send_add_job(td); 1200 1201 if (!(td->io_ops->flags & FIO_NOIO)) { 1202 char *c1, *c2, *c3, *c4; 1203 char *c5 = NULL, *c6 = NULL; 1204 1205 c1 = fio_uint_to_kmg(o->min_bs[DDIR_READ]); 1206 c2 = fio_uint_to_kmg(o->max_bs[DDIR_READ]); 1207 c3 = fio_uint_to_kmg(o->min_bs[DDIR_WRITE]); 1208 c4 = fio_uint_to_kmg(o->max_bs[DDIR_WRITE]); 1209 1210 if (!o->bs_is_seq_rand) { 1211 c5 = fio_uint_to_kmg(o->min_bs[DDIR_TRIM]); 1212 c6 = fio_uint_to_kmg(o->max_bs[DDIR_TRIM]); 1213 } 1214 1215 log_info("%s: (g=%d): rw=%s, ", td->o.name, 1216 td->groupid, 1217 ddir_str(o->td_ddir)); 1218 1219 if (o->bs_is_seq_rand) 1220 log_info("bs(seq/rand)=%s-%s/%s-%s, ", 1221 c1, c2, c3, c4); 1222 else 1223 log_info("bs=%s-%s/%s-%s/%s-%s, ", 1224 c1, c2, c3, c4, c5, c6); 1225 1226 log_info("ioengine=%s, iodepth=%u\n", 1227 td->io_ops->name, o->iodepth); 1228 1229 free(c1); 1230 free(c2); 1231 free(c3); 1232 free(c4); 1233 free(c5); 1234 free(c6); 1235 } 1236 } else if (job_add_num == 1) 1237 log_info("...\n"); 1238 } 1239 1240 /* 1241 * recurse add identical jobs, clear numjobs and stonewall options 1242 * as they don't apply to sub-jobs 1243 */ 1244 numjobs = o->numjobs; 1245 while (--numjobs) { 1246 struct thread_data *td_new = get_new_job(0, td, 1, jobname); 1247 1248 if (!td_new) 1249 goto err; 1250 1251 td_new->o.numjobs = 1; 1252 td_new->o.stonewall = 0; 1253 td_new->o.new_group = 0; 1254 1255 if (file_alloced) { 1256 if (td_new->files) { 1257 struct fio_file *f; 1258 for_each_file(td_new, f, i) { 1259 if (f->file_name) 1260 sfree(f->file_name); 1261 sfree(f); 1262 } 1263 free(td_new->files); 1264 td_new->files = NULL; 1265 } 1266 td_new->files_index = 0; 1267 td_new->files_size = 0; 1268 if (td_new->o.filename) { 1269 free(td_new->o.filename); 1270 td_new->o.filename = NULL; 1271 } 1272 } 1273 1274 if (add_job(td_new, jobname, numjobs, 1, client_type)) 1275 goto err; 1276 } 1277 1278 return 0; 1279err: 1280 put_job(td); 1281 return -1; 1282} 1283 1284/* 1285 * Parse as if 'o' was a command line 1286 */ 1287void add_job_opts(const char **o, int client_type) 1288{ 1289 struct thread_data *td, *td_parent; 1290 int i, in_global = 1; 1291 char jobname[32]; 1292 1293 i = 0; 1294 td_parent = td = NULL; 1295 while (o[i]) { 1296 if (!strncmp(o[i], "name", 4)) { 1297 in_global = 0; 1298 if (td) 1299 add_job(td, jobname, 0, 0, client_type); 1300 td = NULL; 1301 sprintf(jobname, "%s", o[i] + 5); 1302 } 1303 if (in_global && !td_parent) 1304 td_parent = get_new_job(1, &def_thread, 0, jobname); 1305 else if (!in_global && !td) { 1306 if (!td_parent) 1307 td_parent = &def_thread; 1308 td = get_new_job(0, td_parent, 0, jobname); 1309 } 1310 if (in_global) 1311 fio_options_parse(td_parent, (char **) &o[i], 1, 0); 1312 else 1313 fio_options_parse(td, (char **) &o[i], 1, 0); 1314 i++; 1315 } 1316 1317 if (td) 1318 add_job(td, jobname, 0, 0, client_type); 1319} 1320 1321static int skip_this_section(const char *name) 1322{ 1323 int i; 1324 1325 if (!nr_job_sections) 1326 return 0; 1327 if (!strncmp(name, "global", 6)) 1328 return 0; 1329 1330 for (i = 0; i < nr_job_sections; i++) 1331 if (!strcmp(job_sections[i], name)) 1332 return 0; 1333 1334 return 1; 1335} 1336 1337static int is_empty_or_comment(char *line) 1338{ 1339 unsigned int i; 1340 1341 for (i = 0; i < strlen(line); i++) { 1342 if (line[i] == ';') 1343 return 1; 1344 if (line[i] == '#') 1345 return 1; 1346 if (!isspace((int) line[i]) && !iscntrl((int) line[i])) 1347 return 0; 1348 } 1349 1350 return 1; 1351} 1352 1353/* 1354 * This is our [ini] type file parser. 1355 */ 1356int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type) 1357{ 1358 unsigned int global; 1359 struct thread_data *td; 1360 char *string, *name; 1361 FILE *f; 1362 char *p; 1363 int ret = 0, stonewall; 1364 int first_sect = 1; 1365 int skip_fgets = 0; 1366 int inside_skip = 0; 1367 char **opts; 1368 int i, alloc_opts, num_opts; 1369 1370 if (is_buf) 1371 f = NULL; 1372 else { 1373 if (!strcmp(file, "-")) 1374 f = stdin; 1375 else 1376 f = fopen(file, "r"); 1377 1378 if (!f) { 1379 perror("fopen job file"); 1380 return 1; 1381 } 1382 } 1383 1384 string = malloc(4096); 1385 1386 /* 1387 * it's really 256 + small bit, 280 should suffice 1388 */ 1389 name = malloc(280); 1390 memset(name, 0, 280); 1391 1392 alloc_opts = 8; 1393 opts = malloc(sizeof(char *) * alloc_opts); 1394 num_opts = 0; 1395 1396 stonewall = stonewall_flag; 1397 do { 1398 /* 1399 * if skip_fgets is set, we already have loaded a line we 1400 * haven't handled. 1401 */ 1402 if (!skip_fgets) { 1403 if (is_buf) 1404 p = strsep(&file, "\n"); 1405 else 1406 p = fgets(string, 4096, f); 1407 if (!p) 1408 break; 1409 } 1410 1411 skip_fgets = 0; 1412 strip_blank_front(&p); 1413 strip_blank_end(p); 1414 1415 if (is_empty_or_comment(p)) 1416 continue; 1417 if (sscanf(p, "[%255[^\n]]", name) != 1) { 1418 if (inside_skip) 1419 continue; 1420 log_err("fio: option <%s> outside of [] job section\n", 1421 p); 1422 break; 1423 } 1424 1425 name[strlen(name) - 1] = '\0'; 1426 1427 if (skip_this_section(name)) { 1428 inside_skip = 1; 1429 continue; 1430 } else 1431 inside_skip = 0; 1432 1433 global = !strncmp(name, "global", 6); 1434 1435 if (dump_cmdline) { 1436 if (first_sect) 1437 log_info("fio "); 1438 if (!global) 1439 log_info("--name=%s ", name); 1440 first_sect = 0; 1441 } 1442 1443 td = get_new_job(global, &def_thread, 0, name); 1444 if (!td) { 1445 ret = 1; 1446 break; 1447 } 1448 1449 /* 1450 * Separate multiple job files by a stonewall 1451 */ 1452 if (!global && stonewall) { 1453 td->o.stonewall = stonewall; 1454 stonewall = 0; 1455 } 1456 1457 num_opts = 0; 1458 memset(opts, 0, alloc_opts * sizeof(char *)); 1459 1460 while (1) { 1461 if (is_buf) 1462 p = strsep(&file, "\n"); 1463 else 1464 p = fgets(string, 4096, f); 1465 if (!p) 1466 break; 1467 1468 if (is_empty_or_comment(p)) 1469 continue; 1470 1471 strip_blank_front(&p); 1472 1473 /* 1474 * new section, break out and make sure we don't 1475 * fgets() a new line at the top. 1476 */ 1477 if (p[0] == '[') { 1478 skip_fgets = 1; 1479 break; 1480 } 1481 1482 strip_blank_end(p); 1483 1484 if (num_opts == alloc_opts) { 1485 alloc_opts <<= 1; 1486 opts = realloc(opts, 1487 alloc_opts * sizeof(char *)); 1488 } 1489 1490 opts[num_opts] = strdup(p); 1491 num_opts++; 1492 } 1493 1494 ret = fio_options_parse(td, opts, num_opts, dump_cmdline); 1495 if (!ret) 1496 ret = add_job(td, name, 0, 0, type); 1497 else { 1498 log_err("fio: job %s dropped\n", name); 1499 put_job(td); 1500 } 1501 1502 for (i = 0; i < num_opts; i++) 1503 free(opts[i]); 1504 num_opts = 0; 1505 } while (!ret); 1506 1507 if (dump_cmdline) 1508 log_info("\n"); 1509 1510 i = 0; 1511 while (i < nr_job_sections) { 1512 free(job_sections[i]); 1513 i++; 1514 } 1515 1516 free(string); 1517 free(name); 1518 free(opts); 1519 if (!is_buf && f != stdin) 1520 fclose(f); 1521 return ret; 1522} 1523 1524static int fill_def_thread(void) 1525{ 1526 memset(&def_thread, 0, sizeof(def_thread)); 1527 1528 fio_getaffinity(getpid(), &def_thread.o.cpumask); 1529 def_thread.o.error_dump = 1; 1530 1531 /* 1532 * fill default options 1533 */ 1534 fio_fill_default_options(&def_thread); 1535 return 0; 1536} 1537 1538static void usage(const char *name) 1539{ 1540 printf("%s\n", fio_version_string); 1541 printf("%s [options] [job options] <job file(s)>\n", name); 1542 printf(" --debug=options\tEnable debug logging. May be one/more of:\n" 1543 "\t\t\tprocess,file,io,mem,blktrace,verify,random,parse,\n" 1544 "\t\t\tdiskutil,job,mutex,profile,time,net,rate\n"); 1545 printf(" --parse-only\t\tParse options only, don't start any IO\n"); 1546 printf(" --output\t\tWrite output to file\n"); 1547 printf(" --runtime\t\tRuntime in seconds\n"); 1548 printf(" --bandwidth-log\tGenerate per-job bandwidth logs\n"); 1549 printf(" --minimal\t\tMinimal (terse) output\n"); 1550 printf(" --output-format=x\tOutput format (terse,json,normal)\n"); 1551 printf(" --terse-version=x\tSet terse version output format to 'x'\n"); 1552 printf(" --version\t\tPrint version info and exit\n"); 1553 printf(" --help\t\tPrint this page\n"); 1554 printf(" --cpuclock-test\tPerform test/validation of CPU clock\n"); 1555 printf(" --crctest\t\tTest speed of checksum functions\n"); 1556 printf(" --cmdhelp=cmd\t\tPrint command help, \"all\" for all of" 1557 " them\n"); 1558 printf(" --enghelp=engine\tPrint ioengine help, or list" 1559 " available ioengines\n"); 1560 printf(" --enghelp=engine,cmd\tPrint help for an ioengine" 1561 " cmd\n"); 1562 printf(" --showcmd\t\tTurn a job file into command line options\n"); 1563 printf(" --eta=when\t\tWhen ETA estimate should be printed\n"); 1564 printf(" \t\tMay be \"always\", \"never\" or \"auto\"\n"); 1565 printf(" --eta-newline=time\tForce a new line for every 'time'"); 1566 printf(" period passed\n"); 1567 printf(" --status-interval=t\tForce full status dump every"); 1568 printf(" 't' period passed\n"); 1569 printf(" --readonly\t\tTurn on safety read-only checks, preventing" 1570 " writes\n"); 1571 printf(" --section=name\tOnly run specified section in job file\n"); 1572 printf(" --alloc-size=kb\tSet smalloc pool to this size in kb" 1573 " (def 1024)\n"); 1574 printf(" --warnings-fatal\tFio parser warnings are fatal\n"); 1575 printf(" --max-jobs=nr\t\tMaximum number of threads/processes to support\n"); 1576 printf(" --server=args\t\tStart a backend fio server\n"); 1577 printf(" --daemonize=pidfile\tBackground fio server, write pid to file\n"); 1578 printf(" --client=hostname\tTalk to remote backend fio server at hostname\n"); 1579 printf(" --idle-prof=option\tReport cpu idleness on a system or percpu basis\n" 1580 "\t\t\t(option=system,percpu) or run unit work\n" 1581 "\t\t\tcalibration only (option=calibrate)\n"); 1582 printf("\nFio was written by Jens Axboe <jens.axboe@oracle.com>"); 1583 printf("\n Jens Axboe <jaxboe@fusionio.com>"); 1584 printf("\n Jens Axboe <axboe@fb.com>\n"); 1585} 1586 1587#ifdef FIO_INC_DEBUG 1588struct debug_level debug_levels[] = { 1589 { .name = "process", 1590 .help = "Process creation/exit logging", 1591 .shift = FD_PROCESS, 1592 }, 1593 { .name = "file", 1594 .help = "File related action logging", 1595 .shift = FD_FILE, 1596 }, 1597 { .name = "io", 1598 .help = "IO and IO engine action logging (offsets, queue, completions, etc)", 1599 .shift = FD_IO, 1600 }, 1601 { .name = "mem", 1602 .help = "Memory allocation/freeing logging", 1603 .shift = FD_MEM, 1604 }, 1605 { .name = "blktrace", 1606 .help = "blktrace action logging", 1607 .shift = FD_BLKTRACE, 1608 }, 1609 { .name = "verify", 1610 .help = "IO verification action logging", 1611 .shift = FD_VERIFY, 1612 }, 1613 { .name = "random", 1614 .help = "Random generation logging", 1615 .shift = FD_RANDOM, 1616 }, 1617 { .name = "parse", 1618 .help = "Parser logging", 1619 .shift = FD_PARSE, 1620 }, 1621 { .name = "diskutil", 1622 .help = "Disk utility logging actions", 1623 .shift = FD_DISKUTIL, 1624 }, 1625 { .name = "job", 1626 .help = "Logging related to creating/destroying jobs", 1627 .shift = FD_JOB, 1628 }, 1629 { .name = "mutex", 1630 .help = "Mutex logging", 1631 .shift = FD_MUTEX 1632 }, 1633 { .name = "profile", 1634 .help = "Logging related to profiles", 1635 .shift = FD_PROFILE, 1636 }, 1637 { .name = "time", 1638 .help = "Logging related to time keeping functions", 1639 .shift = FD_TIME, 1640 }, 1641 { .name = "net", 1642 .help = "Network logging", 1643 .shift = FD_NET, 1644 }, 1645 { .name = "rate", 1646 .help = "Rate logging", 1647 .shift = FD_RATE, 1648 }, 1649 { .name = NULL, }, 1650}; 1651 1652static int set_debug(const char *string) 1653{ 1654 struct debug_level *dl; 1655 char *p = (char *) string; 1656 char *opt; 1657 int i; 1658 1659 if (!strcmp(string, "?") || !strcmp(string, "help")) { 1660 log_info("fio: dumping debug options:"); 1661 for (i = 0; debug_levels[i].name; i++) { 1662 dl = &debug_levels[i]; 1663 log_info("%s,", dl->name); 1664 } 1665 log_info("all\n"); 1666 return 1; 1667 } 1668 1669 while ((opt = strsep(&p, ",")) != NULL) { 1670 int found = 0; 1671 1672 if (!strncmp(opt, "all", 3)) { 1673 log_info("fio: set all debug options\n"); 1674 fio_debug = ~0UL; 1675 continue; 1676 } 1677 1678 for (i = 0; debug_levels[i].name; i++) { 1679 dl = &debug_levels[i]; 1680 found = !strncmp(opt, dl->name, strlen(dl->name)); 1681 if (!found) 1682 continue; 1683 1684 if (dl->shift == FD_JOB) { 1685 opt = strchr(opt, ':'); 1686 if (!opt) { 1687 log_err("fio: missing job number\n"); 1688 break; 1689 } 1690 opt++; 1691 fio_debug_jobno = atoi(opt); 1692 log_info("fio: set debug jobno %d\n", 1693 fio_debug_jobno); 1694 } else { 1695 log_info("fio: set debug option %s\n", opt); 1696 fio_debug |= (1UL << dl->shift); 1697 } 1698 break; 1699 } 1700 1701 if (!found) 1702 log_err("fio: debug mask %s not found\n", opt); 1703 } 1704 return 0; 1705} 1706#else 1707static int set_debug(const char *string) 1708{ 1709 log_err("fio: debug tracing not included in build\n"); 1710 return 1; 1711} 1712#endif 1713 1714static void fio_options_fill_optstring(void) 1715{ 1716 char *ostr = cmd_optstr; 1717 int i, c; 1718 1719 c = i = 0; 1720 while (l_opts[i].name) { 1721 ostr[c++] = l_opts[i].val; 1722 if (l_opts[i].has_arg == required_argument) 1723 ostr[c++] = ':'; 1724 else if (l_opts[i].has_arg == optional_argument) { 1725 ostr[c++] = ':'; 1726 ostr[c++] = ':'; 1727 } 1728 i++; 1729 } 1730 ostr[c] = '\0'; 1731} 1732 1733static int client_flag_set(char c) 1734{ 1735 int i; 1736 1737 i = 0; 1738 while (l_opts[i].name) { 1739 int val = l_opts[i].val; 1740 1741 if (c == (val & 0xff)) 1742 return (val & FIO_CLIENT_FLAG); 1743 1744 i++; 1745 } 1746 1747 return 0; 1748} 1749 1750static void parse_cmd_client(void *client, char *opt) 1751{ 1752 fio_client_add_cmd_option(client, opt); 1753} 1754 1755int parse_cmd_line(int argc, char *argv[], int client_type) 1756{ 1757 struct thread_data *td = NULL; 1758 int c, ini_idx = 0, lidx, ret = 0, do_exit = 0, exit_val = 0; 1759 char *ostr = cmd_optstr; 1760 void *pid_file = NULL; 1761 void *cur_client = NULL; 1762 int backend = 0; 1763 1764 /* 1765 * Reset optind handling, since we may call this multiple times 1766 * for the backend. 1767 */ 1768 optind = 1; 1769 1770 while ((c = getopt_long_only(argc, argv, ostr, l_opts, &lidx)) != -1) { 1771 if ((c & FIO_CLIENT_FLAG) || client_flag_set(c)) { 1772 parse_cmd_client(cur_client, argv[optind - 1]); 1773 c &= ~FIO_CLIENT_FLAG; 1774 } 1775 1776 switch (c) { 1777 case 'a': 1778 smalloc_pool_size = atoi(optarg); 1779 break; 1780 case 't': 1781 if (check_str_time(optarg, &def_timeout, 1)) { 1782 log_err("fio: failed parsing time %s\n", optarg); 1783 do_exit++; 1784 exit_val = 1; 1785 } 1786 break; 1787 case 'l': 1788 log_err("fio: --latency-log is deprecated. Use per-job latency log options.\n"); 1789 do_exit++; 1790 exit_val = 1; 1791 break; 1792 case 'b': 1793 write_bw_log = 1; 1794 break; 1795 case 'o': 1796 if (f_out && f_out != stdout) 1797 fclose(f_out); 1798 1799 f_out = fopen(optarg, "w+"); 1800 if (!f_out) { 1801 perror("fopen output"); 1802 exit(1); 1803 } 1804 f_err = f_out; 1805 break; 1806 case 'm': 1807 output_format = FIO_OUTPUT_TERSE; 1808 break; 1809 case 'F': 1810 if (!optarg) { 1811 log_err("fio: missing --output-format argument\n"); 1812 exit_val = 1; 1813 do_exit++; 1814 break; 1815 } 1816 if (!strcmp(optarg, "minimal") || 1817 !strcmp(optarg, "terse") || 1818 !strcmp(optarg, "csv")) 1819 output_format = FIO_OUTPUT_TERSE; 1820 else if (!strcmp(optarg, "json")) 1821 output_format = FIO_OUTPUT_JSON; 1822 else 1823 output_format = FIO_OUTPUT_NORMAL; 1824 break; 1825 case 'f': 1826 append_terse_output = 1; 1827 break; 1828 case 'h': 1829 did_arg = 1; 1830 if (!cur_client) { 1831 usage(argv[0]); 1832 do_exit++; 1833 } 1834 break; 1835 case 'c': 1836 did_arg = 1; 1837 if (!cur_client) { 1838 fio_show_option_help(optarg); 1839 do_exit++; 1840 } 1841 break; 1842 case 'i': 1843 did_arg = 1; 1844 if (!cur_client) { 1845 fio_show_ioengine_help(optarg); 1846 do_exit++; 1847 } 1848 break; 1849 case 's': 1850 did_arg = 1; 1851 dump_cmdline = 1; 1852 break; 1853 case 'r': 1854 read_only = 1; 1855 break; 1856 case 'v': 1857 did_arg = 1; 1858 if (!cur_client) { 1859 log_info("%s\n", fio_version_string); 1860 do_exit++; 1861 } 1862 break; 1863 case 'V': 1864 terse_version = atoi(optarg); 1865 if (!(terse_version == 2 || terse_version == 3 || 1866 terse_version == 4)) { 1867 log_err("fio: bad terse version format\n"); 1868 exit_val = 1; 1869 do_exit++; 1870 } 1871 break; 1872 case 'e': 1873 if (!strcmp("always", optarg)) 1874 eta_print = FIO_ETA_ALWAYS; 1875 else if (!strcmp("never", optarg)) 1876 eta_print = FIO_ETA_NEVER; 1877 break; 1878 case 'E': { 1879 long long t = 0; 1880 1881 if (str_to_decimal(optarg, &t, 0, NULL, 1)) { 1882 log_err("fio: failed parsing eta time %s\n", optarg); 1883 exit_val = 1; 1884 do_exit++; 1885 } 1886 eta_new_line = t; 1887 break; 1888 } 1889 case 'd': 1890 if (set_debug(optarg)) 1891 do_exit++; 1892 break; 1893 case 'P': 1894 did_arg = 1; 1895 parse_only = 1; 1896 break; 1897 case 'x': { 1898 size_t new_size; 1899 1900 if (!strcmp(optarg, "global")) { 1901 log_err("fio: can't use global as only " 1902 "section\n"); 1903 do_exit++; 1904 exit_val = 1; 1905 break; 1906 } 1907 new_size = (nr_job_sections + 1) * sizeof(char *); 1908 job_sections = realloc(job_sections, new_size); 1909 job_sections[nr_job_sections] = strdup(optarg); 1910 nr_job_sections++; 1911 break; 1912 } 1913 case 'p': 1914 did_arg = 1; 1915 if (exec_profile) 1916 free(exec_profile); 1917 exec_profile = strdup(optarg); 1918 break; 1919 case FIO_GETOPT_JOB: { 1920 const char *opt = l_opts[lidx].name; 1921 char *val = optarg; 1922 1923 if (!strncmp(opt, "name", 4) && td) { 1924 ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type); 1925 if (ret) 1926 goto out_free; 1927 td = NULL; 1928 did_arg = 1; 1929 } 1930 if (!td) { 1931 int is_section = !strncmp(opt, "name", 4); 1932 int global = 0; 1933 1934 if (!is_section || !strncmp(val, "global", 6)) 1935 global = 1; 1936 1937 if (is_section && skip_this_section(val)) 1938 continue; 1939 1940 td = get_new_job(global, &def_thread, 1, NULL); 1941 if (!td || ioengine_load(td)) { 1942 if (td) { 1943 put_job(td); 1944 td = NULL; 1945 } 1946 do_exit++; 1947 break; 1948 } 1949 fio_options_set_ioengine_opts(l_opts, td); 1950 } 1951 1952 if ((!val || !strlen(val)) && 1953 l_opts[lidx].has_arg == required_argument) { 1954 log_err("fio: option %s requires an argument\n", opt); 1955 ret = 1; 1956 } else 1957 ret = fio_cmd_option_parse(td, opt, val); 1958 1959 if (ret) { 1960 if (td) { 1961 put_job(td); 1962 td = NULL; 1963 } 1964 do_exit++; 1965 } 1966 1967 if (!ret && !strcmp(opt, "ioengine")) { 1968 free_ioengine(td); 1969 if (ioengine_load(td)) { 1970 if (td) { 1971 put_job(td); 1972 td = NULL; 1973 } 1974 do_exit++; 1975 break; 1976 } 1977 fio_options_set_ioengine_opts(l_opts, td); 1978 } 1979 break; 1980 } 1981 case FIO_GETOPT_IOENGINE: { 1982 const char *opt = l_opts[lidx].name; 1983 char *val = optarg; 1984 1985 if (!td) 1986 break; 1987 1988 ret = fio_cmd_ioengine_option_parse(td, opt, val); 1989 break; 1990 } 1991 case 'w': 1992 warnings_fatal = 1; 1993 break; 1994 case 'j': 1995 max_jobs = atoi(optarg); 1996 if (!max_jobs || max_jobs > REAL_MAX_JOBS) { 1997 log_err("fio: invalid max jobs: %d\n", max_jobs); 1998 do_exit++; 1999 exit_val = 1; 2000 } 2001 break; 2002 case 'S': 2003 did_arg = 1; 2004#ifndef CONFIG_NO_SHM 2005 if (nr_clients) { 2006 log_err("fio: can't be both client and server\n"); 2007 do_exit++; 2008 exit_val = 1; 2009 break; 2010 } 2011 if (optarg) 2012 fio_server_set_arg(optarg); 2013 is_backend = 1; 2014 backend = 1; 2015#else 2016 log_err("fio: client/server requires SHM support\n"); 2017 do_exit++; 2018 exit_val = 1; 2019#endif 2020 break; 2021 case 'D': 2022 if (pid_file) 2023 free(pid_file); 2024 pid_file = strdup(optarg); 2025 break; 2026 case 'I': 2027 if ((ret = fio_idle_prof_parse_opt(optarg))) { 2028 /* exit on error and calibration only */ 2029 did_arg = 1; 2030 do_exit++; 2031 if (ret == -1) 2032 exit_val = 1; 2033 } 2034 break; 2035 case 'C': 2036 did_arg = 1; 2037 if (is_backend) { 2038 log_err("fio: can't be both client and server\n"); 2039 do_exit++; 2040 exit_val = 1; 2041 break; 2042 } 2043 if (fio_client_add(&fio_client_ops, optarg, &cur_client)) { 2044 log_err("fio: failed adding client %s\n", optarg); 2045 do_exit++; 2046 exit_val = 1; 2047 break; 2048 } 2049 /* 2050 * If the next argument exists and isn't an option, 2051 * assume it's a job file for this client only. 2052 */ 2053 while (optind < argc) { 2054 if (!strncmp(argv[optind], "--", 2) || 2055 !strncmp(argv[optind], "-", 1)) 2056 break; 2057 2058 fio_client_add_ini_file(cur_client, argv[optind]); 2059 optind++; 2060 } 2061 break; 2062 case 'T': 2063 did_arg = 1; 2064 do_exit++; 2065 exit_val = fio_monotonic_clocktest(); 2066 break; 2067 case 'G': 2068 did_arg = 1; 2069 do_exit++; 2070 exit_val = fio_crctest(optarg); 2071 break; 2072 case 'L': { 2073 long long val; 2074 2075 if (check_str_time(optarg, &val, 0)) { 2076 log_err("fio: failed parsing time %s\n", optarg); 2077 do_exit++; 2078 exit_val = 1; 2079 break; 2080 } 2081 status_interval = val * 1000; 2082 break; 2083 } 2084 case '?': 2085 log_err("%s: unrecognized option '%s'\n", argv[0], 2086 argv[optind - 1]); 2087 default: 2088 do_exit++; 2089 exit_val = 1; 2090 break; 2091 } 2092 if (do_exit) 2093 break; 2094 } 2095 2096 if (do_exit && !(is_backend || nr_clients)) 2097 exit(exit_val); 2098 2099 if (nr_clients && fio_clients_connect()) 2100 exit(1); 2101 2102 if (is_backend && backend) 2103 return fio_start_server(pid_file); 2104 else if (pid_file) 2105 free(pid_file); 2106 2107 if (td) { 2108 if (!ret) { 2109 ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type); 2110 if (ret) 2111 did_arg = 1; 2112 } 2113 } 2114 2115 while (!ret && optind < argc) { 2116 ini_idx++; 2117 ini_file = realloc(ini_file, ini_idx * sizeof(char *)); 2118 ini_file[ini_idx - 1] = strdup(argv[optind]); 2119 optind++; 2120 } 2121 2122out_free: 2123 if (pid_file) 2124 free(pid_file); 2125 2126 return ini_idx; 2127} 2128 2129int fio_init_options(void) 2130{ 2131 f_out = stdout; 2132 f_err = stderr; 2133 2134 fio_options_fill_optstring(); 2135 fio_options_dup_and_init(l_opts); 2136 2137 atexit(free_shm); 2138 2139 if (fill_def_thread()) 2140 return 1; 2141 2142 return 0; 2143} 2144 2145extern int fio_check_options(struct thread_options *); 2146 2147int parse_options(int argc, char *argv[]) 2148{ 2149 const int type = FIO_CLIENT_TYPE_CLI; 2150 int job_files, i; 2151 2152 if (fio_init_options()) 2153 return 1; 2154 if (fio_test_cconv(&def_thread.o)) 2155 log_err("fio: failed internal cconv test\n"); 2156 2157 job_files = parse_cmd_line(argc, argv, type); 2158 2159 if (job_files > 0) { 2160 for (i = 0; i < job_files; i++) { 2161 if (i && fill_def_thread()) 2162 return 1; 2163 if (nr_clients) { 2164 if (fio_clients_send_ini(ini_file[i])) 2165 return 1; 2166 free(ini_file[i]); 2167 } else if (!is_backend) { 2168 if (parse_jobs_ini(ini_file[i], 0, i, type)) 2169 return 1; 2170 free(ini_file[i]); 2171 } 2172 } 2173 } else if (nr_clients) { 2174 if (fill_def_thread()) 2175 return 1; 2176 if (fio_clients_send_ini(NULL)) 2177 return 1; 2178 } 2179 2180 free(ini_file); 2181 fio_options_free(&def_thread); 2182 filesetup_mem_free(); 2183 2184 if (!thread_number) { 2185 if (parse_dryrun()) 2186 return 0; 2187 if (exec_profile) 2188 return 0; 2189 if (is_backend || nr_clients) 2190 return 0; 2191 if (did_arg) 2192 return 0; 2193 2194 log_err("No jobs(s) defined\n\n"); 2195 2196 if (!did_arg) { 2197 usage(argv[0]); 2198 return 1; 2199 } 2200 2201 return 0; 2202 } 2203 2204 if (def_thread.o.gtod_offload) { 2205 fio_gtod_init(); 2206 fio_gtod_offload = 1; 2207 fio_gtod_cpu = def_thread.o.gtod_cpu; 2208 } 2209 2210 if (output_format == FIO_OUTPUT_NORMAL) 2211 log_info("%s\n", fio_version_string); 2212 2213 return 0; 2214} 2215 2216void options_default_fill(struct thread_options *o) 2217{ 2218 memcpy(o, &def_thread.o, sizeof(*o)); 2219} 2220