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