options.c revision b463e9363b826d5ba4f16e0115a26f24b77078f4
1#include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <ctype.h> 5#include <string.h> 6#include <assert.h> 7#include <libgen.h> 8#include <fcntl.h> 9#include <sys/types.h> 10#include <sys/stat.h> 11 12#include "fio.h" 13#include "verify.h" 14#include "parse.h" 15#include "lib/fls.h" 16#include "options.h" 17 18#include "crc/crc32c.h" 19 20/* 21 * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that. 22 */ 23static char *get_opt_postfix(const char *str) 24{ 25 char *p = strstr(str, ":"); 26 27 if (!p) 28 return NULL; 29 30 p++; 31 strip_blank_front(&p); 32 strip_blank_end(p); 33 return strdup(p); 34} 35 36static int converthexchartoint(char a) 37{ 38 int base; 39 40 switch(a) { 41 case '0'...'9': 42 base = '0'; 43 break; 44 case 'A'...'F': 45 base = 'A' - 10; 46 break; 47 case 'a'...'f': 48 base = 'a' - 10; 49 break; 50 default: 51 base = 0; 52 } 53 return (a - base); 54} 55 56static int bs_cmp(const void *p1, const void *p2) 57{ 58 const struct bssplit *bsp1 = p1; 59 const struct bssplit *bsp2 = p2; 60 61 return bsp1->perc < bsp2->perc; 62} 63 64static int bssplit_ddir(struct thread_data *td, int ddir, char *str) 65{ 66 struct bssplit *bssplit; 67 unsigned int i, perc, perc_missing; 68 unsigned int max_bs, min_bs; 69 long long val; 70 char *fname; 71 72 td->o.bssplit_nr[ddir] = 4; 73 bssplit = malloc(4 * sizeof(struct bssplit)); 74 75 i = 0; 76 max_bs = 0; 77 min_bs = -1; 78 while ((fname = strsep(&str, ":")) != NULL) { 79 char *perc_str; 80 81 if (!strlen(fname)) 82 break; 83 84 /* 85 * grow struct buffer, if needed 86 */ 87 if (i == td->o.bssplit_nr[ddir]) { 88 td->o.bssplit_nr[ddir] <<= 1; 89 bssplit = realloc(bssplit, td->o.bssplit_nr[ddir] 90 * sizeof(struct bssplit)); 91 } 92 93 perc_str = strstr(fname, "/"); 94 if (perc_str) { 95 *perc_str = '\0'; 96 perc_str++; 97 perc = atoi(perc_str); 98 if (perc > 100) 99 perc = 100; 100 else if (!perc) 101 perc = -1; 102 } else 103 perc = -1; 104 105 if (str_to_decimal(fname, &val, 1, td)) { 106 log_err("fio: bssplit conversion failed\n"); 107 free(td->o.bssplit); 108 return 1; 109 } 110 111 if (val > max_bs) 112 max_bs = val; 113 if (val < min_bs) 114 min_bs = val; 115 116 bssplit[i].bs = val; 117 bssplit[i].perc = perc; 118 i++; 119 } 120 121 td->o.bssplit_nr[ddir] = i; 122 123 /* 124 * Now check if the percentages add up, and how much is missing 125 */ 126 perc = perc_missing = 0; 127 for (i = 0; i < td->o.bssplit_nr[ddir]; i++) { 128 struct bssplit *bsp = &bssplit[i]; 129 130 if (bsp->perc == (unsigned char) -1) 131 perc_missing++; 132 else 133 perc += bsp->perc; 134 } 135 136 if (perc > 100) { 137 log_err("fio: bssplit percentages add to more than 100%%\n"); 138 free(bssplit); 139 return 1; 140 } 141 /* 142 * If values didn't have a percentage set, divide the remains between 143 * them. 144 */ 145 if (perc_missing) { 146 for (i = 0; i < td->o.bssplit_nr[ddir]; i++) { 147 struct bssplit *bsp = &bssplit[i]; 148 149 if (bsp->perc == (unsigned char) -1) 150 bsp->perc = (100 - perc) / perc_missing; 151 } 152 } 153 154 td->o.min_bs[ddir] = min_bs; 155 td->o.max_bs[ddir] = max_bs; 156 157 /* 158 * now sort based on percentages, for ease of lookup 159 */ 160 qsort(bssplit, td->o.bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp); 161 td->o.bssplit[ddir] = bssplit; 162 return 0; 163 164} 165 166static int str_bssplit_cb(void *data, const char *input) 167{ 168 struct thread_data *td = data; 169 char *str, *p, *odir; 170 int ret = 0; 171 172 p = str = strdup(input); 173 174 strip_blank_front(&str); 175 strip_blank_end(str); 176 177 odir = strchr(str, ','); 178 if (odir) { 179 ret = bssplit_ddir(td, DDIR_WRITE, odir + 1); 180 if (!ret) { 181 *odir = '\0'; 182 ret = bssplit_ddir(td, DDIR_READ, str); 183 } 184 } else { 185 char *op; 186 187 op = strdup(str); 188 189 ret = bssplit_ddir(td, DDIR_READ, str); 190 if (!ret) 191 ret = bssplit_ddir(td, DDIR_WRITE, op); 192 193 free(op); 194 } 195 196 free(p); 197 return ret; 198} 199 200static int str_rw_cb(void *data, const char *str) 201{ 202 struct thread_data *td = data; 203 char *nr = get_opt_postfix(str); 204 205 td->o.ddir_seq_nr = 1; 206 if (nr) { 207 td->o.ddir_seq_nr = atoi(nr); 208 free(nr); 209 } 210 211 return 0; 212} 213 214static int str_mem_cb(void *data, const char *mem) 215{ 216 struct thread_data *td = data; 217 218 if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP) { 219 td->mmapfile = get_opt_postfix(mem); 220 if (td->o.mem_type == MEM_MMAPHUGE && !td->mmapfile) { 221 log_err("fio: mmaphuge:/path/to/file\n"); 222 return 1; 223 } 224 } 225 226 return 0; 227} 228 229static int str_verify_cb(void *data, const char *mem) 230{ 231 struct thread_data *td = data; 232 233 if (td->o.verify != VERIFY_CRC32C_INTEL) 234 return 0; 235 236 if (!crc32c_intel_works()) { 237 log_info("fio: System does not support hw accelerated crc32c. Falling back to sw crc32c.\n"); 238 td->o.verify = VERIFY_CRC32C; 239 } 240 241 return 0; 242} 243 244static int fio_clock_source_cb(void *data, const char *str) 245{ 246 struct thread_data *td = data; 247 248 fio_clock_source = td->o.clocksource; 249 fio_time_init(); 250 return 0; 251} 252 253static int str_lockmem_cb(void fio_unused *data, unsigned long long *val) 254{ 255 mlock_size = *val; 256 return 0; 257} 258 259static int str_rwmix_read_cb(void *data, unsigned long long *val) 260{ 261 struct thread_data *td = data; 262 263 td->o.rwmix[DDIR_READ] = *val; 264 td->o.rwmix[DDIR_WRITE] = 100 - *val; 265 return 0; 266} 267 268static int str_rwmix_write_cb(void *data, unsigned long long *val) 269{ 270 struct thread_data *td = data; 271 272 td->o.rwmix[DDIR_WRITE] = *val; 273 td->o.rwmix[DDIR_READ] = 100 - *val; 274 return 0; 275} 276 277#ifdef FIO_HAVE_IOPRIO 278static int str_prioclass_cb(void *data, unsigned long long *val) 279{ 280 struct thread_data *td = data; 281 unsigned short mask; 282 283 /* 284 * mask off old class bits, str_prio_cb() may have set a default class 285 */ 286 mask = (1 << IOPRIO_CLASS_SHIFT) - 1; 287 td->ioprio &= mask; 288 289 td->ioprio |= *val << IOPRIO_CLASS_SHIFT; 290 td->ioprio_set = 1; 291 return 0; 292} 293 294static int str_prio_cb(void *data, unsigned long long *val) 295{ 296 struct thread_data *td = data; 297 298 td->ioprio |= *val; 299 300 /* 301 * If no class is set, assume BE 302 */ 303 if ((td->ioprio >> IOPRIO_CLASS_SHIFT) == 0) 304 td->ioprio |= IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT; 305 306 td->ioprio_set = 1; 307 return 0; 308} 309#endif 310 311static int str_exitall_cb(void) 312{ 313 exitall_on_terminate = 1; 314 return 0; 315} 316 317#ifdef FIO_HAVE_CPU_AFFINITY 318static int str_cpumask_cb(void *data, unsigned long long *val) 319{ 320 struct thread_data *td = data; 321 unsigned int i; 322 long max_cpu; 323 int ret; 324 325 ret = fio_cpuset_init(&td->o.cpumask); 326 if (ret < 0) { 327 log_err("fio: cpuset_init failed\n"); 328 td_verror(td, ret, "fio_cpuset_init"); 329 return 1; 330 } 331 332 max_cpu = sysconf(_SC_NPROCESSORS_ONLN); 333 334 for (i = 0; i < sizeof(int) * 8; i++) { 335 if ((1 << i) & *val) { 336 if (i > max_cpu) { 337 log_err("fio: CPU %d too large (max=%ld)\n", i, 338 max_cpu); 339 return 1; 340 } 341 dprint(FD_PARSE, "set cpu allowed %d\n", i); 342 fio_cpu_set(&td->o.cpumask, i); 343 } 344 } 345 346 td->o.cpumask_set = 1; 347 return 0; 348} 349 350static int set_cpus_allowed(struct thread_data *td, os_cpu_mask_t *mask, 351 const char *input) 352{ 353 char *cpu, *str, *p; 354 long max_cpu; 355 int ret = 0; 356 357 ret = fio_cpuset_init(mask); 358 if (ret < 0) { 359 log_err("fio: cpuset_init failed\n"); 360 td_verror(td, ret, "fio_cpuset_init"); 361 return 1; 362 } 363 364 p = str = strdup(input); 365 366 strip_blank_front(&str); 367 strip_blank_end(str); 368 369 max_cpu = sysconf(_SC_NPROCESSORS_ONLN); 370 371 while ((cpu = strsep(&str, ",")) != NULL) { 372 char *str2, *cpu2; 373 int icpu, icpu2; 374 375 if (!strlen(cpu)) 376 break; 377 378 str2 = cpu; 379 icpu2 = -1; 380 while ((cpu2 = strsep(&str2, "-")) != NULL) { 381 if (!strlen(cpu2)) 382 break; 383 384 icpu2 = atoi(cpu2); 385 } 386 387 icpu = atoi(cpu); 388 if (icpu2 == -1) 389 icpu2 = icpu; 390 while (icpu <= icpu2) { 391 if (icpu >= FIO_MAX_CPUS) { 392 log_err("fio: your OS only supports up to" 393 " %d CPUs\n", (int) FIO_MAX_CPUS); 394 ret = 1; 395 break; 396 } 397 if (icpu > max_cpu) { 398 log_err("fio: CPU %d too large (max=%ld)\n", 399 icpu, max_cpu); 400 ret = 1; 401 break; 402 } 403 404 dprint(FD_PARSE, "set cpu allowed %d\n", icpu); 405 fio_cpu_set(mask, icpu); 406 icpu++; 407 } 408 if (ret) 409 break; 410 } 411 412 free(p); 413 if (!ret) 414 td->o.cpumask_set = 1; 415 return ret; 416} 417 418static int str_cpus_allowed_cb(void *data, const char *input) 419{ 420 struct thread_data *td = data; 421 int ret; 422 423 ret = set_cpus_allowed(td, &td->o.cpumask, input); 424 if (!ret) 425 td->o.cpumask_set = 1; 426 427 return ret; 428} 429 430static int str_verify_cpus_allowed_cb(void *data, const char *input) 431{ 432 struct thread_data *td = data; 433 int ret; 434 435 ret = set_cpus_allowed(td, &td->o.verify_cpumask, input); 436 if (!ret) 437 td->o.verify_cpumask_set = 1; 438 439 return ret; 440} 441#endif 442 443#ifdef FIO_HAVE_TRIM 444static int str_verify_trim_cb(void *data, unsigned long long *val) 445{ 446 struct thread_data *td = data; 447 448 td->o.trim_percentage = *val; 449 return 0; 450} 451#endif 452 453static int str_fst_cb(void *data, const char *str) 454{ 455 struct thread_data *td = data; 456 char *nr = get_opt_postfix(str); 457 458 td->file_service_nr = 1; 459 if (nr) { 460 td->file_service_nr = atoi(nr); 461 free(nr); 462 } 463 464 return 0; 465} 466 467#ifdef FIO_HAVE_SYNC_FILE_RANGE 468static int str_sfr_cb(void *data, const char *str) 469{ 470 struct thread_data *td = data; 471 char *nr = get_opt_postfix(str); 472 473 td->sync_file_range_nr = 1; 474 if (nr) { 475 td->sync_file_range_nr = atoi(nr); 476 free(nr); 477 } 478 479 return 0; 480} 481#endif 482 483static int check_dir(struct thread_data *td, char *fname) 484{ 485 char file[PATH_MAX], *dir; 486 int elen = 0; 487 488 if (td->o.directory) { 489 strcpy(file, td->o.directory); 490 strcat(file, "/"); 491 elen = strlen(file); 492 } 493 494 sprintf(file + elen, "%s", fname); 495 dir = dirname(file); 496 497#if 0 498 { 499 struct stat sb; 500 /* 501 * We can't do this on FIO_DISKLESSIO engines. The engine isn't loaded 502 * yet, so we can't do this check right here... 503 */ 504 if (lstat(dir, &sb) < 0) { 505 int ret = errno; 506 507 log_err("fio: %s is not a directory\n", dir); 508 td_verror(td, ret, "lstat"); 509 return 1; 510 } 511 512 if (!S_ISDIR(sb.st_mode)) { 513 log_err("fio: %s is not a directory\n", dir); 514 return 1; 515 } 516 } 517#endif 518 519 return 0; 520} 521 522/* 523 * Return next file in the string. Files are separated with ':'. If the ':' 524 * is escaped with a '\', then that ':' is part of the filename and does not 525 * indicate a new file. 526 */ 527static char *get_next_file_name(char **ptr) 528{ 529 char *str = *ptr; 530 char *p, *start; 531 532 if (!str || !strlen(str)) 533 return NULL; 534 535 start = str; 536 do { 537 /* 538 * No colon, we are done 539 */ 540 p = strchr(str, ':'); 541 if (!p) { 542 *ptr = NULL; 543 break; 544 } 545 546 /* 547 * We got a colon, but it's the first character. Skip and 548 * continue 549 */ 550 if (p == start) { 551 str = ++start; 552 continue; 553 } 554 555 if (*(p - 1) != '\\') { 556 *p = '\0'; 557 *ptr = p + 1; 558 break; 559 } 560 561 memmove(p - 1, p, strlen(p) + 1); 562 str = p; 563 } while (1); 564 565 return start; 566} 567 568static int str_filename_cb(void *data, const char *input) 569{ 570 struct thread_data *td = data; 571 char *fname, *str, *p; 572 573 p = str = strdup(input); 574 575 strip_blank_front(&str); 576 strip_blank_end(str); 577 578 if (!td->files_index) 579 td->o.nr_files = 0; 580 581 while ((fname = get_next_file_name(&str)) != NULL) { 582 if (!strlen(fname)) 583 break; 584 if (check_dir(td, fname)) { 585 free(p); 586 return 1; 587 } 588 add_file(td, fname); 589 td->o.nr_files++; 590 } 591 592 free(p); 593 return 0; 594} 595 596static int str_directory_cb(void *data, const char fio_unused *str) 597{ 598 struct thread_data *td = data; 599 struct stat sb; 600 601 if (lstat(td->o.directory, &sb) < 0) { 602 int ret = errno; 603 604 log_err("fio: %s is not a directory\n", td->o.directory); 605 td_verror(td, ret, "lstat"); 606 return 1; 607 } 608 if (!S_ISDIR(sb.st_mode)) { 609 log_err("fio: %s is not a directory\n", td->o.directory); 610 return 1; 611 } 612 613 return 0; 614} 615 616static int str_opendir_cb(void *data, const char fio_unused *str) 617{ 618 struct thread_data *td = data; 619 620 if (!td->files_index) 621 td->o.nr_files = 0; 622 623 return add_dir_files(td, td->o.opendir); 624} 625 626static int str_verify_offset_cb(void *data, unsigned long long *off) 627{ 628 struct thread_data *td = data; 629 630 if (*off && *off < sizeof(struct verify_header)) { 631 log_err("fio: verify_offset too small\n"); 632 return 1; 633 } 634 635 td->o.verify_offset = *off; 636 return 0; 637} 638 639static int str_verify_pattern_cb(void *data, const char *input) 640{ 641 struct thread_data *td = data; 642 long off; 643 int i = 0, j = 0, len, k, base = 10; 644 char* loc1, * loc2; 645 646 loc1 = strstr(input, "0x"); 647 loc2 = strstr(input, "0X"); 648 if (loc1 || loc2) 649 base = 16; 650 off = strtol(input, NULL, base); 651 if (off != LONG_MAX || errno != ERANGE) { 652 while (off) { 653 td->o.verify_pattern[i] = off & 0xff; 654 off >>= 8; 655 i++; 656 } 657 } else { 658 len = strlen(input); 659 k = len - 1; 660 if (base == 16) { 661 if (loc1) 662 j = loc1 - input + 2; 663 else 664 j = loc2 - input + 2; 665 } else 666 return 1; 667 if (len - j < MAX_PATTERN_SIZE * 2) { 668 while (k >= j) { 669 off = converthexchartoint(input[k--]); 670 if (k >= j) 671 off += (converthexchartoint(input[k--]) 672 * 16); 673 td->o.verify_pattern[i++] = (char) off; 674 } 675 } 676 } 677 td->o.verify_pattern_bytes = i; 678 return 0; 679} 680 681static int str_lockfile_cb(void *data, const char *str) 682{ 683 struct thread_data *td = data; 684 char *nr = get_opt_postfix(str); 685 686 td->o.lockfile_batch = 1; 687 if (nr) { 688 td->o.lockfile_batch = atoi(nr); 689 free(nr); 690 } 691 692 return 0; 693} 694 695static int str_write_bw_log_cb(void *data, const char *str) 696{ 697 struct thread_data *td = data; 698 699 if (str) 700 td->o.bw_log_file = strdup(str); 701 702 td->o.write_bw_log = 1; 703 return 0; 704} 705 706static int str_write_lat_log_cb(void *data, const char *str) 707{ 708 struct thread_data *td = data; 709 710 if (str) 711 td->o.lat_log_file = strdup(str); 712 713 td->o.write_lat_log = 1; 714 return 0; 715} 716 717static int str_gtod_reduce_cb(void *data, int *il) 718{ 719 struct thread_data *td = data; 720 int val = *il; 721 722 td->o.disable_lat = !!val; 723 td->o.disable_clat = !!val; 724 td->o.disable_slat = !!val; 725 td->o.disable_bw = !!val; 726 if (val) 727 td->tv_cache_mask = 63; 728 729 return 0; 730} 731 732static int str_gtod_cpu_cb(void *data, long long *il) 733{ 734 struct thread_data *td = data; 735 int val = *il; 736 737 td->o.gtod_cpu = val; 738 td->o.gtod_offload = 1; 739 return 0; 740} 741 742static int rw_verify(struct fio_option *o, void *data) 743{ 744 struct thread_data *td = data; 745 746 if (read_only && td_write(td)) { 747 log_err("fio: job <%s> has write bit set, but fio is in" 748 " read-only mode\n", td->o.name); 749 return 1; 750 } 751 752 return 0; 753} 754 755static int gtod_cpu_verify(struct fio_option *o, void *data) 756{ 757#ifndef FIO_HAVE_CPU_AFFINITY 758 struct thread_data *td = data; 759 760 if (td->o.gtod_cpu) { 761 log_err("fio: platform must support CPU affinity for" 762 "gettimeofday() offloading\n"); 763 return 1; 764 } 765#endif 766 767 return 0; 768} 769 770static int kb_base_verify(struct fio_option *o, void *data) 771{ 772 struct thread_data *td = data; 773 774 if (td->o.kb_base != 1024 && td->o.kb_base != 1000) { 775 log_err("fio: kb_base set to nonsensical value: %u\n", 776 td->o.kb_base); 777 return 1; 778 } 779 780 return 0; 781} 782 783#define __stringify_1(x) #x 784#define __stringify(x) __stringify_1(x) 785 786/* 787 * Map of job/command line options 788 */ 789static struct fio_option options[FIO_MAX_OPTS] = { 790 { 791 .name = "description", 792 .type = FIO_OPT_STR_STORE, 793 .off1 = td_var_offset(description), 794 .help = "Text job description", 795 }, 796 { 797 .name = "name", 798 .type = FIO_OPT_STR_STORE, 799 .off1 = td_var_offset(name), 800 .help = "Name of this job", 801 }, 802 { 803 .name = "directory", 804 .type = FIO_OPT_STR_STORE, 805 .off1 = td_var_offset(directory), 806 .cb = str_directory_cb, 807 .help = "Directory to store files in", 808 }, 809 { 810 .name = "filename", 811 .type = FIO_OPT_STR_STORE, 812 .off1 = td_var_offset(filename), 813 .cb = str_filename_cb, 814 .prio = -1, /* must come after "directory" */ 815 .help = "File(s) to use for the workload", 816 }, 817 { 818 .name = "kb_base", 819 .type = FIO_OPT_INT, 820 .off1 = td_var_offset(kb_base), 821 .verify = kb_base_verify, 822 .prio = 1, 823 .def = "1024", 824 .help = "How many bytes per KB for reporting (1000 or 1024)", 825 }, 826 { 827 .name = "lockfile", 828 .type = FIO_OPT_STR, 829 .cb = str_lockfile_cb, 830 .off1 = td_var_offset(file_lock_mode), 831 .help = "Lock file when doing IO to it", 832 .parent = "filename", 833 .def = "none", 834 .posval = { 835 { .ival = "none", 836 .oval = FILE_LOCK_NONE, 837 .help = "No file locking", 838 }, 839 { .ival = "exclusive", 840 .oval = FILE_LOCK_EXCLUSIVE, 841 .help = "Exclusive file lock", 842 }, 843 { 844 .ival = "readwrite", 845 .oval = FILE_LOCK_READWRITE, 846 .help = "Read vs write lock", 847 }, 848 }, 849 }, 850 { 851 .name = "opendir", 852 .type = FIO_OPT_STR_STORE, 853 .off1 = td_var_offset(opendir), 854 .cb = str_opendir_cb, 855 .help = "Recursively add files from this directory and down", 856 }, 857 { 858 .name = "rw", 859 .alias = "readwrite", 860 .type = FIO_OPT_STR, 861 .cb = str_rw_cb, 862 .off1 = td_var_offset(td_ddir), 863 .help = "IO direction", 864 .def = "read", 865 .verify = rw_verify, 866 .posval = { 867 { .ival = "read", 868 .oval = TD_DDIR_READ, 869 .help = "Sequential read", 870 }, 871 { .ival = "write", 872 .oval = TD_DDIR_WRITE, 873 .help = "Sequential write", 874 }, 875 { .ival = "randread", 876 .oval = TD_DDIR_RANDREAD, 877 .help = "Random read", 878 }, 879 { .ival = "randwrite", 880 .oval = TD_DDIR_RANDWRITE, 881 .help = "Random write", 882 }, 883 { .ival = "rw", 884 .oval = TD_DDIR_RW, 885 .help = "Sequential read and write mix", 886 }, 887 { .ival = "randrw", 888 .oval = TD_DDIR_RANDRW, 889 .help = "Random read and write mix" 890 }, 891 }, 892 }, 893 { 894 .name = "rw_sequencer", 895 .type = FIO_OPT_STR, 896 .off1 = td_var_offset(rw_seq), 897 .help = "IO offset generator modifier", 898 .def = "sequential", 899 .posval = { 900 { .ival = "sequential", 901 .oval = RW_SEQ_SEQ, 902 .help = "Generate sequential offsets", 903 }, 904 { .ival = "identical", 905 .oval = RW_SEQ_IDENT, 906 .help = "Generate identical offsets", 907 }, 908 }, 909 }, 910 911 { 912 .name = "ioengine", 913 .type = FIO_OPT_STR_STORE, 914 .off1 = td_var_offset(ioengine), 915 .help = "IO engine to use", 916 .def = "sync", 917 .posval = { 918 { .ival = "sync", 919 .help = "Use read/write", 920 }, 921 { .ival = "psync", 922 .help = "Use pread/pwrite", 923 }, 924 { .ival = "vsync", 925 .help = "Use readv/writev", 926 }, 927#ifdef FIO_HAVE_LIBAIO 928 { .ival = "libaio", 929 .help = "Linux native asynchronous IO", 930 }, 931#endif 932#ifdef FIO_HAVE_POSIXAIO 933 { .ival = "posixaio", 934 .help = "POSIX asynchronous IO", 935 }, 936#endif 937#ifdef FIO_HAVE_SOLARISAIO 938 { .ival = "solarisaio", 939 .help = "Solaris native asynchronous IO", 940 }, 941#endif 942#ifdef FIO_HAVE_WINDOWSAIO 943 { .ival = "windowsaio", 944 .help = "Windows native asynchronous IO" 945 }, 946 { .ival = "mmap", 947 .help = "Memory mapped IO" 948 }, 949#endif 950#ifdef FIO_HAVE_SPLICE 951 { .ival = "splice", 952 .help = "splice/vmsplice based IO", 953 }, 954 { .ival = "netsplice", 955 .help = "splice/vmsplice to/from the network", 956 }, 957#endif 958#ifdef FIO_HAVE_SGIO 959 { .ival = "sg", 960 .help = "SCSI generic v3 IO", 961 }, 962#endif 963 { .ival = "null", 964 .help = "Testing engine (no data transfer)", 965 }, 966 { .ival = "net", 967 .help = "Network IO", 968 }, 969#ifdef FIO_HAVE_SYSLET 970 { .ival = "syslet-rw", 971 .help = "syslet enabled async pread/pwrite IO", 972 }, 973#endif 974 { .ival = "cpuio", 975 .help = "CPU cycle burner engine", 976 }, 977#ifdef FIO_HAVE_GUASI 978 { .ival = "guasi", 979 .help = "GUASI IO engine", 980 }, 981#endif 982#ifdef FIO_HAVE_BINJECT 983 { .ival = "binject", 984 .help = "binject direct inject block engine", 985 }, 986#endif 987 { .ival = "external", 988 .help = "Load external engine (append name)", 989 }, 990 }, 991 }, 992 { 993 .name = "iodepth", 994 .type = FIO_OPT_INT, 995 .off1 = td_var_offset(iodepth), 996 .help = "Number of IO buffers to keep in flight", 997 .minval = 1, 998 .def = "1", 999 }, 1000 { 1001 .name = "iodepth_batch", 1002 .alias = "iodepth_batch_submit", 1003 .type = FIO_OPT_INT, 1004 .off1 = td_var_offset(iodepth_batch), 1005 .help = "Number of IO buffers to submit in one go", 1006 .parent = "iodepth", 1007 .minval = 1, 1008 .def = "1", 1009 }, 1010 { 1011 .name = "iodepth_batch_complete", 1012 .type = FIO_OPT_INT, 1013 .off1 = td_var_offset(iodepth_batch_complete), 1014 .help = "Number of IO buffers to retrieve in one go", 1015 .parent = "iodepth", 1016 .minval = 0, 1017 .def = "1", 1018 }, 1019 { 1020 .name = "iodepth_low", 1021 .type = FIO_OPT_INT, 1022 .off1 = td_var_offset(iodepth_low), 1023 .help = "Low water mark for queuing depth", 1024 .parent = "iodepth", 1025 }, 1026 { 1027 .name = "size", 1028 .type = FIO_OPT_STR_VAL, 1029 .off1 = td_var_offset(size), 1030 .minval = 1, 1031 .help = "Total size of device or files", 1032 }, 1033 { 1034 .name = "fill_device", 1035 .type = FIO_OPT_BOOL, 1036 .off1 = td_var_offset(fill_device), 1037 .help = "Write until an ENOSPC error occurs", 1038 .def = "0", 1039 }, 1040 { 1041 .name = "filesize", 1042 .type = FIO_OPT_STR_VAL, 1043 .off1 = td_var_offset(file_size_low), 1044 .off2 = td_var_offset(file_size_high), 1045 .minval = 1, 1046 .help = "Size of individual files", 1047 }, 1048 { 1049 .name = "offset", 1050 .alias = "fileoffset", 1051 .type = FIO_OPT_STR_VAL, 1052 .off1 = td_var_offset(start_offset), 1053 .help = "Start IO from this offset", 1054 .def = "0", 1055 }, 1056 { 1057 .name = "bs", 1058 .alias = "blocksize", 1059 .type = FIO_OPT_INT, 1060 .off1 = td_var_offset(bs[DDIR_READ]), 1061 .off2 = td_var_offset(bs[DDIR_WRITE]), 1062 .minval = 1, 1063 .help = "Block size unit", 1064 .def = "4k", 1065 .parent = "rw", 1066 }, 1067 { 1068 .name = "ba", 1069 .alias = "blockalign", 1070 .type = FIO_OPT_INT, 1071 .off1 = td_var_offset(ba[DDIR_READ]), 1072 .off2 = td_var_offset(ba[DDIR_WRITE]), 1073 .minval = 1, 1074 .help = "IO block offset alignment", 1075 .parent = "rw", 1076 }, 1077 { 1078 .name = "bsrange", 1079 .alias = "blocksize_range", 1080 .type = FIO_OPT_RANGE, 1081 .off1 = td_var_offset(min_bs[DDIR_READ]), 1082 .off2 = td_var_offset(max_bs[DDIR_READ]), 1083 .off3 = td_var_offset(min_bs[DDIR_WRITE]), 1084 .off4 = td_var_offset(max_bs[DDIR_WRITE]), 1085 .minval = 1, 1086 .help = "Set block size range (in more detail than bs)", 1087 .parent = "rw", 1088 }, 1089 { 1090 .name = "bssplit", 1091 .type = FIO_OPT_STR, 1092 .cb = str_bssplit_cb, 1093 .help = "Set a specific mix of block sizes", 1094 .parent = "rw", 1095 }, 1096 { 1097 .name = "bs_unaligned", 1098 .alias = "blocksize_unaligned", 1099 .type = FIO_OPT_STR_SET, 1100 .off1 = td_var_offset(bs_unaligned), 1101 .help = "Don't sector align IO buffer sizes", 1102 .parent = "rw", 1103 }, 1104 { 1105 .name = "randrepeat", 1106 .type = FIO_OPT_BOOL, 1107 .off1 = td_var_offset(rand_repeatable), 1108 .help = "Use repeatable random IO pattern", 1109 .def = "1", 1110 .parent = "rw", 1111 }, 1112 { 1113 .name = "norandommap", 1114 .type = FIO_OPT_STR_SET, 1115 .off1 = td_var_offset(norandommap), 1116 .help = "Accept potential duplicate random blocks", 1117 .parent = "rw", 1118 }, 1119 { 1120 .name = "softrandommap", 1121 .type = FIO_OPT_BOOL, 1122 .off1 = td_var_offset(softrandommap), 1123 .help = "Set norandommap if randommap allocation fails", 1124 .parent = "norandommap", 1125 .def = "0", 1126 }, 1127 { 1128 .name = "nrfiles", 1129 .alias = "nr_files", 1130 .type = FIO_OPT_INT, 1131 .off1 = td_var_offset(nr_files), 1132 .help = "Split job workload between this number of files", 1133 .def = "1", 1134 }, 1135 { 1136 .name = "openfiles", 1137 .type = FIO_OPT_INT, 1138 .off1 = td_var_offset(open_files), 1139 .help = "Number of files to keep open at the same time", 1140 }, 1141 { 1142 .name = "file_service_type", 1143 .type = FIO_OPT_STR, 1144 .cb = str_fst_cb, 1145 .off1 = td_var_offset(file_service_type), 1146 .help = "How to select which file to service next", 1147 .def = "roundrobin", 1148 .posval = { 1149 { .ival = "random", 1150 .oval = FIO_FSERVICE_RANDOM, 1151 .help = "Choose a file at random", 1152 }, 1153 { .ival = "roundrobin", 1154 .oval = FIO_FSERVICE_RR, 1155 .help = "Round robin select files", 1156 }, 1157 { .ival = "sequential", 1158 .oval = FIO_FSERVICE_SEQ, 1159 .help = "Finish one file before moving to the next", 1160 }, 1161 }, 1162 .parent = "nrfiles", 1163 }, 1164#ifdef FIO_HAVE_FALLOCATE 1165 { 1166 .name = "fallocate", 1167 .type = FIO_OPT_BOOL, 1168 .off1 = td_var_offset(fallocate), 1169 .help = "Use fallocate() when laying out files", 1170 .def = "1", 1171 }, 1172#endif 1173 { 1174 .name = "fadvise_hint", 1175 .type = FIO_OPT_BOOL, 1176 .off1 = td_var_offset(fadvise_hint), 1177 .help = "Use fadvise() to advise the kernel on IO pattern", 1178 .def = "1", 1179 }, 1180 { 1181 .name = "fsync", 1182 .type = FIO_OPT_INT, 1183 .off1 = td_var_offset(fsync_blocks), 1184 .help = "Issue fsync for writes every given number of blocks", 1185 .def = "0", 1186 }, 1187 { 1188 .name = "fdatasync", 1189 .type = FIO_OPT_INT, 1190 .off1 = td_var_offset(fdatasync_blocks), 1191 .help = "Issue fdatasync for writes every given number of blocks", 1192 .def = "0", 1193 }, 1194 { 1195 .name = "write_barrier", 1196 .type = FIO_OPT_INT, 1197 .off1 = td_var_offset(barrier_blocks), 1198 .help = "Make every Nth write a barrier write", 1199 .def = "0", 1200 }, 1201#ifdef FIO_HAVE_SYNC_FILE_RANGE 1202 { 1203 .name = "sync_file_range", 1204 .posval = { 1205 { .ival = "wait_before", 1206 .oval = SYNC_FILE_RANGE_WAIT_BEFORE, 1207 .help = "SYNC_FILE_RANGE_WAIT_BEFORE", 1208 .or = 1, 1209 }, 1210 { .ival = "write", 1211 .oval = SYNC_FILE_RANGE_WRITE, 1212 .help = "SYNC_FILE_RANGE_WRITE", 1213 .or = 1, 1214 }, 1215 { 1216 .ival = "wait_after", 1217 .oval = SYNC_FILE_RANGE_WAIT_AFTER, 1218 .help = "SYNC_FILE_RANGE_WAIT_AFTER", 1219 .or = 1, 1220 }, 1221 }, 1222 .type = FIO_OPT_STR_MULTI, 1223 .cb = str_sfr_cb, 1224 .off1 = td_var_offset(sync_file_range), 1225 .help = "Use sync_file_range()", 1226 }, 1227#endif 1228 { 1229 .name = "direct", 1230 .type = FIO_OPT_BOOL, 1231 .off1 = td_var_offset(odirect), 1232 .help = "Use O_DIRECT IO (negates buffered)", 1233 .def = "0", 1234 }, 1235 { 1236 .name = "buffered", 1237 .type = FIO_OPT_BOOL, 1238 .off1 = td_var_offset(odirect), 1239 .neg = 1, 1240 .help = "Use buffered IO (negates direct)", 1241 .def = "1", 1242 }, 1243 { 1244 .name = "overwrite", 1245 .type = FIO_OPT_BOOL, 1246 .off1 = td_var_offset(overwrite), 1247 .help = "When writing, set whether to overwrite current data", 1248 .def = "0", 1249 }, 1250 { 1251 .name = "loops", 1252 .type = FIO_OPT_INT, 1253 .off1 = td_var_offset(loops), 1254 .help = "Number of times to run the job", 1255 .def = "1", 1256 }, 1257 { 1258 .name = "numjobs", 1259 .type = FIO_OPT_INT, 1260 .off1 = td_var_offset(numjobs), 1261 .help = "Duplicate this job this many times", 1262 .def = "1", 1263 }, 1264 { 1265 .name = "startdelay", 1266 .type = FIO_OPT_STR_VAL_TIME, 1267 .off1 = td_var_offset(start_delay), 1268 .help = "Only start job when this period has passed", 1269 .def = "0", 1270 }, 1271 { 1272 .name = "runtime", 1273 .alias = "timeout", 1274 .type = FIO_OPT_STR_VAL_TIME, 1275 .off1 = td_var_offset(timeout), 1276 .help = "Stop workload when this amount of time has passed", 1277 .def = "0", 1278 }, 1279 { 1280 .name = "time_based", 1281 .type = FIO_OPT_STR_SET, 1282 .off1 = td_var_offset(time_based), 1283 .help = "Keep running until runtime/timeout is met", 1284 }, 1285 { 1286 .name = "ramp_time", 1287 .type = FIO_OPT_STR_VAL_TIME, 1288 .off1 = td_var_offset(ramp_time), 1289 .help = "Ramp up time before measuring performance", 1290 }, 1291 { 1292 .name = "clocksource", 1293 .type = FIO_OPT_STR, 1294 .cb = fio_clock_source_cb, 1295 .off1 = td_var_offset(clocksource), 1296 .help = "What type of timing source to use", 1297 .posval = { 1298 { .ival = "gettimeofday", 1299 .oval = CS_GTOD, 1300 .help = "Use gettimeofday(2) for timing", 1301 }, 1302 { .ival = "clock_gettime", 1303 .oval = CS_CGETTIME, 1304 .help = "Use clock_gettime(2) for timing", 1305 }, 1306#ifdef ARCH_HAVE_CPU_CLOCK 1307 { .ival = "cpu", 1308 .oval = CS_CPUCLOCK, 1309 .help = "Use CPU private clock", 1310 }, 1311#endif 1312 }, 1313 }, 1314 { 1315 .name = "mem", 1316 .alias = "iomem", 1317 .type = FIO_OPT_STR, 1318 .cb = str_mem_cb, 1319 .off1 = td_var_offset(mem_type), 1320 .help = "Backing type for IO buffers", 1321 .def = "malloc", 1322 .posval = { 1323 { .ival = "malloc", 1324 .oval = MEM_MALLOC, 1325 .help = "Use malloc(3) for IO buffers", 1326 }, 1327 { .ival = "shm", 1328 .oval = MEM_SHM, 1329 .help = "Use shared memory segments for IO buffers", 1330 }, 1331#ifdef FIO_HAVE_HUGETLB 1332 { .ival = "shmhuge", 1333 .oval = MEM_SHMHUGE, 1334 .help = "Like shm, but use huge pages", 1335 }, 1336#endif 1337 { .ival = "mmap", 1338 .oval = MEM_MMAP, 1339 .help = "Use mmap(2) (file or anon) for IO buffers", 1340 }, 1341#ifdef FIO_HAVE_HUGETLB 1342 { .ival = "mmaphuge", 1343 .oval = MEM_MMAPHUGE, 1344 .help = "Like mmap, but use huge pages", 1345 }, 1346#endif 1347 }, 1348 }, 1349 { 1350 .name = "iomem_align", 1351 .alias = "mem_align", 1352 .type = FIO_OPT_INT, 1353 .off1 = td_var_offset(mem_align), 1354 .minval = 0, 1355 .help = "IO memory buffer offset alignment", 1356 .def = "0", 1357 .parent = "iomem", 1358 }, 1359 { 1360 .name = "verify", 1361 .type = FIO_OPT_STR, 1362 .off1 = td_var_offset(verify), 1363 .help = "Verify data written", 1364 .cb = str_verify_cb, 1365 .def = "0", 1366 .posval = { 1367 { .ival = "0", 1368 .oval = VERIFY_NONE, 1369 .help = "Don't do IO verification", 1370 }, 1371 { .ival = "md5", 1372 .oval = VERIFY_MD5, 1373 .help = "Use md5 checksums for verification", 1374 }, 1375 { .ival = "crc64", 1376 .oval = VERIFY_CRC64, 1377 .help = "Use crc64 checksums for verification", 1378 }, 1379 { .ival = "crc32", 1380 .oval = VERIFY_CRC32, 1381 .help = "Use crc32 checksums for verification", 1382 }, 1383 { .ival = "crc32c-intel", 1384 .oval = VERIFY_CRC32C_INTEL, 1385 .help = "Use hw crc32c checksums for verification", 1386 }, 1387 { .ival = "crc32c", 1388 .oval = VERIFY_CRC32C, 1389 .help = "Use crc32c checksums for verification", 1390 }, 1391 { .ival = "crc16", 1392 .oval = VERIFY_CRC16, 1393 .help = "Use crc16 checksums for verification", 1394 }, 1395 { .ival = "crc7", 1396 .oval = VERIFY_CRC7, 1397 .help = "Use crc7 checksums for verification", 1398 }, 1399 { .ival = "sha1", 1400 .oval = VERIFY_SHA1, 1401 .help = "Use sha1 checksums for verification", 1402 }, 1403 { .ival = "sha256", 1404 .oval = VERIFY_SHA256, 1405 .help = "Use sha256 checksums for verification", 1406 }, 1407 { .ival = "sha512", 1408 .oval = VERIFY_SHA512, 1409 .help = "Use sha512 checksums for verification", 1410 }, 1411 { .ival = "meta", 1412 .oval = VERIFY_META, 1413 .help = "Use io information", 1414 }, 1415 { 1416 .ival = "null", 1417 .oval = VERIFY_NULL, 1418 .help = "Pretend to verify", 1419 }, 1420 }, 1421 }, 1422 { 1423 .name = "do_verify", 1424 .type = FIO_OPT_BOOL, 1425 .off1 = td_var_offset(do_verify), 1426 .help = "Run verification stage after write", 1427 .def = "1", 1428 .parent = "verify", 1429 }, 1430 { 1431 .name = "verifysort", 1432 .type = FIO_OPT_BOOL, 1433 .off1 = td_var_offset(verifysort), 1434 .help = "Sort written verify blocks for read back", 1435 .def = "1", 1436 .parent = "verify", 1437 }, 1438 { 1439 .name = "verify_interval", 1440 .type = FIO_OPT_INT, 1441 .off1 = td_var_offset(verify_interval), 1442 .minval = 2 * sizeof(struct verify_header), 1443 .help = "Store verify buffer header every N bytes", 1444 .parent = "verify", 1445 }, 1446 { 1447 .name = "verify_offset", 1448 .type = FIO_OPT_INT, 1449 .help = "Offset verify header location by N bytes", 1450 .def = "0", 1451 .cb = str_verify_offset_cb, 1452 .parent = "verify", 1453 }, 1454 { 1455 .name = "verify_pattern", 1456 .type = FIO_OPT_STR, 1457 .cb = str_verify_pattern_cb, 1458 .help = "Fill pattern for IO buffers", 1459 .parent = "verify", 1460 }, 1461 { 1462 .name = "verify_fatal", 1463 .type = FIO_OPT_BOOL, 1464 .off1 = td_var_offset(verify_fatal), 1465 .def = "0", 1466 .help = "Exit on a single verify failure, don't continue", 1467 .parent = "verify", 1468 }, 1469 { 1470 .name = "verify_dump", 1471 .type = FIO_OPT_BOOL, 1472 .off1 = td_var_offset(verify_dump), 1473 .def = "1", 1474 .help = "Dump contents of good and bad blocks on failure", 1475 .parent = "verify", 1476 }, 1477 { 1478 .name = "verify_async", 1479 .type = FIO_OPT_INT, 1480 .off1 = td_var_offset(verify_async), 1481 .def = "0", 1482 .help = "Number of async verifier threads to use", 1483 .parent = "verify", 1484 }, 1485 { 1486 .name = "verify_backlog", 1487 .type = FIO_OPT_STR_VAL, 1488 .off1 = td_var_offset(verify_backlog), 1489 .help = "Verify after this number of blocks are written", 1490 .parent = "verify", 1491 }, 1492 { 1493 .name = "verify_backlog_batch", 1494 .type = FIO_OPT_INT, 1495 .off1 = td_var_offset(verify_batch), 1496 .help = "Verify this number of IO blocks", 1497 .parent = "verify", 1498 }, 1499#ifdef FIO_HAVE_CPU_AFFINITY 1500 { 1501 .name = "verify_async_cpus", 1502 .type = FIO_OPT_STR, 1503 .cb = str_verify_cpus_allowed_cb, 1504 .help = "Set CPUs allowed for async verify threads", 1505 .parent = "verify_async", 1506 }, 1507#endif 1508#ifdef FIO_HAVE_TRIM 1509 { 1510 .name = "trim_percentage", 1511 .type = FIO_OPT_INT, 1512 .cb = str_verify_trim_cb, 1513 .maxval = 100, 1514 .help = "Number of verify blocks to discard/trim", 1515 .parent = "verify", 1516 .def = "0", 1517 }, 1518 { 1519 .name = "trim_verify_zero", 1520 .type = FIO_OPT_INT, 1521 .help = "Verify that trim/discarded blocks are returned as zeroes", 1522 .off1 = td_var_offset(trim_zero), 1523 .parent = "trim_percentage", 1524 .def = "1", 1525 }, 1526 { 1527 .name = "trim_backlog", 1528 .type = FIO_OPT_STR_VAL, 1529 .off1 = td_var_offset(trim_backlog), 1530 .help = "Trim after this number of blocks are written", 1531 .parent = "trim_percentage", 1532 }, 1533 { 1534 .name = "trim_backlog_batch", 1535 .type = FIO_OPT_INT, 1536 .off1 = td_var_offset(trim_batch), 1537 .help = "Trim this number of IO blocks", 1538 .parent = "trim_percentage", 1539 }, 1540#endif 1541 { 1542 .name = "write_iolog", 1543 .type = FIO_OPT_STR_STORE, 1544 .off1 = td_var_offset(write_iolog_file), 1545 .help = "Store IO pattern to file", 1546 }, 1547 { 1548 .name = "read_iolog", 1549 .type = FIO_OPT_STR_STORE, 1550 .off1 = td_var_offset(read_iolog_file), 1551 .help = "Playback IO pattern from file", 1552 }, 1553 { 1554 .name = "replay_no_stall", 1555 .type = FIO_OPT_INT, 1556 .off1 = td_var_offset(no_stall), 1557 .def = "0", 1558 .parent = "read_iolog", 1559 .help = "Playback IO pattern file as fast as possible without stalls", 1560 }, 1561 { 1562 .name = "replay_redirect", 1563 .type = FIO_OPT_STR_STORE, 1564 .off1 = td_var_offset(replay_redirect), 1565 .parent = "read_iolog", 1566 .help = "Replay all I/O onto this device, regardless of trace device", 1567 }, 1568 { 1569 .name = "exec_prerun", 1570 .type = FIO_OPT_STR_STORE, 1571 .off1 = td_var_offset(exec_prerun), 1572 .help = "Execute this file prior to running job", 1573 }, 1574 { 1575 .name = "exec_postrun", 1576 .type = FIO_OPT_STR_STORE, 1577 .off1 = td_var_offset(exec_postrun), 1578 .help = "Execute this file after running job", 1579 }, 1580#ifdef FIO_HAVE_IOSCHED_SWITCH 1581 { 1582 .name = "ioscheduler", 1583 .type = FIO_OPT_STR_STORE, 1584 .off1 = td_var_offset(ioscheduler), 1585 .help = "Use this IO scheduler on the backing device", 1586 }, 1587#endif 1588 { 1589 .name = "zonesize", 1590 .type = FIO_OPT_STR_VAL, 1591 .off1 = td_var_offset(zone_size), 1592 .help = "Give size of an IO zone", 1593 .def = "0", 1594 }, 1595 { 1596 .name = "zoneskip", 1597 .type = FIO_OPT_STR_VAL, 1598 .off1 = td_var_offset(zone_skip), 1599 .help = "Space between IO zones", 1600 .def = "0", 1601 }, 1602 { 1603 .name = "lockmem", 1604 .type = FIO_OPT_STR_VAL, 1605 .cb = str_lockmem_cb, 1606 .help = "Lock down this amount of memory", 1607 .def = "0", 1608 }, 1609 { 1610 .name = "rwmixread", 1611 .type = FIO_OPT_INT, 1612 .cb = str_rwmix_read_cb, 1613 .maxval = 100, 1614 .help = "Percentage of mixed workload that is reads", 1615 .def = "50", 1616 }, 1617 { 1618 .name = "rwmixwrite", 1619 .type = FIO_OPT_INT, 1620 .cb = str_rwmix_write_cb, 1621 .maxval = 100, 1622 .help = "Percentage of mixed workload that is writes", 1623 .def = "50", 1624 }, 1625 { 1626 .name = "rwmixcycle", 1627 .type = FIO_OPT_DEPRECATED, 1628 }, 1629 { 1630 .name = "nice", 1631 .type = FIO_OPT_INT, 1632 .off1 = td_var_offset(nice), 1633 .help = "Set job CPU nice value", 1634 .minval = -19, 1635 .maxval = 20, 1636 .def = "0", 1637 }, 1638#ifdef FIO_HAVE_IOPRIO 1639 { 1640 .name = "prio", 1641 .type = FIO_OPT_INT, 1642 .cb = str_prio_cb, 1643 .help = "Set job IO priority value", 1644 .minval = 0, 1645 .maxval = 7, 1646 }, 1647 { 1648 .name = "prioclass", 1649 .type = FIO_OPT_INT, 1650 .cb = str_prioclass_cb, 1651 .help = "Set job IO priority class", 1652 .minval = 0, 1653 .maxval = 3, 1654 }, 1655#endif 1656 { 1657 .name = "thinktime", 1658 .type = FIO_OPT_INT, 1659 .off1 = td_var_offset(thinktime), 1660 .help = "Idle time between IO buffers (usec)", 1661 .def = "0", 1662 }, 1663 { 1664 .name = "thinktime_spin", 1665 .type = FIO_OPT_INT, 1666 .off1 = td_var_offset(thinktime_spin), 1667 .help = "Start think time by spinning this amount (usec)", 1668 .def = "0", 1669 .parent = "thinktime", 1670 }, 1671 { 1672 .name = "thinktime_blocks", 1673 .type = FIO_OPT_INT, 1674 .off1 = td_var_offset(thinktime_blocks), 1675 .help = "IO buffer period between 'thinktime'", 1676 .def = "1", 1677 .parent = "thinktime", 1678 }, 1679 { 1680 .name = "rate", 1681 .type = FIO_OPT_INT, 1682 .off1 = td_var_offset(rate[0]), 1683 .off2 = td_var_offset(rate[1]), 1684 .help = "Set bandwidth rate", 1685 }, 1686 { 1687 .name = "ratemin", 1688 .type = FIO_OPT_INT, 1689 .off1 = td_var_offset(ratemin[0]), 1690 .off2 = td_var_offset(ratemin[1]), 1691 .help = "Job must meet this rate or it will be shutdown", 1692 .parent = "rate", 1693 }, 1694 { 1695 .name = "rate_iops", 1696 .type = FIO_OPT_INT, 1697 .off1 = td_var_offset(rate_iops[0]), 1698 .off2 = td_var_offset(rate_iops[1]), 1699 .help = "Limit IO used to this number of IO operations/sec", 1700 }, 1701 { 1702 .name = "rate_iops_min", 1703 .type = FIO_OPT_INT, 1704 .off1 = td_var_offset(rate_iops_min[0]), 1705 .off2 = td_var_offset(rate_iops_min[1]), 1706 .help = "Job must meet this rate or it will be shut down", 1707 .parent = "rate_iops", 1708 }, 1709 { 1710 .name = "ratecycle", 1711 .type = FIO_OPT_INT, 1712 .off1 = td_var_offset(ratecycle), 1713 .help = "Window average for rate limits (msec)", 1714 .def = "1000", 1715 .parent = "rate", 1716 }, 1717 { 1718 .name = "invalidate", 1719 .type = FIO_OPT_BOOL, 1720 .off1 = td_var_offset(invalidate_cache), 1721 .help = "Invalidate buffer/page cache prior to running job", 1722 .def = "1", 1723 }, 1724 { 1725 .name = "sync", 1726 .type = FIO_OPT_BOOL, 1727 .off1 = td_var_offset(sync_io), 1728 .help = "Use O_SYNC for buffered writes", 1729 .def = "0", 1730 .parent = "buffered", 1731 }, 1732 { 1733 .name = "bwavgtime", 1734 .type = FIO_OPT_INT, 1735 .off1 = td_var_offset(bw_avg_time), 1736 .help = "Time window over which to calculate bandwidth" 1737 " (msec)", 1738 .def = "500", 1739 }, 1740 { 1741 .name = "create_serialize", 1742 .type = FIO_OPT_BOOL, 1743 .off1 = td_var_offset(create_serialize), 1744 .help = "Serialize creating of job files", 1745 .def = "1", 1746 }, 1747 { 1748 .name = "create_fsync", 1749 .type = FIO_OPT_BOOL, 1750 .off1 = td_var_offset(create_fsync), 1751 .help = "fsync file after creation", 1752 .def = "1", 1753 }, 1754 { 1755 .name = "create_on_open", 1756 .type = FIO_OPT_BOOL, 1757 .off1 = td_var_offset(create_on_open), 1758 .help = "Create files when they are opened for IO", 1759 .def = "0", 1760 }, 1761 { 1762 .name = "pre_read", 1763 .type = FIO_OPT_BOOL, 1764 .off1 = td_var_offset(pre_read), 1765 .help = "Pre-read files before starting official testing", 1766 .def = "0", 1767 }, 1768 { 1769 .name = "cpuload", 1770 .type = FIO_OPT_INT, 1771 .off1 = td_var_offset(cpuload), 1772 .help = "Use this percentage of CPU", 1773 }, 1774 { 1775 .name = "cpuchunks", 1776 .type = FIO_OPT_INT, 1777 .off1 = td_var_offset(cpucycle), 1778 .help = "Length of the CPU burn cycles (usecs)", 1779 .def = "50000", 1780 .parent = "cpuload", 1781 }, 1782#ifdef FIO_HAVE_CPU_AFFINITY 1783 { 1784 .name = "cpumask", 1785 .type = FIO_OPT_INT, 1786 .cb = str_cpumask_cb, 1787 .help = "CPU affinity mask", 1788 }, 1789 { 1790 .name = "cpus_allowed", 1791 .type = FIO_OPT_STR, 1792 .cb = str_cpus_allowed_cb, 1793 .help = "Set CPUs allowed", 1794 }, 1795#endif 1796 { 1797 .name = "end_fsync", 1798 .type = FIO_OPT_BOOL, 1799 .off1 = td_var_offset(end_fsync), 1800 .help = "Include fsync at the end of job", 1801 .def = "0", 1802 }, 1803 { 1804 .name = "fsync_on_close", 1805 .type = FIO_OPT_BOOL, 1806 .off1 = td_var_offset(fsync_on_close), 1807 .help = "fsync files on close", 1808 .def = "0", 1809 }, 1810 { 1811 .name = "unlink", 1812 .type = FIO_OPT_BOOL, 1813 .off1 = td_var_offset(unlink), 1814 .help = "Unlink created files after job has completed", 1815 .def = "0", 1816 }, 1817 { 1818 .name = "exitall", 1819 .type = FIO_OPT_STR_SET, 1820 .cb = str_exitall_cb, 1821 .help = "Terminate all jobs when one exits", 1822 }, 1823 { 1824 .name = "stonewall", 1825 .type = FIO_OPT_STR_SET, 1826 .off1 = td_var_offset(stonewall), 1827 .help = "Insert a hard barrier between this job and previous", 1828 }, 1829 { 1830 .name = "new_group", 1831 .type = FIO_OPT_STR_SET, 1832 .off1 = td_var_offset(new_group), 1833 .help = "Mark the start of a new group (for reporting)", 1834 }, 1835 { 1836 .name = "thread", 1837 .type = FIO_OPT_STR_SET, 1838 .off1 = td_var_offset(use_thread), 1839 .help = "Use threads instead of forks", 1840 }, 1841 { 1842 .name = "write_bw_log", 1843 .type = FIO_OPT_STR, 1844 .off1 = td_var_offset(write_bw_log), 1845 .cb = str_write_bw_log_cb, 1846 .help = "Write log of bandwidth during run", 1847 }, 1848 { 1849 .name = "write_lat_log", 1850 .type = FIO_OPT_STR, 1851 .off1 = td_var_offset(write_lat_log), 1852 .cb = str_write_lat_log_cb, 1853 .help = "Write log of latency during run", 1854 }, 1855 { 1856 .name = "hugepage-size", 1857 .type = FIO_OPT_INT, 1858 .off1 = td_var_offset(hugepage_size), 1859 .help = "When using hugepages, specify size of each page", 1860 .def = __stringify(FIO_HUGE_PAGE), 1861 }, 1862 { 1863 .name = "group_reporting", 1864 .type = FIO_OPT_STR_SET, 1865 .off1 = td_var_offset(group_reporting), 1866 .help = "Do reporting on a per-group basis", 1867 }, 1868 { 1869 .name = "zero_buffers", 1870 .type = FIO_OPT_STR_SET, 1871 .off1 = td_var_offset(zero_buffers), 1872 .help = "Init IO buffers to all zeroes", 1873 }, 1874 { 1875 .name = "refill_buffers", 1876 .type = FIO_OPT_STR_SET, 1877 .off1 = td_var_offset(refill_buffers), 1878 .help = "Refill IO buffers on every IO submit", 1879 }, 1880#ifdef FIO_HAVE_DISK_UTIL 1881 { 1882 .name = "disk_util", 1883 .type = FIO_OPT_BOOL, 1884 .off1 = td_var_offset(do_disk_util), 1885 .help = "Log disk utilization statistics", 1886 .def = "1", 1887 }, 1888#endif 1889 { 1890 .name = "gtod_reduce", 1891 .type = FIO_OPT_BOOL, 1892 .help = "Greatly reduce number of gettimeofday() calls", 1893 .cb = str_gtod_reduce_cb, 1894 .def = "0", 1895 }, 1896 { 1897 .name = "disable_lat", 1898 .type = FIO_OPT_BOOL, 1899 .off1 = td_var_offset(disable_lat), 1900 .help = "Disable latency numbers", 1901 .parent = "gtod_reduce", 1902 .def = "0", 1903 }, 1904 { 1905 .name = "disable_clat", 1906 .type = FIO_OPT_BOOL, 1907 .off1 = td_var_offset(disable_clat), 1908 .help = "Disable completion latency numbers", 1909 .parent = "gtod_reduce", 1910 .def = "0", 1911 }, 1912 { 1913 .name = "disable_slat", 1914 .type = FIO_OPT_BOOL, 1915 .off1 = td_var_offset(disable_slat), 1916 .help = "Disable submission latency numbers", 1917 .parent = "gtod_reduce", 1918 .def = "0", 1919 }, 1920 { 1921 .name = "disable_bw_measurement", 1922 .type = FIO_OPT_BOOL, 1923 .off1 = td_var_offset(disable_bw), 1924 .help = "Disable bandwidth logging", 1925 .parent = "gtod_reduce", 1926 .def = "0", 1927 }, 1928 { 1929 .name = "gtod_cpu", 1930 .type = FIO_OPT_INT, 1931 .cb = str_gtod_cpu_cb, 1932 .help = "Set up dedicated gettimeofday() thread on this CPU", 1933 .verify = gtod_cpu_verify, 1934 }, 1935 { 1936 .name = "continue_on_error", 1937 .type = FIO_OPT_BOOL, 1938 .off1 = td_var_offset(continue_on_error), 1939 .help = "Continue on non-fatal errors during IO", 1940 .def = "0", 1941 }, 1942 { 1943 .name = "profile", 1944 .type = FIO_OPT_STR_STORE, 1945 .off1 = td_var_offset(profile), 1946 .help = "Select a specific builtin performance test", 1947 }, 1948 { 1949 .name = "cgroup", 1950 .type = FIO_OPT_STR_STORE, 1951 .off1 = td_var_offset(cgroup), 1952 .help = "Add job to cgroup of this name", 1953 }, 1954 { 1955 .name = "cgroup_weight", 1956 .type = FIO_OPT_INT, 1957 .off1 = td_var_offset(cgroup_weight), 1958 .help = "Use given weight for cgroup", 1959 .minval = 100, 1960 .maxval = 1000, 1961 }, 1962 { 1963 .name = "cgroup_nodelete", 1964 .type = FIO_OPT_BOOL, 1965 .off1 = td_var_offset(cgroup_nodelete), 1966 .help = "Do not delete cgroups after job completion", 1967 .def = "0", 1968 }, 1969 { 1970 .name = "uid", 1971 .type = FIO_OPT_INT, 1972 .off1 = td_var_offset(uid), 1973 .help = "Run job with this user ID", 1974 }, 1975 { 1976 .name = "gid", 1977 .type = FIO_OPT_INT, 1978 .off1 = td_var_offset(gid), 1979 .help = "Run job with this group ID", 1980 }, 1981 { 1982 .name = NULL, 1983 }, 1984}; 1985 1986static void add_to_lopt(struct option *lopt, struct fio_option *o, 1987 const char *name) 1988{ 1989 lopt->name = (char *) name; 1990 lopt->val = FIO_GETOPT_JOB; 1991 if (o->type == FIO_OPT_STR_SET) 1992 lopt->has_arg = no_argument; 1993 else 1994 lopt->has_arg = required_argument; 1995} 1996 1997void fio_options_dup_and_init(struct option *long_options) 1998{ 1999 struct fio_option *o; 2000 unsigned int i; 2001 2002 options_init(options); 2003 2004 i = 0; 2005 while (long_options[i].name) 2006 i++; 2007 2008 o = &options[0]; 2009 while (o->name) { 2010 add_to_lopt(&long_options[i], o, o->name); 2011 if (o->alias) { 2012 i++; 2013 add_to_lopt(&long_options[i], o, o->alias); 2014 } 2015 2016 i++; 2017 o++; 2018 assert(i < FIO_NR_OPTIONS); 2019 } 2020} 2021 2022struct fio_keyword { 2023 const char *word; 2024 const char *desc; 2025 char *replace; 2026}; 2027 2028static struct fio_keyword fio_keywords[] = { 2029 { 2030 .word = "$pagesize", 2031 .desc = "Page size in the system", 2032 }, 2033 { 2034 .word = "$mb_memory", 2035 .desc = "Megabytes of memory online", 2036 }, 2037 { 2038 .word = "$ncpus", 2039 .desc = "Number of CPUs online in the system", 2040 }, 2041 { 2042 .word = NULL, 2043 }, 2044}; 2045 2046void fio_keywords_init(void) 2047{ 2048 unsigned long long mb_memory; 2049 char buf[128]; 2050 long l; 2051 2052 sprintf(buf, "%lu", page_size); 2053 fio_keywords[0].replace = strdup(buf); 2054 2055 mb_memory = os_phys_mem() / page_size; 2056 sprintf(buf, "%llu", mb_memory); 2057 fio_keywords[1].replace = strdup(buf); 2058 2059 l = sysconf(_SC_NPROCESSORS_ONLN); 2060 sprintf(buf, "%lu", l); 2061 fio_keywords[2].replace = strdup(buf); 2062} 2063 2064#define BC_APP "bc" 2065 2066static char *bc_calc(char *str) 2067{ 2068 char *buf, *tmp, opt[80]; 2069 FILE *f; 2070 int ret; 2071 2072 /* 2073 * No math, just return string 2074 */ 2075 if (!strchr(str, '+') && !strchr(str, '-') && !strchr(str, '*') && 2076 !strchr(str, '/')) 2077 return str; 2078 2079 /* 2080 * Split option from value, we only need to calculate the value 2081 */ 2082 tmp = strchr(str, '='); 2083 if (!tmp) 2084 return str; 2085 2086 tmp++; 2087 memset(opt, 0, sizeof(opt)); 2088 strncpy(opt, str, tmp - str); 2089 2090 buf = malloc(128); 2091 2092 sprintf(buf, "which %s > /dev/null", BC_APP); 2093 if (system(buf)) { 2094 log_err("fio: bc is needed for performing math\n"); 2095 free(buf); 2096 return NULL; 2097 } 2098 2099 sprintf(buf, "echo %s | %s", tmp, BC_APP); 2100 f = popen(buf, "r"); 2101 if (!f) { 2102 free(buf); 2103 return NULL; 2104 } 2105 2106 ret = fread(buf, 1, 128, f); 2107 if (ret <= 0) { 2108 free(buf); 2109 return NULL; 2110 } 2111 2112 buf[ret - 1] = '\0'; 2113 strcat(opt, buf); 2114 strcpy(buf, opt); 2115 pclose(f); 2116 free(str); 2117 return buf; 2118} 2119 2120/* 2121 * Look for reserved variable names and replace them with real values 2122 */ 2123static char *fio_keyword_replace(char *opt) 2124{ 2125 char *s; 2126 int i; 2127 2128 for (i = 0; fio_keywords[i].word != NULL; i++) { 2129 struct fio_keyword *kw = &fio_keywords[i]; 2130 2131 while ((s = strstr(opt, kw->word)) != NULL) { 2132 char *new = malloc(strlen(opt) + 1); 2133 char *o_org = opt; 2134 int olen = s - opt; 2135 int len; 2136 2137 /* 2138 * Copy part of the string before the keyword and 2139 * sprintf() the replacement after it. 2140 */ 2141 memcpy(new, opt, olen); 2142 len = sprintf(new + olen, "%s", kw->replace); 2143 2144 /* 2145 * If there's more in the original string, copy that 2146 * in too 2147 */ 2148 opt += strlen(kw->word) + olen; 2149 if (strlen(opt)) 2150 memcpy(new + olen + len, opt, opt - o_org - 1); 2151 2152 /* 2153 * replace opt and free the old opt 2154 */ 2155 opt = new; 2156 //free(o_org); 2157 2158 /* 2159 * Check for potential math and invoke bc, if possible 2160 */ 2161 opt = bc_calc(opt); 2162 } 2163 } 2164 2165 return opt; 2166} 2167 2168int fio_options_parse(struct thread_data *td, char **opts, int num_opts) 2169{ 2170 int i, ret; 2171 2172 sort_options(opts, options, num_opts); 2173 2174 for (ret = 0, i = 0; i < num_opts; i++) { 2175 opts[i] = fio_keyword_replace(opts[i]); 2176 ret |= parse_option(opts[i], options, td); 2177 } 2178 2179 return ret; 2180} 2181 2182int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val) 2183{ 2184 return parse_cmd_option(opt, val, options, td); 2185} 2186 2187void fio_fill_default_options(struct thread_data *td) 2188{ 2189 fill_default_options(td, options); 2190} 2191 2192int fio_show_option_help(const char *opt) 2193{ 2194 return show_cmd_help(options, opt); 2195} 2196 2197static void __options_mem(struct thread_data *td, int alloc) 2198{ 2199 struct thread_options *o = &td->o; 2200 struct fio_option *opt; 2201 char **ptr; 2202 int i; 2203 2204 for (i = 0, opt = &options[0]; opt->name; i++, opt = &options[i]) { 2205 if (opt->type != FIO_OPT_STR_STORE) 2206 continue; 2207 2208 ptr = (void *) o + opt->off1; 2209 if (*ptr) { 2210 if (alloc) 2211 *ptr = strdup(*ptr); 2212 else { 2213 free(*ptr); 2214 *ptr = NULL; 2215 } 2216 } 2217 } 2218} 2219 2220/* 2221 * dupe FIO_OPT_STR_STORE options 2222 */ 2223void options_mem_dupe(struct thread_data *td) 2224{ 2225 __options_mem(td, 1); 2226} 2227 2228void options_mem_free(struct thread_data fio_unused *td) 2229{ 2230#if 0 2231 __options_mem(td, 0); 2232#endif 2233} 2234 2235unsigned int fio_get_kb_base(void *data) 2236{ 2237 struct thread_data *td = data; 2238 unsigned int kb_base = 0; 2239 2240 if (td) 2241 kb_base = td->o.kb_base; 2242 if (!kb_base) 2243 kb_base = 1024; 2244 2245 return kb_base; 2246} 2247 2248int add_option(struct fio_option *o) 2249{ 2250 struct fio_option *__o; 2251 int opt_index = 0; 2252 2253 __o = options; 2254 while (__o->name) { 2255 opt_index++; 2256 __o++; 2257 } 2258 2259 memcpy(&options[opt_index], o, sizeof(*o)); 2260 return 0; 2261} 2262 2263void invalidate_profile_options(const char *prof_name) 2264{ 2265 struct fio_option *o; 2266 2267 o = options; 2268 while (o->name) { 2269 if (o->prof_name && !strcmp(o->prof_name, prof_name)) { 2270 o->type = FIO_OPT_INVALID; 2271 o->prof_name = NULL; 2272 } 2273 o++; 2274 } 2275} 2276 2277void add_opt_posval(const char *optname, const char *ival, const char *help) 2278{ 2279 struct fio_option *o; 2280 unsigned int i; 2281 2282 o = find_option(options, optname); 2283 if (!o) 2284 return; 2285 2286 for (i = 0; i < PARSE_MAX_VP; i++) { 2287 if (o->posval[i].ival) 2288 continue; 2289 2290 o->posval[i].ival = ival; 2291 o->posval[i].help = help; 2292 break; 2293 } 2294} 2295 2296void del_opt_posval(const char *optname, const char *ival) 2297{ 2298 struct fio_option *o; 2299 unsigned int i; 2300 2301 o = find_option(options, optname); 2302 if (!o) 2303 return; 2304 2305 for (i = 0; i < PARSE_MAX_VP; i++) { 2306 if (!o->posval[i].ival) 2307 continue; 2308 if (strcmp(o->posval[i].ival, ival)) 2309 continue; 2310 2311 o->posval[i].ival = NULL; 2312 o->posval[i].help = NULL; 2313 } 2314} 2315