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