From d4afedfd152cea890ffa7d45bf1664fb70218c45 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 22 May 2013 22:21:29 +0200 Subject: [PATCH] Start of ACT like benchmark profile Signed-off-by: Jens Axboe --- Makefile | 5 +- io_u.c | 7 ++ options.h | 2 + profile.c | 5 +- profile.h | 4 +- profiles/act.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ profiles/tiobench.c | 4 +- 7 files changed, 235 insertions(+), 6 deletions(-) create mode 100644 profiles/act.c diff --git a/Makefile b/Makefile index 781cdec7..d78be342 100644 --- 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 f0b61705..645a6804 100644 --- 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); diff --git a/options.h b/options.h index 9702d47c..3795afd5 100644 --- 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), }; diff --git a/profile.c b/profile.c index 6a80dec2..92f2fc46 100644 --- 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; } diff --git a/profile.h b/profile.h index 673c5c45..3c8d61f1 100644 --- 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 index 00000000..d10e70e0 --- /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 0279e1ca..0d2ce806 100644 --- a/profiles/tiobench.c +++ b/profiles/tiobench.c @@ -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 = { -- 2.25.1