Start of ACT like benchmark profile
authorJens Axboe <axboe@kernel.dk>
Wed, 22 May 2013 20:21:29 +0000 (22:21 +0200)
committerJens Axboe <axboe@kernel.dk>
Wed, 22 May 2013 20:21:29 +0000 (22:21 +0200)
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Makefile
io_u.c
options.h
profile.c
profile.h
profiles/act.c [new file with mode: 0644]
profiles/tiobench.c

index 781cdec759cef88b2a03ecae617811e5bdba6127..d78be342fa00462d7c264b76a40ea0dd668d0dce 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,8 @@ SOURCE := gettime.c ioengines.c init.c stat.c log.c time.c filesetup.c \
                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 @@ endif
 
 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 f0b6170535d2a77a07861a4a0760d72a4130412e..645a6804314ae2c7b40cc3689fed0d21fd5678d8 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -1368,6 +1368,13 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
                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);
index 9702d47c0a0764edecb0abed8f8d7587b4493f90..3795afd5223d1595767973cfefc722c6a559e05e 100644 (file)
--- a/options.h
+++ b/options.h
@@ -93,6 +93,7 @@ enum opt_category_group {
        __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 @@ enum opt_category_group {
        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),
 };
 
index 6a80dec2c7b7479cff92d24c47d2a0d9ac8fa691..92f2fc4624bbd719241e470701a85c9b6888b9d8 100644 (file)
--- a/profile.c
+++ b/profile.c
@@ -30,7 +30,10 @@ int load_profile(const char *profile)
 
        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;
        }
index 673c5c457096fec566d08e720fa81788075dbb43..3c8d61f10bd0a582c3728b831b6cfc6f603fbb2e 100644 (file)
--- a/profile.h
+++ b/profile.h
@@ -13,6 +13,8 @@ struct prof_io_ops {
        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 @@ struct profile_ops {
        /*
         * 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 (file)
index 0000000..d10e70e
--- /dev/null
@@ -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);
+}
index 0279e1cafbec95d286f802889ec8045729a2c3cc..0d2ce8065e261b276bf40f6a8a753c343225dbc2 100644 (file)
@@ -75,9 +75,8 @@ static struct fio_option options[] = {
 /*
  * 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 @@ static void tb_prep_cmdline(void)
                sprintf(dir_idx, "directory=./");
 
        sprintf(t_idx, "numjobs=%u", nthreads);
+       return 0;
 }
 
 static struct profile_ops tiobench_profile = {