Start of ACT like benchmark profile
Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/Makefile b/Makefile
index 781cdec..d78be34 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,8 @@
memalign.c server.c client.c iolog.c backend.c libfio.c flow.c \
cconv.c lib/prio_tree.c json.c lib/zipf.c lib/axmap.c \
lib/lfsr.c gettime-thread.c helpers.c lib/flist_sort.c \
- lib/hweight.c lib/getrusage.c idletime.c td_error.c
+ lib/hweight.c lib/getrusage.c idletime.c td_error.c \
+ profiles/tiobench.c profiles/act.c
ifdef CONFIG_64BIT_LLP64
CFLAGS += -DBITS_PER_LONG=32
@@ -88,7 +89,7 @@
ifeq ($(CONFIG_TARGET_OS), Linux)
SOURCE += diskutil.c fifo.c blktrace.c cgroup.c trim.c engines/sg.c \
- engines/binject.c profiles/tiobench.c
+ engines/binject.c
LIBS += -lpthread -ldl
LDFLAGS += -rdynamic
endif
diff --git a/io_u.c b/io_u.c
index f0b6170..645a680 100644
--- a/io_u.c
+++ b/io_u.c
@@ -1368,6 +1368,13 @@
tusec = utime_since(&io_u->start_time, &icd->time);
add_lat_sample(td, idx, tusec, bytes);
+ if (td->flags & TD_F_PROFILE_OPS) {
+ struct prof_io_ops *ops = &td->prof_io_ops;
+
+ if (ops->io_u_lat)
+ icd->error = ops->io_u_lat(td, tusec);
+ }
+
if (td->o.max_latency && tusec > td->o.max_latency) {
if (!td->error)
log_err("fio: latency of %lu usec exceeds specified max (%u usec)\n", tusec, td->o.max_latency);
diff --git a/options.h b/options.h
index 9702d47..3795afd 100644
--- a/options.h
+++ b/options.h
@@ -93,6 +93,7 @@
__FIO_OPT_G_E4DEFRAG,
__FIO_OPT_G_NETIO,
__FIO_OPT_G_LIBAIO,
+ __FIO_OPT_G_ACT,
__FIO_OPT_G_NR,
FIO_OPT_G_RATE = (1U << __FIO_OPT_G_RATE),
@@ -120,6 +121,7 @@
FIO_OPT_G_E4DEFRAG = (1U << __FIO_OPT_G_E4DEFRAG),
FIO_OPT_G_NETIO = (1U << __FIO_OPT_G_NETIO),
FIO_OPT_G_LIBAIO = (1U << __FIO_OPT_G_LIBAIO),
+ FIO_OPT_G_ACT = (1U << __FIO_OPT_G_ACT),
FIO_OPT_G_INVALID = (1U << __FIO_OPT_G_NR),
};
diff --git a/profile.c b/profile.c
index 6a80dec..92f2fc4 100644
--- a/profile.c
+++ b/profile.c
@@ -30,7 +30,10 @@
ops = find_profile(profile);
if (ops) {
- ops->prep_cmd();
+ if (ops->prep_cmd()) {
+ log_err("fio: profile prep failed\n");
+ return 1;
+ }
add_job_opts(ops->cmdline, FIO_CLIENT_TYPE_CLI);
return 0;
}
diff --git a/profile.h b/profile.h
index 673c5c4..3c8d61f 100644
--- a/profile.h
+++ b/profile.h
@@ -13,6 +13,8 @@
int (*fill_io_u_off)(struct thread_data *, struct io_u *);
int (*fill_io_u_size)(struct thread_data *, struct io_u *);
struct fio_file *(*get_next_file)(struct thread_data *);
+
+ int (*io_u_lat)(struct thread_data *, uint64_t);
};
struct profile_ops {
@@ -29,7 +31,7 @@
/*
* Called after parsing options, to prepare 'cmdline'
*/
- void (*prep_cmd)(void);
+ int (*prep_cmd)(void);
/*
* The complete command line
diff --git a/profiles/act.c b/profiles/act.c
new file mode 100644
index 0000000..d10e70e
--- /dev/null
+++ b/profiles/act.c
@@ -0,0 +1,214 @@
+#include "../fio.h"
+#include "../profile.h"
+#include "../parse.h"
+
+#define OBJ_SIZE 1536 /* each object */
+#define W_BUF_SIZE 128 * 1024 /* write coalescing */
+
+#define R_LOAD 2000
+#define W_LOAD 1000
+
+#define SAMPLE_SEC 3600 /* 1h checks */
+
+struct act_pass_criteria {
+ unsigned int max_usec;
+ unsigned int max_perm;
+};
+#define ACT_MAX_CRIT 3
+
+static struct act_pass_criteria act_pass[ACT_MAX_CRIT] = {
+ {
+ .max_usec = 1000,
+ .max_perm = 50,
+ },
+ {
+ .max_usec = 5000,
+ .max_perm = 10,
+ },
+ {
+ .max_usec = 64000,
+ .max_perm = 1,
+ },
+};
+
+struct act_prof_data {
+ struct timeval sample_tv;
+ uint64_t lat_buckets[ACT_MAX_CRIT];
+ uint64_t total_ios;
+};
+
+static char *device_names;
+static unsigned int load = 1;
+
+static const char *act_opts[128] = {
+ "direct=1",
+ "ioengine=sync",
+ "random_generator=lfsr",
+ "runtime=24h",
+ "time_based=1",
+ NULL,
+};
+static unsigned int opt_idx = 5;
+static unsigned int org_idx;
+
+static void act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+
+static struct fio_option options[] = {
+ {
+ .name = "device-names",
+ .lname = "device-names",
+ .type = FIO_OPT_STR_STORE,
+ .roff1 = &device_names,
+ .help = "Devices to use",
+ .category = FIO_OPT_C_PROFILE,
+ .group = FIO_OPT_G_ACT,
+ },
+ {
+ .name = "load",
+ .lname = "Load multiplier",
+ .type = FIO_OPT_INT,
+ .roff1 = &load,
+ .help = "ACT load multipler (default 1x)",
+ .category = FIO_OPT_C_PROFILE,
+ .group = FIO_OPT_G_ACT,
+ },
+ {
+ .name = NULL,
+ },
+};
+
+static void act_add_opt(const char *str, ...)
+{
+ char buffer[512];
+ va_list args;
+ size_t len;
+
+ va_start(args, str);
+ len = vsnprintf(buffer, sizeof(buffer), str, args);
+ va_end(args);
+
+ if (len)
+ act_opts[opt_idx++] = strdup(buffer);
+}
+
+static void act_add_dev(const char *dev)
+{
+ act_add_opt("name=act-read-%s", dev);
+ act_add_opt("filename=%s", dev);
+ act_add_opt("rw=randread");
+ act_add_opt("rate_iops=%u", load * R_LOAD);
+
+ act_add_opt("name=act-write-%s", dev);
+ act_add_opt("filename=%s", dev);
+ act_add_opt("rw=randwrite");
+ act_add_opt("rate_iops=%u", load * W_LOAD);
+}
+
+/*
+ * Fill our private options into the command line
+ */
+static int act_prep_cmdline(void)
+{
+ if (!device_names) {
+ log_err("act: need device-names\n");
+ return 1;
+ }
+
+ org_idx = opt_idx;
+ act_add_opt("bs=%u", OBJ_SIZE);
+
+ do {
+ char *dev;
+
+ dev = strsep(&device_names, ",");
+ if (!dev)
+ break;
+
+ act_add_dev(dev);
+ } while (1);
+
+ return 0;
+}
+
+static int act_io_u_lat(struct thread_data *td, uint64_t usec)
+{
+ struct act_prof_data *apd = td->prof_data;
+ int i, ret = 0;
+ double perm;
+
+ apd->total_ios++;
+
+ for (i = 0; i < ACT_MAX_CRIT; i++) {
+ if (usec <= act_pass[i].max_usec) {
+ apd->lat_buckets[i]++;
+ break;
+ }
+ }
+
+ if (i == ACT_MAX_CRIT) {
+ log_err("act: max latency exceeded!\n");
+ return 1;
+ }
+
+ if (time_since_now(&apd->sample_tv) < SAMPLE_SEC)
+ return 0;
+
+ /* SAMPLE_SEC has passed, check criteria for pass */
+ for (i = 0; i < ACT_MAX_CRIT; i++) {
+ perm = (1000.0 * apd->lat_buckets[i]) / apd->total_ios;
+ if (perm <= act_pass[i].max_perm)
+ continue;
+
+ log_err("act: %f%% exceeds pass criteria of %f%%\n", perm / 10.0, (double) act_pass[i].max_perm / 10.0);
+ ret = 1;
+ break;
+ }
+
+ fio_gettime(&apd->sample_tv, NULL);
+ return ret;
+}
+
+static int act_td_init(struct thread_data *td)
+{
+ struct act_prof_data *apd;
+
+ apd = calloc(sizeof(*apd), 1);
+ fio_gettime(&apd->sample_tv, NULL);
+ td->prof_data = apd;
+ return 0;
+}
+
+static void act_td_exit(struct thread_data *td)
+{
+ free(td->prof_data);
+ td->prof_data = NULL;
+}
+
+static struct prof_io_ops act_io_ops = {
+ .td_init = act_td_init,
+ .td_exit = act_td_exit,
+ .io_u_lat = act_io_u_lat,
+};
+
+static struct profile_ops act_profile = {
+ .name = "act",
+ .desc = "ACT Aerospike like benchmark",
+ .options = options,
+ .prep_cmd = act_prep_cmdline,
+ .cmdline = act_opts,
+ .io_ops = &act_io_ops,
+};
+
+static void fio_init act_register(void)
+{
+ if (register_profile(&act_profile))
+ log_err("fio: failed to register profile 'act'\n");
+}
+
+static void fio_exit act_unregister(void)
+{
+ while (org_idx && org_idx < opt_idx)
+ free((void *) act_opts[++org_idx]);
+
+ unregister_profile(&act_profile);
+}
diff --git a/profiles/tiobench.c b/profiles/tiobench.c
index 0279e1c..0d2ce80 100644
--- a/profiles/tiobench.c
+++ b/profiles/tiobench.c
@@ -75,9 +75,8 @@
/*
* Fill our private options into the command line
*/
-static void tb_prep_cmdline(void)
+static int tb_prep_cmdline(void)
{
-
/*
* tiobench uses size as MB, so multiply up
*/
@@ -96,6 +95,7 @@
sprintf(dir_idx, "directory=./");
sprintf(t_idx, "numjobs=%u", nthreads);
+ return 0;
}
static struct profile_ops tiobench_profile = {