Add sub-option support (sort-of) and convert libaio_userspace_reap
authorJens Axboe <jaxboe@fusionio.com>
Wed, 31 Aug 2011 02:43:53 +0000 (20:43 -0600)
committerJens Axboe <jaxboe@fusionio.com>
Wed, 31 Aug 2011 02:43:53 +0000 (20:43 -0600)
You should now use ioengine=libaio:userspace_reap instead of
the separate option.

Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
HOWTO
engines/libaio.c
fio.1
options.c
parse.c
parse.h

diff --git a/HOWTO b/HOWTO
index ad4e45402172f04a4563b2974c5e997462b4d30d..724b604b19c1116b87f32cc4b385e36e92dcd445 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -517,6 +517,16 @@ ioengine=str       Defines how the job issues io to the file. The following
                        libaio  Linux native asynchronous io. Note that Linux
                                may only support queued behaviour with
                                non-buffered IO (set direct=1 or buffered=0).
                        libaio  Linux native asynchronous io. Note that Linux
                                may only support queued behaviour with
                                non-buffered IO (set direct=1 or buffered=0).
+                               This engine also has a sub-option,
+                               userspace_reap. To set it, use
+                               ioengine=libaio:userspace_reap. Normally, with
+                               the libaio engine in use, fio will use the
+                               io_getevents system call to reap newly returned
+                               events. With this flag turned on, the AIO ring
+                               will be read directly from user-space to reap
+                               events. The reaping mode is only enabled when
+                               polling for a minimum of 0 events (eg when
+                               iodepth_batch_complete=0).
 
                        posixaio glibc posix asynchronous io.
 
 
                        posixaio glibc posix asynchronous io.
 
@@ -1187,13 +1197,6 @@ uid=int          Instead of running as the invoking user, set the user ID to
 
 gid=int                Set group ID, see uid.
 
 
 gid=int                Set group ID, see uid.
 
-userspace_libaio_reap=bool  Normally, with the libaio engine in use, fio
-               will use the io_getevents system call to reap newly returned
-               events. With this flag turned on, the AIO ring will be read
-               directly from user-space to reap events. The reaping mode is
-               only enabled when polling for a minimum of 0 events (eg when
-               iodepth_batch_complete=0).
-
 6.0 Interpreting the output
 ---------------------------
 
 6.0 Interpreting the output
 ---------------------------
 
index ea05c63c689b43de1f18116a1c04c62bf5af12a6..ad34d065a3c3bb5cea63e97963a6a3609cd44707 100644 (file)
@@ -63,7 +63,7 @@ struct aio_ring {
        unsigned nr;             /** number of io_events */
        unsigned head;
        unsigned tail;
        unsigned nr;             /** number of io_events */
        unsigned head;
        unsigned tail;
+
        unsigned magic;
        unsigned compat_features;
        unsigned incompat_features;
        unsigned magic;
        unsigned compat_features;
        unsigned incompat_features;
@@ -75,11 +75,11 @@ struct aio_ring {
 #define AIO_RING_MAGIC 0xa10a10a1
 
 static int user_io_getevents(io_context_t aio_ctx, unsigned int max,
 #define AIO_RING_MAGIC 0xa10a10a1
 
 static int user_io_getevents(io_context_t aio_ctx, unsigned int max,
-                       struct io_event *events)
+                            struct io_event *events)
 {
        long i = 0;
        unsigned head;
 {
        long i = 0;
        unsigned head;
-       struct aio_ring *ring = (struct aio_ring*)aio_ctx;
+       struct aio_ring *ring = (struct aio_ring*) aio_ctx;
 
        while (i < max) {
                head = ring->head;
 
        while (i < max) {
                head = ring->head;
@@ -91,7 +91,7 @@ static int user_io_getevents(io_context_t aio_ctx, unsigned int max,
                        /* There is another completion to reap */
                        events[i] = ring->events[head];
                        read_barrier();
                        /* There is another completion to reap */
                        events[i] = ring->events[head];
                        read_barrier();
-                       ring->head = (head + 1) % ring->nr;
+                       ring->head = (head + 1) % ring->nr;
                        i++;
                }
        }
                        i++;
                }
        }
diff --git a/fio.1 b/fio.1
index 488896cea76b803c13e35e8e498a0b23611a8e33..ffc97c989b705844a78962e3e8b0de17fb7465b4 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -367,7 +367,13 @@ Basic \fIreadv\fR\|(2) or \fIwritev\fR\|(2) I/O. Will emulate queuing by
 coalescing adjacents IOs into a single submission.
 .TP
 .B libaio
 coalescing adjacents IOs into a single submission.
 .TP
 .B libaio
-Linux native asynchronous I/O.
+Linux native asynchronous I/O.  This engine also has a sub-option,
+\fBuserspace_reap\fR. To set it, use \fBioengine=libaio:userspace_reap\fR.
+Normally, with the libaio engine in use, fio will use the
+\fIio_getevents\fR\|(3) system call to reap newly returned events. With this
+flag turned on, the AIO ring will be read directly from user-space to reap
+events. The reaping mode is only enabled when polling for a minimum of \fB0\fR
+events (eg when \fBiodepth_batch_complete=0\fR).
 .TP
 .B posixaio
 POSIX asynchronous I/O using \fIaio_read\fR\|(3) and \fIaio_write\fR\|(3).
 .TP
 .B posixaio
 POSIX asynchronous I/O using \fIaio_read\fR\|(3) and \fIaio_write\fR\|(3).
index 6f7c41ed1d3df25a07b0f08c932220f752ca553f..74c24d02d5d4bc200da3cf671c64d363d02e92a4 100644 (file)
--- a/options.c
+++ b/options.c
@@ -226,6 +226,21 @@ static int str_rw_cb(void *data, const char *str)
        return 0;
 }
 
        return 0;
 }
 
+#ifdef FIO_HAVE_LIBAIO
+static int str_libaio_cb(void *data, const char *str)
+{
+       struct thread_data *td = data;
+
+       if (!strcmp(str, "userspace_reap")) {
+               td->o.userspace_libaio_reap = 1;
+               return 0;
+       }
+
+       log_err("fio: bad libaio sub-option: %s\n", str);
+       return 1;
+}
+#endif
+
 static int str_mem_cb(void *data, const char *mem)
 {
        struct thread_data *td = data;
 static int str_mem_cb(void *data, const char *mem)
 {
        struct thread_data *td = data;
@@ -961,6 +976,7 @@ static struct fio_option options[FIO_MAX_OPTS] = {
 #ifdef FIO_HAVE_LIBAIO
                          { .ival = "libaio",
                            .help = "Linux native asynchronous IO",
 #ifdef FIO_HAVE_LIBAIO
                          { .ival = "libaio",
                            .help = "Linux native asynchronous IO",
+                           .cb   = str_libaio_cb,
                          },
 #endif
 #ifdef FIO_HAVE_POSIXAIO
                          },
 #endif
 #ifdef FIO_HAVE_POSIXAIO
@@ -2069,15 +2085,6 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .off1   = td_var_offset(gid),
                .help   = "Run job with this group ID",
        },
                .off1   = td_var_offset(gid),
                .help   = "Run job with this group ID",
        },
-#ifdef FIO_HAVE_LIBAIO
-       {
-               .name   = "userspace_libaio_reap",
-               .type   = FIO_OPT_BOOL,
-               .off1   = td_var_offset(userspace_libaio_reap),
-               .help   = "When using the libaio engine with iodepth_batch_complete=0, enable userspace reaping",
-               .def    = "0",
-       },
-#endif
        {
                .name = NULL,
        },
        {
                .name = NULL,
        },
diff --git a/parse.c b/parse.c
index c2c5bf29a51e8dbd0a5fbe99808e7e9ac277dbdc..445812159585cf1dc490f6a294e278dbe4d2ffca 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -346,6 +346,9 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
        double uf;
        char **cp;
        int ret = 0, is_time = 0;
        double uf;
        char **cp;
        int ret = 0, is_time = 0;
+       const struct value_pair *vp;
+       struct value_pair posval[PARSE_MAX_VP];
+       int i, all_skipped = 1;
 
        dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name,
                                                        o->type, ptr);
 
        dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name,
                                                        o->type, ptr);
@@ -359,9 +362,6 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
        case FIO_OPT_STR:
        case FIO_OPT_STR_MULTI: {
                fio_opt_str_fn *fn = o->cb;
        case FIO_OPT_STR:
        case FIO_OPT_STR_MULTI: {
                fio_opt_str_fn *fn = o->cb;
-               const struct value_pair *vp;
-               struct value_pair posval[PARSE_MAX_VP];
-               int i, all_skipped = 1;
 
                posval_sort(o, posval);
 
 
                posval_sort(o, posval);
 
@@ -487,19 +487,40 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
        case FIO_OPT_STR_STORE: {
                fio_opt_str_fn *fn = o->cb;
 
        case FIO_OPT_STR_STORE: {
                fio_opt_str_fn *fn = o->cb;
 
-               if (o->roff1)
-                       cp = (char **) o->roff1;
-               else
-                       cp = td_var(data, o->off1);
+               posval_sort(o, posval);
 
 
-               *cp = strdup(ptr);
-               if (fn) {
-                       ret = fn(data, ptr);
-                       if (ret) {
-                               free(*cp);
-                               *cp = NULL;
+               ret = 1;
+               for (i = 0; i < PARSE_MAX_VP; i++) {
+                       vp = &posval[i];
+                       if (!vp->ival || vp->ival[0] == '\0')
+                               continue;
+                       all_skipped = 0;
+                       if (!strncmp(vp->ival, ptr, opt_len(ptr))) {
+                               char *rest;
+
+                               ret = 0;
+                               if (vp->cb)
+                                       fn = vp->cb;
+                               if (o->roff1)
+                                       cp = (char **) o->roff1;
+                               else
+                                       cp = td_var(data, o->off1);
+                               *cp = strdup(ptr);
+                               rest = strstr(*cp, ":");
+                               if (rest) {
+                                       *rest = '\0';
+                                       ptr = rest + 1;
+                               } else
+                                       ptr = NULL;
+                               break;
                        }
                }
                        }
                }
+
+               if (ret && !all_skipped)
+                       show_option_values(o);
+               else if (fn && ptr)
+                       ret = fn(data, ptr);
+
                break;
        }
        case FIO_OPT_RANGE: {
                break;
        }
        case FIO_OPT_RANGE: {
diff --git a/parse.h b/parse.h
index c5a74171ae94e70cb45339b1b22fbd387579ccf5..f2265a43226cf1584baf6f31fcf0e981351568fc 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -29,6 +29,7 @@ struct value_pair {
        unsigned int oval;              /* output value */
        const char *help;               /* help text for sub option */
        int or;                         /* OR value */
        unsigned int oval;              /* output value */
        const char *help;               /* help text for sub option */
        int or;                         /* OR value */
+       void *cb;                       /* sub-option callback */
 };
 
 #define OPT_LEN_MAX    4096
 };
 
 #define OPT_LEN_MAX    4096