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