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