int read_only = 0;
int status_interval = 0;
-static int write_lat_log;
-
static int prev_group_jobs;
unsigned long fio_debug = 0;
.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,
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
}
}
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;
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;
perror("shmat");
return 1;
}
+#endif
memset(threads, 0, max_jobs * sizeof(struct thread_data));
hash = (void *) threads + max_jobs * sizeof(struct thread_data);
* 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;
td->thread_number = thread_number;
- if (!parent || !parent->o.group_reporting)
+ if (jobname)
+ td->o.name = strdup(jobname);
+
+ if (!parent->o.group_reporting)
stat_number++;
set_cmd_options(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--;
}
{ .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;
char copy[PATH_MAX];
+ size_t dst_left = PATH_MAX - 1;
if (!o->filename_format || !strlen(o->filename_format)) {
sprintf(buf, "%s.%d.%d", jobname, jobnum, filenum);
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 {
if (pre_len) {
strncpy(dst, buf, pre_len);
dst += pre_len;
+ dst_left -= pre_len;
}
switch (f->key) {
- case FPRE_JOBNAME:
- dst += sprintf(dst, "%s", jobname);
+ case FPRE_JOBNAME: {
+ int ret;
+
+ ret = snprintf(dst, dst_left, "%s", jobname);
+ if (ret < 0)
+ break;
+ dst += ret;
+ dst_left -= ret;
break;
- case FPRE_JOBNUM:
- dst += sprintf(dst, "%d", jobnum);
+ }
+ case FPRE_JOBNUM: {
+ int ret;
+
+ ret = snprintf(dst, dst_left, "%d", jobnum);
+ if (ret < 0)
+ break;
+ dst += ret;
+ dst_left -= ret;
break;
- case FPRE_FILENUM:
- dst += sprintf(dst, "%d", filenum);
+ }
+ case FPRE_FILENUM: {
+ int ret;
+
+ ret = snprintf(dst, dst_left, "%d", filenum);
+ if (ret < 0)
+ break;
+ dst += ret;
+ dst_left -= ret;
break;
+ }
default:
assert(0);
break;
}
if (post_start)
- strcpy(dst, buf + post_start);
+ strncpy(dst, buf + post_start, dst_left);
- strcpy(buf, copy);
+ strncpy(buf, copy, buf_size - 1);
} while (1);
}
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
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);
}
}
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.%s",
+ o->lat_log_file, suf);
+ setup_log(&td->lat_log, &p, logname);
+ snprintf(logname, sizeof(logname), "%s_slat.%s",
+ o->lat_log_file, suf);
+ setup_log(&td->slat_log, &p, logname);
+ snprintf(logname, sizeof(logname), "%s_clat.%s",
+ o->lat_log_file, 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.%s",
+ o->bw_log_file, 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.%s",
+ o->iops_log_file, 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);
*/
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;
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);
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;
i++;
}
- for (i = 0; i < num_opts; i++)
- free(opts[i]);
-
free(string);
free(name);
free(opts);
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");
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 <jens.axboe@oracle.com>");
printf("\n Jens Axboe <jaxboe@fusionio.com>");
printf("\n Jens Axboe <axboe@fb.com>\n");
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;
}
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+");
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++;
do_exit++;
break;
case 'P':
+ did_arg = 1;
parse_only = 1;
break;
case 'x': {
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);
if (!strncmp(opt, "name", 4) && td) {
ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type);
if (ret)
- return 0;
+ goto out_free;
td = NULL;
+ did_arg = 1;
}
if (!td) {
int is_section = !strncmp(opt, "name", 4);
if (is_section && skip_this_section(val))
continue;
- td = get_new_job(global, &def_thread, 1);
- if (!td || ioengine_load(td))
- return 0;
+ 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);
}
if (!ret && !strcmp(opt, "ioengine")) {
free_ioengine(td);
- if (ioengine_load(td))
- return 0;
+ if (ioengine_load(td)) {
+ if (td) {
+ put_job(td);
+ td = NULL;
+ }
+ do_exit++;
+ break;
+ }
fio_options_set_ioengine_opts(l_opts, td);
}
break;
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;
}
}
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++;
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++;
}
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;
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) {
optind++;
}
+out_free:
+ if (pid_file)
+ free(pid_file);
+
return ini_idx;
}