X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=init.c;h=25661bef6e72fa3dadede80073d2dcef9eabd6ad;hp=42e710715a250e2eca8f2a6a8cd7c609e6571455;hb=3c0a8bc2f33ba721a97b459d5b32acbf4460450f;hpb=cbbdf1c8f1aa13c9030808720e04ea1081fd57eb diff --git a/init.c b/init.c index 42e71071..25661bef 100644 --- a/init.c +++ b/init.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "fio.h" #ifndef FIO_NO_HAVE_SHM_H @@ -32,6 +33,7 @@ #include "crc/test.h" #include "lib/pow2.h" +#include "lib/memcpy.h" const char fio_version_string[] = FIO_VERSION; @@ -50,6 +52,7 @@ static int nr_job_sections; int exitall_on_terminate = 0; int output_format = FIO_OUTPUT_NORMAL; int eta_print = FIO_ETA_AUTO; +unsigned int eta_interval_msec = 1000; int eta_new_line = 0; FILE *f_out = NULL; FILE *f_err = NULL; @@ -78,7 +81,7 @@ unsigned int fio_debug_jobno = -1; unsigned int *fio_debug_jobp = NULL; static char cmd_optstr[256]; -static int did_arg; +static bool did_arg; #define FIO_CLIENT_FLAG (1 << 16) @@ -152,6 +155,11 @@ static struct option l_opts[FIO_NR_OPTIONS] = { .has_arg = required_argument, .val = 'e' | FIO_CLIENT_FLAG, }, + { + .name = (char *) "eta-interval", + .has_arg = required_argument, + .val = 'O' | FIO_CLIENT_FLAG, + }, { .name = (char *) "eta-newline", .has_arg = required_argument, @@ -233,6 +241,11 @@ static struct option l_opts[FIO_NR_OPTIONS] = { .has_arg = optional_argument, .val = 'G', }, + { + .name = (char *) "memcpytest", + .has_arg = optional_argument, + .val = 'M', + }, { .name = (char *) "idle-prof", .has_arg = required_argument, @@ -698,6 +711,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 +761,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; @@ -755,11 +802,12 @@ static int fixup_options(struct thread_data *td) o->verify_interval = o->min_bs[DDIR_READ]; /* - * Verify interval must be a factor or both min and max + * Verify interval must be a factor of both min and max * write size */ - if (o->verify_interval % o->min_bs[DDIR_WRITE] || - o->verify_interval % o->max_bs[DDIR_WRITE]) + if (!o->verify_interval || + (o->min_bs[DDIR_WRITE] % o->verify_interval) || + (o->max_bs[DDIR_WRITE] % o->verify_interval)) o->verify_interval = gcd(o->min_bs[DDIR_WRITE], o->max_bs[DDIR_WRITE]); } @@ -803,7 +851,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"); @@ -821,16 +869,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 @@ -844,16 +894,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; } @@ -868,28 +918,40 @@ 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; -} + 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; + } -/* External engines are specified by "external:name.o") */ -static const char *get_engine_name(const char *str) -{ - char *p = strstr(str, ":"); + if (o->disable_lat) + o->lat_percentiles = 0; + if (o->disable_clat) + o->clat_percentiles = 0; - if (!p) - return str; + /* + * Fix these up to be nsec internally + */ + o->max_latency *= 1000ULL; + o->latency_target *= 1000ULL; + o->latency_window *= 1000ULL; - p++; - strip_blank_front(&p); - strip_blank_end(p); - return p; + return ret; } static void init_rand_file_service(struct thread_data *td) @@ -1003,14 +1065,15 @@ void td_fill_rand_seeds(struct thread_data *td) */ int ioengine_load(struct thread_data *td) { - const char *engine; - if (!td->o.ioengine) { log_err("fio: internal fault, no IO engine specified\n"); return 1; } if (td->io_ops) { + struct ioengine_ops *ops; + void *dlhandle; + /* An engine is loaded, but the requested ioengine * may have changed. */ @@ -1019,14 +1082,29 @@ int ioengine_load(struct thread_data *td) return 0; } + /* + * Name of file and engine may be different, load ops + * for this name and see if they match. If they do, then + * the engine is unchanged. + */ + dlhandle = td->io_ops_dlhandle; + ops = load_ioengine(td); + if (ops == td->io_ops && dlhandle == td->io_ops_dlhandle) { + if (dlhandle) + dlclose(dlhandle); + return 0; + } + + if (dlhandle && dlhandle != td->io_ops_dlhandle) + dlclose(dlhandle); + /* Unload the old engine. */ free_ioengine(td); } - engine = get_engine_name(td->o.ioengine); - td->io_ops = load_ioengine(td, engine); + 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; } @@ -1072,6 +1150,7 @@ int ioengine_load(struct thread_data *td) static void init_flags(struct thread_data *td) { struct thread_options *o = &td->o; + int i; if (o->verify_backlog) td->flags |= TD_F_VER_BACKLOG; @@ -1101,6 +1180,13 @@ static void init_flags(struct thread_data *td) if (o->mem_type == MEM_CUDA_MALLOC) td->flags &= ~TD_F_SCRAMBLE_BUFFERS; + + for (i = 0; i < DDIR_RWDIR_CNT; i++) { + if (option_check_rate(td, i)) { + td->flags |= TD_F_CHECK_RATE; + break; + } + } } static int setup_random_seeds(struct thread_data *td) @@ -1384,8 +1470,10 @@ 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)); + td->ts.sig_figs = o->sig_figs; for (i = 0; i < DDIR_RWDIR_CNT; i++) { td->ts.clat_stat[i].min_val = ULONG_MAX; @@ -1394,6 +1482,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, td->ts.bw_stat[i].min_val = ULONG_MAX; td->ts.iops_stat[i].min_val = ULONG_MAX; } + td->ts.sync_stat.min_val = ULONG_MAX; td->ddir_seq_nr = o->ddir_seq_nr; if ((o->stonewall || o->new_group) && prev_group_jobs) { @@ -1497,7 +1586,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, p.avg_msec = min(o->log_avg_msec, o->bw_avg_time); else o->bw_avg_time = p.avg_msec; - + p.hist_msec = o->log_hist_msec; p.hist_coarseness = o->log_hist_coarseness; @@ -1528,7 +1617,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, p.avg_msec = min(o->log_avg_msec, o->iops_avg_time); else o->iops_avg_time = p.avg_msec; - + p.hist_msec = o->log_hist_msec; p.hist_coarseness = o->log_hist_coarseness; @@ -1555,14 +1644,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, @@ -2083,13 +2172,11 @@ 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"); - printf("\nFio was written by Jens Axboe "); - printf("\n Jens Axboe "); - printf("\n Jens Axboe \n"); + printf("\nFio was written by Jens Axboe \n"); } #ifdef FIO_INC_DEBUG @@ -2396,35 +2483,35 @@ int parse_cmd_line(int argc, char *argv[], int client_type) output_format |= FIO_OUTPUT_TERSE; break; case 'h': - did_arg = 1; + did_arg = true; if (!cur_client) { usage(argv[0]); do_exit++; } break; case 'c': - did_arg = 1; + did_arg = true; if (!cur_client) { fio_show_option_help(optarg); do_exit++; } break; case 'i': - did_arg = 1; + did_arg = true; if (!cur_client) { fio_show_ioengine_help(optarg); do_exit++; } break; case 's': - did_arg = 1; + did_arg = true; dump_cmdline = 1; break; case 'r': read_only = 1; break; case 'v': - did_arg = 1; + did_arg = true; if (!cur_client) { log_info("%s\n", fio_version_string); do_exit++; @@ -2451,8 +2538,31 @@ int parse_cmd_line(int argc, char *argv[], int client_type) log_err("fio: failed parsing eta time %s\n", optarg); exit_val = 1; do_exit++; + break; } eta_new_line = t / 1000; + if (!eta_new_line) { + log_err("fio: eta new line time too short\n"); + exit_val = 1; + do_exit++; + } + break; + } + case 'O': { + long long t = 0; + + if (check_str_time(optarg, &t, 1)) { + log_err("fio: failed parsing eta interval %s\n", optarg); + exit_val = 1; + do_exit++; + break; + } + eta_interval_msec = t / 1000; + if (eta_interval_msec < DISK_UTIL_MSEC) { + log_err("fio: eta interval time too short (%umsec min)\n", DISK_UTIL_MSEC); + exit_val = 1; + do_exit++; + } break; } case 'd': @@ -2460,7 +2570,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) do_exit++; break; case 'P': - did_arg = 1; + did_arg = true; parse_only = 1; break; case 'x': { @@ -2482,12 +2592,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type) #ifdef CONFIG_ZLIB case 'X': exit_val = iolog_file_inflate(optarg); - did_arg++; + did_arg = true; do_exit++; break; #endif case 'p': - did_arg = 1; + did_arg = true; if (exec_profile) free(exec_profile); exec_profile = strdup(optarg); @@ -2501,7 +2611,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) if (ret) goto out_free; td = NULL; - did_arg = 1; + did_arg = true; } if (!td) { int is_section = !strncmp(opt, "name", 4); @@ -2576,7 +2686,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) } break; case 'S': - did_arg = 1; + did_arg = true; #ifndef CONFIG_NO_SHM if (nr_clients) { log_err("fio: can't be both client and server\n"); @@ -2602,14 +2712,14 @@ int parse_cmd_line(int argc, char *argv[], int client_type) case 'I': if ((ret = fio_idle_prof_parse_opt(optarg))) { /* exit on error and calibration only */ - did_arg = 1; + did_arg = true; do_exit++; if (ret == -1) exit_val = 1; } break; case 'C': - did_arg = 1; + did_arg = true; if (is_backend) { log_err("fio: can't be both client and server\n"); do_exit++; @@ -2666,22 +2776,27 @@ int parse_cmd_line(int argc, char *argv[], int client_type) } break; case 'R': - did_arg = 1; + did_arg = true; if (fio_client_add_ini_file(cur_client, optarg, true)) { do_exit++; exit_val = 1; } break; case 'T': - did_arg = 1; + did_arg = true; do_exit++; exit_val = fio_monotonic_clocktest(1); break; case 'G': - did_arg = 1; + did_arg = true; do_exit++; exit_val = fio_crctest(optarg); break; + case 'M': + did_arg = true; + do_exit++; + exit_val = fio_memcpy_test(optarg); + break; case 'L': { long long val; @@ -2691,6 +2806,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; } @@ -2831,13 +2951,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)