X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=init.c;h=62c7dc2472c9f67625a6b3a97d37d8847a185931;hp=21779c7b162fda0dadeb9f2238d7a334f7c7f3db;hb=69bdd6badc47775443413405e1aea4abe9e570c9;hpb=b400a20e5d688f3498b2e3e9ce5567d3496dd746 diff --git a/init.c b/init.c index 21779c7b..62c7dc24 100644 --- a/init.c +++ b/init.c @@ -64,8 +64,6 @@ int write_bw_log = 0; int read_only = 0; int status_interval = 0; -static int write_lat_log; - static int prev_group_jobs; unsigned long fio_debug = 0; @@ -172,6 +170,13 @@ static struct option l_opts[FIO_NR_OPTIONS] = { .has_arg = required_argument, .val = 'x' | FIO_CLIENT_FLAG, }, +#ifdef CONFIG_ZLIB + { + .name = (char *) "inflate-log", + .has_arg = required_argument, + .val = 'X' | FIO_CLIENT_FLAG, + }, +#endif { .name = (char *) "alloc-size", .has_arg = required_argument, @@ -238,15 +243,19 @@ static struct option l_opts[FIO_NR_OPTIONS] = { void free_threads_shm(void) { - struct shmid_ds sbuf; - if (threads) { void *tp = threads; +#ifndef CONFIG_NO_SHM + struct shmid_ds sbuf; threads = NULL; shmdt(tp); shmctl(shm_id, IPC_RMID, &sbuf); shm_id = -1; +#else + threads = NULL; + free(tp); +#endif } } @@ -287,6 +296,7 @@ static int setup_thread_area(void) size += file_hash_size; size += sizeof(unsigned int); +#ifndef CONFIG_NO_SHM shm_id = shmget(0, size, IPC_CREAT | 0600); if (shm_id != -1) break; @@ -294,10 +304,16 @@ static int setup_thread_area(void) perror("shmget"); break; } +#else + threads = malloc(size); + if (threads) + break; +#endif max_jobs >>= 1; } while (max_jobs); +#ifndef CONFIG_NO_SHM if (shm_id == -1) return 1; @@ -306,6 +322,7 @@ static int setup_thread_area(void) perror("shmat"); return 1; } +#endif memset(threads, 0, max_jobs * sizeof(struct thread_data)); hash = (void *) threads + max_jobs * sizeof(struct thread_data); @@ -330,7 +347,7 @@ static void set_cmd_options(struct thread_data *td) * Return a free job structure. */ static struct thread_data *get_new_job(int global, struct thread_data *parent, - int preserve_eo) + int preserve_eo, const char *jobname) { struct thread_data *td; @@ -363,6 +380,10 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent, profile_add_hooks(td); td->thread_number = thread_number; + td->subjob_number = 0; + + if (jobname) + td->o.name = strdup(jobname); if (!parent->o.group_reporting) stat_number++; @@ -386,6 +407,9 @@ static void put_job(struct thread_data *td) if (td->io_ops) free_ioengine(td); + if (td->o.name) + free(td->o.name); + memset(&threads[td->thread_number - 1], 0, sizeof(*td)); thread_number--; } @@ -612,6 +636,15 @@ static int fixup_options(struct thread_data *td) if (o->max_bs[DDIR_WRITE] != o->min_bs[DDIR_WRITE] && !o->verify_interval) o->verify_interval = o->min_bs[DDIR_WRITE]; + + /* + * Verify interval must be smaller or equal to the + * write size. + */ + if (o->verify_interval > o->min_bs[DDIR_WRITE]) + o->verify_interval = o->min_bs[DDIR_WRITE]; + else if (td_read(td) && o->verify_interval > o->min_bs[DDIR_READ]) + o->verify_interval = o->min_bs[DDIR_READ]; } if (o->pre_read) { @@ -937,7 +970,7 @@ static struct fpre_keyword { { .keyword = NULL, }, }; -static char *make_filename(char *buf, struct thread_options *o, +static char *make_filename(char *buf, size_t buf_size,struct thread_options *o, const char *jobname, int jobnum, int filenum) { struct fpre_keyword *f; @@ -952,7 +985,9 @@ static char *make_filename(char *buf, struct thread_options *o, for (f = &fpre_keywords[0]; f->keyword; f++) f->strlen = strlen(f->keyword); - strcpy(buf, o->filename_format); + buf[buf_size - 1] = '\0'; + strncpy(buf, o->filename_format, buf_size - 1); + memset(copy, 0, sizeof(copy)); for (f = &fpre_keywords[0]; f->keyword; f++) { do { @@ -1012,7 +1047,7 @@ static char *make_filename(char *buf, struct thread_options *o, if (post_start) strncpy(dst, buf + post_start, dst_left); - strcpy(buf, copy); + strncpy(buf, copy, buf_size - 1); } while (1); } @@ -1036,6 +1071,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, char fname[PATH_MAX]; int numjobs, file_alloced; struct thread_options *o = &td->o; + char logname[PATH_MAX + 32]; /* * the def_thread is just for options, it's not a real job @@ -1072,7 +1108,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, add_file(td, jobname, job_add_num, 0); else { for (i = 0; i < o->nr_files; i++) - add_file(td, make_filename(fname, o, jobname, job_add_num, i), job_add_num, 0); + add_file(td, make_filename(fname, sizeof(fname), o, jobname, job_add_num, i), job_add_num, 0); } } @@ -1125,15 +1161,72 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, if (setup_rate(td)) goto err; - if (o->lat_log_file || write_lat_log) { - setup_log(&td->lat_log, o->log_avg_msec, IO_LOG_TYPE_LAT); - setup_log(&td->slat_log, o->log_avg_msec, IO_LOG_TYPE_SLAT); - setup_log(&td->clat_log, o->log_avg_msec, IO_LOG_TYPE_CLAT); + if (o->lat_log_file) { + struct log_params p = { + .td = td, + .avg_msec = o->log_avg_msec, + .log_type = IO_LOG_TYPE_LAT, + .log_offset = o->log_offset, + .log_gz = o->log_gz, + .log_gz_store = o->log_gz_store, + }; + const char *suf; + + if (p.log_gz_store) + suf = "log.fz"; + else + suf = "log"; + + snprintf(logname, sizeof(logname), "%s_lat.%d.%s", + o->lat_log_file, td->thread_number, suf); + setup_log(&td->lat_log, &p, logname); + snprintf(logname, sizeof(logname), "%s_slat.%d.%s", + o->lat_log_file, td->thread_number, suf); + setup_log(&td->slat_log, &p, logname); + snprintf(logname, sizeof(logname), "%s_clat.%d.%s", + o->lat_log_file, td->thread_number, suf); + setup_log(&td->clat_log, &p, logname); + } + if (o->bw_log_file) { + struct log_params p = { + .td = td, + .avg_msec = o->log_avg_msec, + .log_type = IO_LOG_TYPE_BW, + .log_offset = o->log_offset, + .log_gz = o->log_gz, + .log_gz_store = o->log_gz_store, + }; + const char *suf; + + if (p.log_gz_store) + suf = "log.fz"; + else + suf = "log"; + + snprintf(logname, sizeof(logname), "%s_bw.%d.%s", + o->bw_log_file, td->thread_number, suf); + setup_log(&td->bw_log, &p, logname); + } + if (o->iops_log_file) { + struct log_params p = { + .td = td, + .avg_msec = o->log_avg_msec, + .log_type = IO_LOG_TYPE_IOPS, + .log_offset = o->log_offset, + .log_gz = o->log_gz, + .log_gz_store = o->log_gz_store, + }; + const char *suf; + + if (p.log_gz_store) + suf = "log.fz"; + else + suf = "log"; + + snprintf(logname, sizeof(logname), "%s_iops.%d.%s", + o->iops_log_file, td->thread_number, suf); + setup_log(&td->iops_log, &p, logname); } - if (o->bw_log_file || write_bw_log) - setup_log(&td->bw_log, o->log_avg_msec, IO_LOG_TYPE_BW); - if (o->iops_log_file) - setup_log(&td->iops_log, o->log_avg_msec, IO_LOG_TYPE_IOPS); if (!o->name) o->name = strdup(jobname); @@ -1188,7 +1281,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, */ numjobs = o->numjobs; while (--numjobs) { - struct thread_data *td_new = get_new_job(0, td, 1); + struct thread_data *td_new = get_new_job(0, td, 1, jobname); if (!td_new) goto err; @@ -1196,6 +1289,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, td_new->o.numjobs = 1; td_new->o.stonewall = 0; td_new->o.new_group = 0; + td_new->subjob_number = numjobs; if (file_alloced) { if (td_new->files) { @@ -1246,11 +1340,11 @@ void add_job_opts(const char **o, int client_type) sprintf(jobname, "%s", o[i] + 5); } if (in_global && !td_parent) - td_parent = get_new_job(1, &def_thread, 0); + td_parent = get_new_job(1, &def_thread, 0, jobname); else if (!in_global && !td) { if (!td_parent) td_parent = &def_thread; - td = get_new_job(0, td_parent, 0); + td = get_new_job(0, td_parent, 0, jobname); } if (in_global) fio_options_parse(td_parent, (char **) &o[i], 1, 0); @@ -1385,7 +1479,7 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type) first_sect = 0; } - td = get_new_job(global, &def_thread, 0); + td = get_new_job(global, &def_thread, 0, name); if (!td) { ret = 1; break; @@ -1486,11 +1580,10 @@ static void usage(const char *name) printf("%s [options] [job options] \n", name); printf(" --debug=options\tEnable debug logging. May be one/more of:\n" "\t\t\tprocess,file,io,mem,blktrace,verify,random,parse,\n" - "\t\t\tdiskutil,job,mutex,profile,time,net,rate\n"); + "\t\t\tdiskutil,job,mutex,profile,time,net,rate,compress\n"); printf(" --parse-only\t\tParse options only, don't start any IO\n"); printf(" --output\t\tWrite output to file\n"); printf(" --runtime\t\tRuntime in seconds\n"); - printf(" --latency-log\t\tGenerate per-job latency logs\n"); printf(" --bandwidth-log\tGenerate per-job bandwidth logs\n"); printf(" --minimal\t\tMinimal (terse) output\n"); printf(" --output-format=x\tOutput format (terse,json,normal)\n"); @@ -1525,6 +1618,9 @@ static void usage(const char *name) printf(" --idle-prof=option\tReport cpu idleness on a system or percpu basis\n" "\t\t\t(option=system,percpu) or run unit work\n" "\t\t\tcalibration only (option=calibrate)\n"); +#ifdef CONFIG_ZLIB + printf(" --inflate-log=log\tInflate and output compressed log\n"); +#endif printf("\nFio was written by Jens Axboe "); printf("\n Jens Axboe "); printf("\n Jens Axboe \n"); @@ -1592,6 +1688,10 @@ struct debug_level debug_levels[] = { .help = "Rate logging", .shift = FD_RATE, }, + { .name = "compress", + .help = "Log compression logging", + .shift = FD_COMPRESS, + }, { .name = NULL, }, }; @@ -1714,8 +1814,6 @@ int parse_cmd_line(int argc, char *argv[], int client_type) optind = 1; while ((c = getopt_long_only(argc, argv, ostr, l_opts, &lidx)) != -1) { - did_arg = 1; - if ((c & FIO_CLIENT_FLAG) || client_flag_set(c)) { parse_cmd_client(cur_client, argv[optind - 1]); c &= ~FIO_CLIENT_FLAG; @@ -1733,13 +1831,15 @@ int parse_cmd_line(int argc, char *argv[], int client_type) } break; case 'l': - write_lat_log = 1; + log_err("fio: --latency-log is deprecated. Use per-job latency log options.\n"); + do_exit++; + exit_val = 1; break; case 'b': write_bw_log = 1; break; case 'o': - if (f_out) + if (f_out && f_out != stdout) fclose(f_out); f_out = fopen(optarg, "w+"); @@ -1772,30 +1872,35 @@ int parse_cmd_line(int argc, char *argv[], int client_type) append_terse_output = 1; break; case 'h': + did_arg = 1; if (!cur_client) { usage(argv[0]); do_exit++; } break; case 'c': + did_arg = 1; if (!cur_client) { fio_show_option_help(optarg); do_exit++; } break; case 'i': + did_arg = 1; if (!cur_client) { fio_show_ioengine_help(optarg); do_exit++; } break; case 's': + did_arg = 1; dump_cmdline = 1; break; case 'r': read_only = 1; break; case 'v': + did_arg = 1; if (!cur_client) { log_info("%s\n", fio_version_string); do_exit++; @@ -1832,6 +1937,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) do_exit++; break; case 'P': + did_arg = 1; parse_only = 1; break; case 'x': { @@ -1850,7 +1956,15 @@ int parse_cmd_line(int argc, char *argv[], int client_type) nr_job_sections++; break; } +#ifdef CONFIG_ZLIB + case 'X': + exit_val = iolog_file_inflate(optarg); + did_arg++; + do_exit++; + break; +#endif case 'p': + did_arg = 1; if (exec_profile) free(exec_profile); exec_profile = strdup(optarg); @@ -1864,6 +1978,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) if (ret) goto out_free; td = NULL; + did_arg = 1; } if (!td) { int is_section = !strncmp(opt, "name", 4); @@ -1875,9 +1990,15 @@ int parse_cmd_line(int argc, char *argv[], int client_type) if (is_section && skip_this_section(val)) continue; - td = get_new_job(global, &def_thread, 1); - if (!td || ioengine_load(td)) - goto out_free; + td = get_new_job(global, &def_thread, 1, NULL); + if (!td || ioengine_load(td)) { + if (td) { + put_job(td); + td = NULL; + } + do_exit++; + break; + } fio_options_set_ioengine_opts(l_opts, td); } @@ -1898,8 +2019,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type) if (!ret && !strcmp(opt, "ioengine")) { free_ioengine(td); - if (ioengine_load(td)) - goto out_free; + if (ioengine_load(td)) { + put_job(td); + td = NULL; + do_exit++; + break; + } fio_options_set_ioengine_opts(l_opts, td); } break; @@ -1907,6 +2032,10 @@ int parse_cmd_line(int argc, char *argv[], int client_type) case FIO_GETOPT_IOENGINE: { const char *opt = l_opts[lidx].name; char *val = optarg; + + if (!td) + break; + ret = fio_cmd_ioengine_option_parse(td, opt, val); break; } @@ -1922,6 +2051,8 @@ int parse_cmd_line(int argc, char *argv[], int client_type) } break; case 'S': + did_arg = 1; +#ifndef CONFIG_NO_SHM if (nr_clients) { log_err("fio: can't be both client and server\n"); do_exit++; @@ -1932,19 +2063,28 @@ int parse_cmd_line(int argc, char *argv[], int client_type) fio_server_set_arg(optarg); is_backend = 1; backend = 1; +#else + log_err("fio: client/server requires SHM support\n"); + do_exit++; + exit_val = 1; +#endif break; case 'D': + if (pid_file) + free(pid_file); pid_file = strdup(optarg); break; case 'I': if ((ret = fio_idle_prof_parse_opt(optarg))) { /* exit on error and calibration only */ + did_arg = 1; do_exit++; - if (ret == -1) + if (ret == -1) exit_val = 1; } break; case 'C': + did_arg = 1; if (is_backend) { log_err("fio: can't be both client and server\n"); do_exit++; @@ -1971,10 +2111,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type) } break; case 'T': + did_arg = 1; do_exit++; exit_val = fio_monotonic_clocktest(); break; case 'G': + did_arg = 1; do_exit++; exit_val = fio_crctest(optarg); break; @@ -2014,8 +2156,11 @@ int parse_cmd_line(int argc, char *argv[], int client_type) free(pid_file); if (td) { - if (!ret) + if (!ret) { ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type); + if (ret) + did_arg = 1; + } } while (!ret && optind < argc) {