Add support for simple profile benchmarks

One of the reasons that tiobench gets used a lot, is that you
simply have to run it. For "real" benchmarks, you usually
have to configure them first. This adds support for easy testing
by adding some predefined and included workloads. This commit
includes tiobench, to run a tiobench like workload you would
simply do:

$ fio --profile=tiobench

and that would be it.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/fio.h b/fio.h
index e4ed76f..1723067 100644
--- a/fio.h
+++ b/fio.h
@@ -28,6 +28,7 @@
 #include "io_ddir.h"
 #include "ioengine.h"
 #include "iolog.h"
+#include "profiles.h"
 
 #ifdef FIO_HAVE_GUASI
 #include <guasi.h>
@@ -264,6 +265,11 @@
 	 * I/O Error handling
 	 */
 	unsigned int continue_on_error;
+
+	/*
+	 * Benchmark profile type
+	 */
+	unsigned int profile;
 };
 
 #define FIO_VERROR_SIZE	128
diff --git a/init.c b/init.c
index cc0f3ba..26c7d1d 100644
--- a/init.c
+++ b/init.c
@@ -127,10 +127,35 @@
 		.val		= 'a',
 	},
 	{
+		.name		= "profile",
+		.has_arg	= required_argument,
+		.val		= 'p',
+	},
+	{
 		.name		= NULL,
 	},
 };
 
+static const char *tiobench_opts[] = {
+	"buffered=0", "size=256*$mb_memory", "bs=4k", "timeout=600",
+	"numjobs=4", "group_reporting", "thread", "overwrite=1",
+	"filename=.fio.tio.1:.fio.tio.2:.fio.tio.3:.fio.tio.4",
+	"name=seqwrite", "rw=write", "end_fsync=1",
+	"name=randwrite", "stonewall", "rw=randwrite", "end_fsync=1",
+	"name=seqread", "stonewall", "rw=read",
+	"name=randread", "stonewall", "rw=randread", NULL,
+};
+
+static const char **fio_prof_strings[PROFILE_END] = {
+	NULL,
+	tiobench_opts,
+};
+
+static const char *profiles[PROFILE_END] = {
+	"none",
+	"tiobench",
+};
+
 FILE *get_f_out()
 {
 	return f_out;
@@ -992,6 +1017,57 @@
 }
 #endif
 
+static int load_profile(const char *profile)
+{
+	struct thread_data *td, *td_parent;
+	const char **o;
+	int i, in_global = 1;
+	char jobname[32];
+
+	dprint(FD_PARSE, "loading profile %s\n", profile);
+
+	for (i = 0; i < PROFILE_END; i++) {
+		if (!strcmp(profile, profiles[i]))
+			break;
+	}
+
+	if (i == PROFILE_END) {
+		log_err("fio: unknown profile %s\n", profile);
+		return 1;
+	}
+
+	o = fio_prof_strings[i];
+	if (!o)
+		return 0;
+
+	i = 0;
+	td_parent = td = NULL;
+	while (o[i]) {
+		if (!strncmp(o[i], "name", 4)) {
+			in_global = 0;
+			if (td)
+				add_job(td, jobname, 0);
+			td = NULL;
+			sprintf(jobname, "%s", o[i] + 5);
+		}
+		if (in_global && !td_parent)
+			td_parent = get_new_job(1, &def_thread);
+		else if (!in_global && !td) {
+			if (!td_parent)
+				td_parent = &def_thread;
+			td = get_new_job(0, td_parent);
+		}
+		if (in_global)
+			fio_options_parse(td_parent, (char **) &o[i], 1);
+		else
+			fio_options_parse(td, (char **) &o[i], 1);
+		i++;
+	}
+	if (td)
+		add_job(td, jobname, 0);
+	return 0;
+}
+
 static int parse_cmd_line(int argc, char *argv[])
 {
 	struct thread_data *td = NULL;
@@ -1058,6 +1134,10 @@
 				free(job_section);
 			job_section = strdup(optarg);
 			break;
+		case 'p':
+			if (load_profile(optarg))
+				do_exit++;
+			break;
 		case FIO_GETOPT_JOB: {
 			const char *opt = l_opts[lidx].name;
 			char *val = optarg;
diff --git a/options.c b/options.c
index 4544378..ff27765 100644
--- a/options.c
+++ b/options.c
@@ -1715,6 +1715,18 @@
 		.def	= "0",
 	},
 	{
+		.name	= "profile",
+		.type	= FIO_OPT_STR,
+		.off1	= td_var_offset(profile),
+		.posval = {
+			  { .ival = "tiobench",
+			    .oval = PROFILE_TIOBENCH,
+			    .help = "Perform tiobench like test",
+			  },
+		},
+		.help	= "Select a specific builtin performance test",
+	},
+	{
 		.name = NULL,
 	},
 };
@@ -1811,6 +1823,7 @@
 		return str;
 
 	tmp++;
+	memset(opt, 0, sizeof(opt));
 	strncpy(opt, str, tmp - str);
 
 	buf = malloc(128);
@@ -1879,7 +1892,7 @@
 			 * replace opt and free the old opt
 			 */
 			opt = new;
-			free(o_org);
+			//free(o_org);
 
 			/*
 			 * Check for potential math and invoke bc, if possible
diff --git a/profiles.h b/profiles.h
new file mode 100644
index 0000000..8203a46
--- /dev/null
+++ b/profiles.h
@@ -0,0 +1,10 @@
+#ifndef FIO_PROFILE_H
+#define FIO_PROFILE_H
+
+enum {
+	PROFILE_NONE		= 0,
+	PROFILE_TIOBENCH	= 1,
+	PROFILE_END		= 2,
+};
+
+#endif