X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=init.c;h=c70f6a0a125549d073d7b273b68fde8a1ae2356e;hp=2f9433b40deea2110dc2aa738244959606c97bdd;hb=a2e4a0937bff2e93121ee8b6202c5f858f10d6fa;hpb=49d719fc52d3d2164c55a16193cb2880b515b46f diff --git a/init.c b/init.c index 2f9433b4..c70f6a0a 100644 --- a/init.c +++ b/init.c @@ -361,7 +361,7 @@ static int setup_thread_area(void) #endif memset(threads, 0, max_jobs * sizeof(struct thread_data)); - fio_debug_jobp = (void *) threads + max_jobs * sizeof(struct thread_data); + fio_debug_jobp = (unsigned int *)(threads + max_jobs); *fio_debug_jobp = -1; flow_init(); @@ -523,7 +523,7 @@ static int __setup_rate(struct thread_data *td, enum fio_ddir ddir) td->rate_next_io_time[ddir] = 0; td->rate_io_issue_bytes[ddir] = 0; - td->last_usec = 0; + td->last_usec[ddir] = 0; return 0; } @@ -698,6 +698,23 @@ static int fixup_options(struct thread_data *td) if (o->iodepth_batch_complete_min > o->iodepth_batch_complete_max) o->iodepth_batch_complete_max = o->iodepth_batch_complete_min; + /* + * There's no need to check for in-flight overlapping IOs if the job + * isn't changing data or the maximum iodepth is guaranteed to be 1 + */ + if (o->serialize_overlap && !(td->flags & TD_F_READ_IOLOG) && + (!(td_write(td) || td_trim(td)) || o->iodepth == 1)) + o->serialize_overlap = 0; + /* + * Currently can't check for overlaps in offload mode + */ + if (o->serialize_overlap && o->io_submit_mode == IO_MODE_OFFLOAD) { + log_err("fio: checking for in-flight overlaps when the " + "io_submit_mode is offload is not supported\n"); + o->serialize_overlap = 0; + ret = warnings_fatal; + } + if (o->nr_files > td->files_index) o->nr_files = td->files_index; @@ -731,13 +748,30 @@ static int fixup_options(struct thread_data *td) o->size = -1ULL; if (o->verify != VERIFY_NONE) { - if (td_write(td) && o->do_verify && o->numjobs > 1) { - log_info("Multiple writers may overwrite blocks that " - "belong to other jobs. This can cause " + if (td_write(td) && o->do_verify && o->numjobs > 1 && + (o->filename || + !(o->unique_filename && + strstr(o->filename_format, "$jobname") && + strstr(o->filename_format, "$jobnum") && + strstr(o->filename_format, "$filenum")))) { + log_info("fio: multiple writers may overwrite blocks " + "that belong to other jobs. This can cause " "verification failures.\n"); ret = warnings_fatal; } + /* + * Warn if verification is requested but no verification of any + * kind can be started due to time constraints + */ + if (td_write(td) && o->do_verify && o->timeout && + o->time_based && !td_read(td) && !o->verify_backlog) { + log_info("fio: verification read phase will never " + "start because write phase uses all of " + "runtime\n"); + ret = warnings_fatal; + } + if (!fio_option_is_set(o, refill_buffers)) o->refill_buffers = 1; @@ -781,6 +815,11 @@ static int fixup_options(struct thread_data *td) o->unit_base = 8; } +#ifndef FIO_HAVE_ANY_FALLOCATE + /* Platform doesn't support any fallocate so force it to none */ + o->fallocate_mode = FIO_FALLOCATE_NONE; +#endif + #ifndef CONFIG_FDATASYNC if (o->fdatasync_blocks) { log_info("fio: this platform does not support fdatasync()" @@ -798,7 +837,7 @@ static int fixup_options(struct thread_data *td) * Windows doesn't support O_DIRECT or O_SYNC with the _open interface, * so fail if we're passed those flags */ - if (td_ioengine_flagged(td, FIO_SYNCIO) && (td->o.odirect || td->o.sync_io)) { + if (td_ioengine_flagged(td, FIO_SYNCIO) && (o->odirect || o->sync_io)) { log_err("fio: Windows does not support direct or non-buffered io with" " the synchronous ioengines. Use the 'windowsaio' ioengine" " with 'direct=1' and 'iodepth=1' instead.\n"); @@ -816,16 +855,18 @@ static int fixup_options(struct thread_data *td) if (o->compress_percentage == 100) { o->zero_buffers = 1; o->compress_percentage = 0; - } else if (!fio_option_is_set(o, refill_buffers)) + } else if (!fio_option_is_set(o, refill_buffers)) { o->refill_buffers = 1; + td->flags |= TD_F_REFILL_BUFFERS; + } } /* * Using a non-uniform random distribution excludes usage of * a random map */ - if (td->o.random_distribution != FIO_RAND_DIST_RANDOM) - td->o.norandommap = 1; + if (o->random_distribution != FIO_RAND_DIST_RANDOM) + o->norandommap = 1; /* * If size is set but less than the min block size, complain @@ -839,16 +880,16 @@ static int fixup_options(struct thread_data *td) /* * O_ATOMIC implies O_DIRECT */ - if (td->o.oatomic) - td->o.odirect = 1; + if (o->oatomic) + o->odirect = 1; /* * If randseed is set, that overrides randrepeat */ - if (fio_option_is_set(&td->o, rand_seed)) - td->o.rand_repeatable = 0; + if (fio_option_is_set(o, rand_seed)) + o->rand_repeatable = 0; - if (td_ioengine_flagged(td, FIO_NOEXTEND) && td->o.file_append) { + if (td_ioengine_flagged(td, FIO_NOEXTEND) && o->file_append) { log_err("fio: can't append/extent with IO engine %s\n", td->io_ops->name); ret = 1; } @@ -863,28 +904,28 @@ static int fixup_options(struct thread_data *td) if (!td->loops) td->loops = 1; - if (td->o.block_error_hist && td->o.nr_files != 1) { + if (o->block_error_hist && o->nr_files != 1) { log_err("fio: block error histogram only available " "with a single file per job, but %d files " - "provided\n", td->o.nr_files); + "provided\n", o->nr_files); ret = 1; } - return ret; -} - -/* External engines are specified by "external:name.o") */ -static const char *get_engine_name(const char *str) -{ - char *p = strstr(str, ":"); - - if (!p) - return str; + if (fio_option_is_set(o, clat_percentiles) && + !fio_option_is_set(o, lat_percentiles)) { + o->lat_percentiles = !o->clat_percentiles; + } else if (fio_option_is_set(o, lat_percentiles) && + !fio_option_is_set(o, clat_percentiles)) { + o->clat_percentiles = !o->lat_percentiles; + } else if (fio_option_is_set(o, lat_percentiles) && + fio_option_is_set(o, clat_percentiles) && + o->lat_percentiles && o->clat_percentiles) { + log_err("fio: lat_percentiles and clat_percentiles are " + "mutually exclusive\n"); + ret = 1; + } - p++; - strip_blank_front(&p); - strip_blank_end(p); - return p; + return ret; } static void init_rand_file_service(struct thread_data *td) @@ -909,9 +950,9 @@ void td_fill_verify_state_seed(struct thread_data *td) bool use64; if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64) - use64 = 1; + use64 = true; else - use64 = 0; + use64 = false; init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF], use64); @@ -921,7 +962,22 @@ static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64) { int i; - init_rand_seed(&td->bsrange_state, td->rand_seeds[FIO_RAND_BS_OFF], use64); + /* + * trimwrite is special in that we need to generate the same + * offsets to get the "write after trim" effect. If we are + * using bssplit to set buffer length distributions, ensure that + * we seed the trim and write generators identically. + */ + if (td_trimwrite(td)) { + init_rand_seed(&td->bsrange_state[DDIR_READ], td->rand_seeds[FIO_RAND_BS_OFF], use64); + init_rand_seed(&td->bsrange_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_BS1_OFF], use64); + init_rand_seed(&td->bsrange_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_BS1_OFF], use64); + } else { + init_rand_seed(&td->bsrange_state[DDIR_READ], td->rand_seeds[FIO_RAND_BS_OFF], use64); + init_rand_seed(&td->bsrange_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_BS1_OFF], use64); + init_rand_seed(&td->bsrange_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_BS2_OFF], use64); + } + td_fill_verify_state_seed(td); init_rand_seed(&td->rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF], false); @@ -933,7 +989,9 @@ static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64) init_rand_seed(&td->file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], use64); init_rand_seed(&td->trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF], use64); init_rand_seed(&td->delay_state, td->rand_seeds[FIO_RAND_START_DELAY], use64); - init_rand_seed(&td->poisson_state, td->rand_seeds[FIO_RAND_POISSON_OFF], 0); + init_rand_seed(&td->poisson_state[0], td->rand_seeds[FIO_RAND_POISSON_OFF], 0); + init_rand_seed(&td->poisson_state[1], td->rand_seeds[FIO_RAND_POISSON2_OFF], 0); + init_rand_seed(&td->poisson_state[2], td->rand_seeds[FIO_RAND_POISSON3_OFF], 0); init_rand_seed(&td->dedupe_state, td->rand_seeds[FIO_DEDUPE_OFF], false); init_rand_seed(&td->zone_state, td->rand_seeds[FIO_RAND_ZONE_OFF], false); @@ -965,9 +1023,9 @@ void td_fill_rand_seeds(struct thread_data *td) } if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64) - use64 = 1; + use64 = true; else - use64 = 0; + use64 = false; td_fill_rand_seeds_internal(td, use64); @@ -981,22 +1039,27 @@ void td_fill_rand_seeds(struct thread_data *td) */ int ioengine_load(struct thread_data *td) { - const char *engine; - - /* - * Engine has already been loaded. - */ - if (td->io_ops) - return 0; if (!td->o.ioengine) { log_err("fio: internal fault, no IO engine specified\n"); return 1; } - engine = get_engine_name(td->o.ioengine); - td->io_ops = load_ioengine(td, engine); + if (td->io_ops) { + /* An engine is loaded, but the requested ioengine + * may have changed. + */ + if (!strcmp(td->io_ops->name, td->o.ioengine)) { + /* The right engine is already loaded */ + return 0; + } + + /* Unload the old engine. */ + free_ioengine(td); + } + + td->io_ops = load_ioengine(td); if (!td->io_ops) { - log_err("fio: failed to load engine %s\n", engine); + log_err("fio: failed to load engine\n"); return 1; } @@ -1068,6 +1131,9 @@ static void init_flags(struct thread_data *td) if (o->verify_async || o->io_submit_mode == IO_MODE_OFFLOAD) td->flags |= TD_F_NEED_LOCK; + + if (o->mem_type == MEM_CUDA_MALLOC) + td->flags &= ~TD_F_SCRAMBLE_BUFFERS; } static int setup_random_seeds(struct thread_data *td) @@ -1075,8 +1141,12 @@ static int setup_random_seeds(struct thread_data *td) unsigned long seed; unsigned int i; - if (!td->o.rand_repeatable && !fio_option_is_set(&td->o, rand_seed)) - return init_random_state(td, td->rand_seeds, sizeof(td->rand_seeds)); + if (!td->o.rand_repeatable && !fio_option_is_set(&td->o, rand_seed)) { + int ret = init_random_seeds(td->rand_seeds, sizeof(td->rand_seeds)); + if (!ret) + td_fill_rand_seeds(td); + return ret; + } seed = td->o.rand_seed; for (i = 0; i < 4; i++) @@ -1347,6 +1417,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, td->mutex = fio_mutex_init(FIO_MUTEX_LOCKED); td->ts.clat_percentiles = o->clat_percentiles; + td->ts.lat_percentiles = o->lat_percentiles; td->ts.percentile_precision = o->percentile_precision; memcpy(td->ts.percentile_list, o->percentile_list, sizeof(o->percentile_list)); @@ -1355,6 +1426,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, td->ts.slat_stat[i].min_val = ULONG_MAX; td->ts.lat_stat[i].min_val = ULONG_MAX; td->ts.bw_stat[i].min_val = ULONG_MAX; + td->ts.iops_stat[i].min_val = ULONG_MAX; } td->ddir_seq_nr = o->ddir_seq_nr; @@ -1371,7 +1443,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, prev_group_jobs++; if (setup_random_seeds(td)) { - td_verror(td, errno, "init_random_state"); + td_verror(td, errno, "setup_random_seeds"); goto err; } @@ -1517,14 +1589,14 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, char *c5 = NULL, *c6 = NULL; int i2p = is_power_of_2(o->kb_base); - c1 = num2str(o->min_bs[DDIR_READ], 4, 1, i2p, N2S_BYTE); - c2 = num2str(o->max_bs[DDIR_READ], 4, 1, i2p, N2S_BYTE); - c3 = num2str(o->min_bs[DDIR_WRITE], 4, 1, i2p, N2S_BYTE); - c4 = num2str(o->max_bs[DDIR_WRITE], 4, 1, i2p, N2S_BYTE); + c1 = num2str(o->min_bs[DDIR_READ], o->sig_figs, 1, i2p, N2S_BYTE); + c2 = num2str(o->max_bs[DDIR_READ], o->sig_figs, 1, i2p, N2S_BYTE); + c3 = num2str(o->min_bs[DDIR_WRITE], o->sig_figs, 1, i2p, N2S_BYTE); + c4 = num2str(o->max_bs[DDIR_WRITE], o->sig_figs, 1, i2p, N2S_BYTE); if (!o->bs_is_seq_rand) { - c5 = num2str(o->min_bs[DDIR_TRIM], 4, 1, i2p, N2S_BYTE); - c6 = num2str(o->max_bs[DDIR_TRIM], 4, 1, i2p, N2S_BYTE); + c5 = num2str(o->min_bs[DDIR_TRIM], o->sig_figs, 1, i2p, N2S_BYTE); + c6 = num2str(o->max_bs[DDIR_TRIM], o->sig_figs, 1, i2p, N2S_BYTE); } log_info("%s: (g=%d): rw=%s, ", td->o.name, @@ -2012,7 +2084,7 @@ static void usage(const char *name) printf(" --version\t\tPrint version info and exit\n"); printf(" --help\t\tPrint this page\n"); printf(" --cpuclock-test\tPerform test/validation of CPU clock\n"); - printf(" --crctest=type\tTest speed of checksum functions\n"); + printf(" --crctest=[type]\tTest speed of checksum functions\n"); printf(" --cmdhelp=cmd\t\tPrint command help, \"all\" for all of" " them\n"); printf(" --enghelp=engine\tPrint ioengine help, or list" @@ -2045,7 +2117,7 @@ static void usage(const char *name) printf(" --inflate-log=log\tInflate and output compressed log\n"); #endif printf(" --trigger-file=file\tExecute trigger cmd when file exists\n"); - printf(" --trigger-timeout=t\tExecute trigger af this time\n"); + printf(" --trigger-timeout=t\tExecute trigger at this time\n"); printf(" --trigger=cmd\t\tSet this command as local trigger\n"); printf(" --trigger-remote=cmd\tSet this command as remote trigger\n"); printf(" --aux-path=path\tUse this path for fio state generated files\n"); @@ -2394,8 +2466,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) break; case 'V': terse_version = atoi(optarg); - if (!(terse_version == 2 || terse_version == 3 || - terse_version == 4)) { + if (!(terse_version >= 2 && terse_version <= 5)) { log_err("fio: bad terse version format\n"); exit_val = 1; do_exit++; @@ -2506,7 +2577,6 @@ int parse_cmd_line(int argc, char *argv[], int client_type) } if (!ret && !strcmp(opt, "ioengine")) { - free_ioengine(td); if (ioengine_load(td)) { put_job(td); td = NULL; @@ -2655,6 +2725,11 @@ int parse_cmd_line(int argc, char *argv[], int client_type) exit_val = 1; break; } + if (val < 1000) { + log_err("fio: status interval too small\n"); + do_exit++; + exit_val = 1; + } status_interval = val / 1000; break; } @@ -2795,13 +2870,8 @@ int parse_options(int argc, char *argv[]) return 0; log_err("No job(s) defined\n\n"); - - if (!did_arg) { - usage(argv[0]); - return 1; - } - - return 0; + usage(argv[0]); + return 1; } if (output_format & FIO_OUTPUT_NORMAL)