X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=init.c;h=7f64ce21a36aec1bedf4d609f7cb63866923643a;hp=42fc8a4ecc66e344135ebd9aa52efb2ac87d355a;hb=HEAD;hpb=a87c90fd72823d5438d724e5a57ced8d1f7bed3f diff --git a/init.c b/init.c index 42fc8a4e..ff3e9a90 100644 --- a/init.c +++ b/init.c @@ -224,6 +224,13 @@ static struct option l_opts[FIO_NR_OPTIONS] = { .has_arg = optional_argument, .val = 'S', }, +#ifdef WIN32 + { + .name = (char *) "server-internal", + .has_arg = required_argument, + .val = 'N', + }, +#endif { .name = (char *) "daemonize", .has_arg = required_argument, .val = 'D', @@ -327,6 +334,7 @@ void free_threads_shm(void) static void free_shm(void) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (nr_segments) { flow_exit(); fio_debug_jobp = NULL; @@ -343,6 +351,7 @@ static void free_shm(void) fio_filelock_exit(); file_hash_exit(); scleanup(); +#endif } static int add_thread_segment(void) @@ -446,19 +455,6 @@ static void dump_opt_list(struct thread_data *td) } } -static void fio_dump_options_free(struct thread_data *td) -{ - while (!flist_empty(&td->opt_list)) { - struct print_option *p; - - p = flist_first_entry(&td->opt_list, struct print_option, list); - flist_del_init(&p->list); - free(p->name); - free(p->value); - free(p); - } -} - static void copy_opt_list(struct thread_data *dst, struct thread_data *src) { struct flist_head *entry; @@ -622,6 +618,19 @@ static int fixup_options(struct thread_data *td) ret |= 1; } + if (td_trimwrite(td) && o->num_range > 1) { + log_err("fio: trimwrite cannot be used with multiple" + " ranges.\n"); + ret |= 1; + } + + if (td_trim(td) && o->num_range > 1 && + !td_ioengine_flagged(td, FIO_MULTI_RANGE_TRIM)) { + log_err("fio: can't use multiple ranges with IO engine %s\n", + td->io_ops->name); + ret |= 1; + } + #ifndef CONFIG_PSHARED if (!o->use_thread) { log_info("fio: this platform does not support process shared" @@ -644,6 +653,11 @@ static int fixup_options(struct thread_data *td) ret |= 1; } + if (o->zone_mode == ZONE_MODE_ZBD && !o->create_serialize) { + log_err("fio: --zonemode=zbd and --create_serialize=0 are not compatible.\n"); + ret |= 1; + } + if (o->zone_mode == ZONE_MODE_STRIDED && !o->zone_size) { log_err("fio: --zonesize must be specified when using --zonemode=strided.\n"); ret |= 1; @@ -915,12 +929,6 @@ static int fixup_options(struct thread_data *td) ret |= 1; } - /* - * O_ATOMIC implies O_DIRECT - */ - if (o->oatomic) - o->odirect = 1; - /* * If randseed is set, that overrides randrepeat */ @@ -956,12 +964,66 @@ static int fixup_options(struct thread_data *td) if (o->disable_slat) o->slat_percentiles = 0; + /* Do this only for the parent job */ + if (!td->subjob_number) { + /* + * Fix these up to be nsec internally + */ + for_each_rw_ddir(ddir) + o->max_latency[ddir] *= 1000ULL; + + o->latency_target *= 1000ULL; + } + /* - * Fix these up to be nsec internally + * Dedupe working set verifications */ - o->max_latency *= 1000ULL; - o->latency_target *= 1000ULL; + if (o->dedupe_percentage && o->dedupe_mode == DEDUPE_MODE_WORKING_SET) { + if (!fio_option_is_set(o, size)) { + log_err("fio: pregenerated dedupe working set " + "requires size to be set\n"); + ret |= 1; + } else if (o->nr_files != 1) { + log_err("fio: dedupe working set mode supported with " + "single file per job, but %d files " + "provided\n", o->nr_files); + ret |= 1; + } else if (o->dedupe_working_set_percentage + o->dedupe_percentage > 100) { + log_err("fio: impossible to reach expected dedupe percentage %u " + "since %u percentage of size is reserved to dedupe working set " + "(those are unique pages)\n", + o->dedupe_percentage, o->dedupe_working_set_percentage); + ret |= 1; + } + } + + for_each_td(td2) { + if (td->o.ss_check_interval != td2->o.ss_check_interval) { + log_err("fio: conflicting ss_check_interval: %llu and %llu, must be globally equal\n", + td->o.ss_check_interval, td2->o.ss_check_interval); + ret |= 1; + } + } end_for_each(); + if (td->o.ss_dur && td->o.ss_check_interval / 1000L < 1000) { + log_err("fio: ss_check_interval must be at least 1s\n"); + ret |= 1; + } + if (td->o.ss_dur && (td->o.ss_dur % td->o.ss_check_interval != 0 || td->o.ss_dur <= td->o.ss_check_interval)) { + log_err("fio: ss_duration %lluus must be multiple of ss_check_interval %lluus\n", + td->o.ss_dur, td->o.ss_check_interval); + ret |= 1; + } + + if (td->o.fdp) { + if (fio_option_is_set(&td->o, dp_type) && + (td->o.dp_type == FIO_DP_STREAMS || td->o.dp_type == FIO_DP_NONE)) { + log_err("fio: fdp=1 is not compatible with dataplacement={streams, none}\n"); + ret |= 1; + } else { + td->o.dp_type = FIO_DP_FDP; + } + } return ret; } @@ -982,8 +1044,12 @@ static void init_rand_file_service(struct thread_data *td) } } -void td_fill_verify_state_seed(struct thread_data *td) +void td_fill_rand_seeds(struct thread_data *td) { + uint64_t read_seed = td->rand_seeds[FIO_RAND_BS_OFF]; + uint64_t write_seed = td->rand_seeds[FIO_RAND_BS1_OFF]; + uint64_t trim_seed = td->rand_seeds[FIO_RAND_BS2_OFF]; + int i; bool use64; if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64) @@ -991,17 +1057,6 @@ void td_fill_verify_state_seed(struct thread_data *td) else use64 = false; - init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF], - use64); -} - -static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64) -{ - uint64_t read_seed = td->rand_seeds[FIO_RAND_BS_OFF]; - uint64_t write_seed = td->rand_seeds[FIO_RAND_BS1_OFF]; - uint64_t trim_seed = td->rand_seeds[FIO_RAND_BS2_OFF]; - int i; - /* * trimwrite is special in that we need to generate the same * offsets to get the "write after trim" effect. If we are @@ -1018,7 +1073,8 @@ static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64) init_rand_seed(&td->bsrange_state[DDIR_WRITE], write_seed, use64); init_rand_seed(&td->bsrange_state[DDIR_TRIM], trim_seed, use64); - td_fill_verify_state_seed(td); + init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF], + use64); init_rand_seed(&td->rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF], false); if (td->o.file_service_type == FIO_FSERVICE_RANDOM) @@ -1035,12 +1091,7 @@ static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64) 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); init_rand_seed(&td->prio_state, td->rand_seeds[FIO_RAND_PRIO_CMDS], false); - - if (!td_random(td)) - return; - - if (td->o.rand_repeatable) - td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number; + init_rand_seed(&td->dedupe_working_set_index_state, td->rand_seeds[FIO_RAND_DEDUPE_WORKING_SET_IX], use64); init_rand_seed(&td->random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF], use64); @@ -1049,29 +1100,41 @@ static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64) init_rand_seed(s, td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF], false); } + + init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF], use64); + frand_copy(&td->buf_state_prev, &td->buf_state); + + init_rand_seed(&td->fdp_state, td->rand_seeds[FIO_RAND_FDP_OFF], use64); } -void td_fill_rand_seeds(struct thread_data *td) +static int setup_random_seeds(struct thread_data *td) { - bool use64; - - if (td->o.allrand_repeatable) { - unsigned int i; + uint64_t seed; + unsigned int i; - for (i = 0; i < FIO_RAND_NR_OFFS; i++) - td->rand_seeds[i] = FIO_RANDSEED * td->thread_number - + i; + 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)); + dprint(FD_RANDOM, "using system RNG for random seeds\n"); + if (ret) + return ret; + } else { + seed = td->o.rand_seed; + for (i = 0; i < 4; i++) + seed *= 0x9e370001UL; + + for (i = 0; i < FIO_RAND_NR_OFFS; i++) { + td->rand_seeds[i] = seed * td->thread_number + i; + seed *= 0x9e370001UL; + } } - if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64) - use64 = true; - else - use64 = false; + td_fill_rand_seeds(td); - td_fill_rand_seeds_internal(td, use64); + dprint(FD_RANDOM, "FIO_RAND_NR_OFFS=%d\n", FIO_RAND_NR_OFFS); + for (int i = 0; i < FIO_RAND_NR_OFFS; i++) + dprint(FD_RANDOM, "rand_seeds[%d]=%" PRIu64 "\n", i, td->rand_seeds[i]); - init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF], use64); - frand_copy(&td->buf_state_prev, &td->buf_state); + return 0; } /* @@ -1102,18 +1165,15 @@ int ioengine_load(struct thread_data *td) * for this name and see if they match. If they do, then * the engine is unchanged. */ - dlhandle = td->io_ops_dlhandle; + dlhandle = td->io_ops->dlhandle; ops = load_ioengine(td); if (!ops) goto fail; - if (ops == td->io_ops && dlhandle == td->io_ops_dlhandle) { - if (dlhandle) - dlclose(dlhandle); + if (ops == td->io_ops && dlhandle == td->io_ops->dlhandle) return 0; - } - if (dlhandle && dlhandle != td->io_ops_dlhandle) + if (dlhandle && dlhandle != td->io_ops->dlhandle) dlclose(dlhandle); /* Unload the old engine. */ @@ -1210,36 +1270,12 @@ static void init_flags(struct thread_data *td) } } -static int setup_random_seeds(struct thread_data *td) -{ - uint64_t seed; - unsigned int i; - - 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++) - seed *= 0x9e370001UL; - - for (i = 0; i < FIO_RAND_NR_OFFS; i++) { - td->rand_seeds[i] = seed * td->thread_number + i; - seed *= 0x9e370001UL; - } - - td_fill_rand_seeds(td); - return 0; -} - enum { FPRE_NONE = 0, FPRE_JOBNAME, FPRE_JOBNUM, - FPRE_FILENUM + FPRE_FILENUM, + FPRE_CLIENTUID }; static struct fpre_keyword { @@ -1250,6 +1286,7 @@ static struct fpre_keyword { { .keyword = "$jobname", .key = FPRE_JOBNAME, }, { .keyword = "$jobnum", .key = FPRE_JOBNUM, }, { .keyword = "$filenum", .key = FPRE_FILENUM, }, + { .keyword = "$clientuid", .key = FPRE_CLIENTUID, }, { .keyword = NULL, }, }; @@ -1339,6 +1376,21 @@ static char *make_filename(char *buf, size_t buf_size,struct thread_options *o, } break; } + case FPRE_CLIENTUID: { + int ret; + ret = snprintf(dst, dst_left, "%s", client_sockaddr_str); + if (ret < 0) + break; + else if (ret > dst_left) { + log_err("fio: truncated filename\n"); + dst += dst_left; + dst_left = 0; + } else { + dst += ret; + dst_left -= ret; + } + break; + } default: assert(0); break; @@ -1371,15 +1423,14 @@ static void gen_log_name(char *name, size_t size, const char *logtype, static int check_waitees(char *waitee) { - struct thread_data *td; - int i, ret = 0; + int ret = 0; - for_each_td(td, i) { + for_each_td(td) { if (td->subjob_number) continue; ret += !strcmp(td->o.name, waitee); - } + } end_for_each(); return ret; } @@ -1412,6 +1463,23 @@ static bool wait_for_ok(const char *jobname, struct thread_options *o) return true; } +static int verify_per_group_options(struct thread_data *td, const char *jobname) +{ + for_each_td(td2) { + if (td->groupid != td2->groupid) + continue; + + if (td->o.stats && + td->o.lat_percentiles != td2->o.lat_percentiles) { + log_err("fio: lat_percentiles in job: %s differs from group\n", + jobname); + return 1; + } + } end_for_each(); + + return 0; +} + /* * Treat an empty log file name the same as a one not given */ @@ -1481,6 +1549,9 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, if (fixup_options(td)) goto err; + if (!td->o.dedupe_global && init_dedupe_working_set_seeds(td, 0)) + goto err; + /* * Belongs to fixup_options, but o->name is not necessarily set as yet */ @@ -1512,17 +1583,15 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, 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; - 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->ts.clat_high_prio_stat[i].min_val = ULONG_MAX; - td->ts.clat_low_prio_stat[i].min_val = ULONG_MAX; - } - td->ts.sync_stat.min_val = ULONG_MAX; - td->ddir_seq_nr = o->ddir_seq_nr; + init_thread_stat_min_vals(&td->ts); + + /* + * td->>ddir_seq_nr needs to be initialized to 1, NOT o->ddir_seq_nr, + * so that get_next_offset gets a new random offset the first time it + * is called, instead of keeping an initial offset of 0 for the first + * nr-1 calls + */ + td->ddir_seq_nr = 1; if ((o->stonewall || o->new_group) && prev_group_jobs) { prev_group_jobs = 0; @@ -1536,6 +1605,10 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, td->groupid = groupid; prev_group_jobs++; + if (td->o.group_reporting && prev_group_jobs > 1 && + verify_per_group_options(td, jobname)) + goto err; + if (setup_rate(td)) goto err; @@ -1547,6 +1620,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, .hist_coarseness = o->log_hist_coarseness, .log_type = IO_LOG_TYPE_LAT, .log_offset = o->log_offset, + .log_prio = o->log_prio, .log_gz = o->log_gz, .log_gz_store = o->log_gz_store, }; @@ -1558,17 +1632,23 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, else suf = "log"; - gen_log_name(logname, sizeof(logname), "lat", pre, - td->thread_number, suf, o->per_job_logs); - setup_log(&td->lat_log, &p, logname); + if (!o->disable_lat) { + gen_log_name(logname, sizeof(logname), "lat", pre, + td->thread_number, suf, o->per_job_logs); + setup_log(&td->lat_log, &p, logname); + } - gen_log_name(logname, sizeof(logname), "slat", pre, - td->thread_number, suf, o->per_job_logs); - setup_log(&td->slat_log, &p, logname); + if (!o->disable_slat) { + gen_log_name(logname, sizeof(logname), "slat", pre, + td->thread_number, suf, o->per_job_logs); + setup_log(&td->slat_log, &p, logname); + } - gen_log_name(logname, sizeof(logname), "clat", pre, - td->thread_number, suf, o->per_job_logs); - setup_log(&td->clat_log, &p, logname); + if (!o->disable_clat) { + gen_log_name(logname, sizeof(logname), "clat", pre, + td->thread_number, suf, o->per_job_logs); + setup_log(&td->clat_log, &p, logname); + } } @@ -1580,6 +1660,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, .hist_coarseness = o->log_hist_coarseness, .log_type = IO_LOG_TYPE_HIST, .log_offset = o->log_offset, + .log_prio = o->log_prio, .log_gz = o->log_gz, .log_gz_store = o->log_gz_store, }; @@ -1611,6 +1692,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, .hist_coarseness = o->log_hist_coarseness, .log_type = IO_LOG_TYPE_BW, .log_offset = o->log_offset, + .log_prio = o->log_prio, .log_gz = o->log_gz, .log_gz_store = o->log_gz_store, }; @@ -1642,6 +1724,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, .hist_coarseness = o->log_hist_coarseness, .log_type = IO_LOG_TYPE_IOPS, .log_offset = o->log_offset, + .log_prio = o->log_prio, .log_gz = o->log_gz, .log_gz_store = o->log_gz_store, }; @@ -1889,8 +1972,7 @@ static int __parse_jobs_ini(struct thread_data *td, * it's really 256 + small bit, 280 should suffice */ if (!nested) { - name = malloc(280); - memset(name, 0, 280); + name = calloc(1, 280); } opts = NULL; @@ -2110,6 +2192,10 @@ static int __parse_jobs_ini(struct thread_data *td, i++; } + free(job_sections); + job_sections = NULL; + nr_job_sections = 0; + free(opts); out: free(string); @@ -2190,7 +2276,7 @@ static void usage(const char *name) printf(" --minimal\t\tMinimal (terse) output\n"); printf(" --output-format=type\tOutput format (terse,json,json+,normal)\n"); printf(" --terse-version=type\tSet terse version output format" - " (default 3, or 2 or 4)\n"); + " (default 3, or 2 or 4 or 5)\n"); 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"); @@ -2731,6 +2817,15 @@ int parse_cmd_line(int argc, char *argv[], int client_type) break; ret = fio_cmd_ioengine_option_parse(td, opt, val); + + if (ret) { + if (td) { + put_job(td); + td = NULL; + } + do_exit++; + exit_val = 1; + } break; } case 'w': @@ -2758,6 +2853,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type) exit_val = 1; #endif break; +#ifdef WIN32 + case 'N': + did_arg = true; + fio_server_internal_set(optarg); + break; +#endif case 'D': if (pid_file) free(pid_file); @@ -2905,7 +3006,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) log_err("%s: unrecognized option '%s'\n", argv[0], argv[optind - 1]); show_closest_option(argv[optind - 1]); - fallthrough; + fio_fallthrough; default: do_exit++; exit_val = 1;