Add support for giving bw/clat/slat log prefixes

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/HOWTO b/HOWTO
index f4efd28..4298f32 100644
--- a/HOWTO
+++ b/HOWTO
@@ -804,14 +804,23 @@
 		the file needs to be turned into a blkparse binary data
 		file first (blktrace <device> -d file_for_fio.bin).
 
-write_bw_log	If given, write a bandwidth log of the jobs in this job
+write_bw_log=str If given, write a bandwidth log of the jobs in this job
 		file. Can be used to store data of the bandwidth of the
 		jobs in their lifetime. The included fio_generate_plots
 		script uses gnuplot to turn these text files into nice
-		graphs.
+		graphs. See write_log_log for behaviour of given
+		filename. For this option, the postfix is _bw.log.
 
-write_lat_log	Same as write_bw_log, except that this option stores io
-		completion latencies instead.
+write_lat_log=str Same as write_bw_log, except that this option stores io
+		completion latencies instead. If no filename is given
+		with this option, the default filename of "jobname_type.log"
+		is used. Even if the filename is given, fio will still
+		append the type of log. So if one specifies
+
+		write_lat_log=foo
+
+		The actual log names will be foo_clat.log and foo_slat.log.
+		This helps fio_generate_plot fine the logs automatically.
 
 lockmem=siint	Pin down the specified amount of memory with mlock(2). Can
 		potentially be used instead of removing memory or booting
diff --git a/fio.c b/fio.c
index 2aa8b40..5a87ae4 100644
--- a/fio.c
+++ b/fio.c
@@ -1066,12 +1066,24 @@
 	td->ts.io_bytes[0] = td->io_bytes[0];
 	td->ts.io_bytes[1] = td->io_bytes[1];
 
-	if (td->ts.bw_log)
-		finish_log(td, td->ts.bw_log, "bw");
-	if (td->ts.slat_log)
-		finish_log(td, td->ts.slat_log, "slat");
-	if (td->ts.clat_log)
-		finish_log(td, td->ts.clat_log, "clat");
+	if (td->ts.bw_log) {
+		if (td->o.bw_log_file)
+			finish_log_named(td, td->ts.bw_log, td->o.bw_log_file, "bw");
+		else
+			finish_log(td, td->ts.bw_log, "bw");
+	}
+	if (td->ts.slat_log) {
+		if (td->o.lat_log_file)
+			finish_log_named(td, td->ts.slat_log, td->o.lat_log_file, "clat");
+		else
+			finish_log(td, td->ts.slat_log, "slat");
+	}
+	if (td->ts.clat_log) {
+		if (td->o.lat_log_file)
+			finish_log_named(td, td->ts.clat_log, td->o.lat_log_file, "clat");
+		else
+			finish_log(td, td->ts.clat_log, "clat");
+	}
 	if (td->o.exec_postrun) {
 		if (system(td->o.exec_postrun) < 0)
 			log_err("fio: postrun %s failed\n", td->o.exec_postrun);
diff --git a/fio.h b/fio.h
index 3e39aea..f8e6a4a 100644
--- a/fio.h
+++ b/fio.h
@@ -503,6 +503,8 @@
 
 	char *read_iolog_file;
 	char *write_iolog_file;
+	char *bw_log_file;
+	char *lat_log_file;
 
 	/*
 	 * Pre-run and post-run shell
@@ -806,6 +808,7 @@
 extern void update_io_ticks(void);
 extern void setup_log(struct io_log **);
 extern void finish_log(struct thread_data *, struct io_log *, const char *);
+extern void finish_log_named(struct thread_data *, struct io_log *, const char *, const char *);
 extern void __finish_log(struct io_log *, const char *);
 extern struct io_log *agg_io_log[2];
 extern int write_bw_log;
diff --git a/log.c b/log.c
index 5c468ad..611aa9f 100644
--- a/log.c
+++ b/log.c
@@ -471,11 +471,17 @@
 	free(log);
 }
 
-void finish_log(struct thread_data *td, struct io_log *log, const char *name)
+void finish_log_named(struct thread_data *td, struct io_log *log,
+		       const char *prefix, const char *postfix)
 {
 	char file_name[256], *p;
 
-	snprintf(file_name, 200, "%s_%s.log", td->o.name, name);
+	snprintf(file_name, 200, "%s_%s.log", prefix, postfix);
 	p = basename(file_name);
 	__finish_log(log, p);
 }
+
+void finish_log(struct thread_data *td, struct io_log *log, const char *name)
+{
+	finish_log_named(td, log, td->o.name, name);
+}
diff --git a/options.c b/options.c
index 3d27f25..b890420 100644
--- a/options.c
+++ b/options.c
@@ -438,6 +438,28 @@
 	return 0;
 }
 
+static int str_write_bw_log_cb(void *data, const char *str)
+{
+	struct thread_data *td = data;
+
+	if (str)
+		td->o.bw_log_file = strdup(str);
+
+	td->o.write_bw_log = 1;
+	return 0;
+}
+
+static int str_write_lat_log_cb(void *data, const char *str)
+{
+	struct thread_data *td = data;
+
+	if (str)
+		td->o.lat_log_file = strdup(str);
+
+	td->o.write_lat_log = 1;
+	return 0;
+}
+
 static int str_gtod_reduce_cb(void *data, int *il)
 {
 	struct thread_data *td = data;
@@ -1266,14 +1288,16 @@
 	},
 	{
 		.name	= "write_bw_log",
-		.type	= FIO_OPT_STR_SET,
+		.type	= FIO_OPT_STR,
 		.off1	= td_var_offset(write_bw_log),
+		.cb	= str_write_bw_log_cb,
 		.help	= "Write log of bandwidth during run",
 	},
 	{
 		.name	= "write_lat_log",
-		.type	= FIO_OPT_STR_SET,
+		.type	= FIO_OPT_STR,
 		.off1	= td_var_offset(write_lat_log),
+		.cb	= str_write_lat_log_cb,
 		.help	= "Write log of latency during run",
 	},
 	{
diff --git a/parse.c b/parse.c
index 8a2e6f2..44c02f6 100644
--- a/parse.c
+++ b/parse.c
@@ -236,7 +236,7 @@
 	dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name,
 							o->type, ptr);
 
-	if (!ptr && o->type != FIO_OPT_STR_SET) {
+	if (!ptr && o->type != FIO_OPT_STR_SET && o->type != FIO_OPT_STR) {
 		fprintf(stderr, "Option %s requires an argument\n", o->name);
 		return 1;
 	}