Make experimental_verify=1 handle all cases properly
authorJens Axboe <axboe@kernel.dk>
Wed, 23 Jan 2013 16:27:25 +0000 (09:27 -0700)
committerJens Axboe <axboe@kernel.dk>
Wed, 23 Jan 2013 16:27:25 +0000 (09:27 -0700)
- Don't track written bytes, just replay the workload by resetting
  all the random generators. This should work for any mixture of IO.

- Handle trims for verify.

- Ensure that rwmix is replayed properly for verify.

- Fixup logging for replay.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
backend.c
io_u.c
ioengine.h
ioengines.c
libfio.c

index 507faa9992e7325d4c80de368e43f2a779893739..902414ef8cfe23669a7c3e8ca43b0b879affd984 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -393,12 +393,11 @@ static int break_on_this_error(struct thread_data *td, enum fio_ddir ddir,
  * The main verify engine. Runs over the writes we previously submitted,
  * reads the blocks back in, and checks the crc/md5 of the data.
  */
-static void do_verify(struct thread_data *td, uint64_t verify_bytes)
+static void do_verify(struct thread_data *td)
 {
        struct fio_file *f;
        struct io_u *io_u;
        int ret, min_events;
-       uint64_t io_bytes;
        unsigned int i;
 
        dprint(FD_VERIFY, "starting loop\n");
@@ -422,7 +421,6 @@ static void do_verify(struct thread_data *td, uint64_t verify_bytes)
        td_set_runstate(td, TD_VERIFYING);
 
        io_u = NULL;
-       io_bytes = 0;
        while (!td->terminate) {
                enum fio_ddir ddir;
                int ret2, full;
@@ -455,11 +453,34 @@ static void do_verify(struct thread_data *td, uint64_t verify_bytes)
                                break;
                        }
                } else {
-                       io_u = get_io_u(td);
-                       if (!io_u)
-                               break;
+                       while ((io_u = get_io_u(td)) != NULL) {
+                               /*
+                                * We are only interested in the places where
+                                * we wrote or trimmed IOs. Turn those into
+                                * reads for verification purposes.
+                                */
+                               if (io_u->ddir == DDIR_READ) {
+                                       /*
+                                        * Pretend we issued it for rwmix
+                                        * accounting
+                                        */
+                                       td->io_issues[DDIR_READ]++;
+                                       put_io_u(td, io_u);
+                                       continue;
+                               } else if (io_u->ddir == DDIR_TRIM) {
+                                       io_u->ddir = DDIR_READ;
+                                       io_u->flags |= IO_U_F_TRIMMED;
+                                       break;
+                               } else if (io_u->ddir == DDIR_WRITE) {
+                                       io_u->ddir = DDIR_READ;
+                                       break;
+                               } else {
+                                       put_io_u(td, io_u);
+                                       continue;
+                               }
+                       }
 
-                       if (io_u->buflen + io_bytes > verify_bytes)
+                       if (!io_u)
                                break;
                }
 
@@ -491,7 +512,6 @@ static void do_verify(struct thread_data *td, uint64_t verify_bytes)
                                io_u->xfer_buflen = io_u->resid;
                                io_u->xfer_buf += bytes;
                                io_u->offset += bytes;
-                               io_bytes += bytes;
 
                                if (ddir_rw(io_u->ddir))
                                        td->ts.short_io_u[io_u->ddir]++;
@@ -507,7 +527,6 @@ sync_done:
                                if (ret < 0)
                                        break;
                        }
-                       io_bytes += io_u->xfer_buflen;
                        continue;
                case FIO_Q_QUEUED:
                        break;
@@ -542,18 +561,15 @@ sync_done:
                                min_events = 1;
 
                        do {
-                               unsigned long bytes = 0;
-
                                /*
                                 * Reap required number of io units, if any,
                                 * and do the verification on them through
                                 * the callback handler
                                 */
-                               if (io_u_queued_complete(td, min_events, &bytes) < 0) {
+                               if (io_u_queued_complete(td, min_events, NULL) < 0) {
                                        ret = -1;
                                        break;
                                }
-                               io_bytes += bytes;
                        } while (full && (td->cur_depth > td->o.iodepth_low));
                }
                if (ret < 0)
@@ -1190,8 +1206,6 @@ static void *thread_main(void *data)
 
        clear_state = 0;
        while (keep_running(td)) {
-               uint64_t write_bytes;
-
                fio_gettime(&td->start, NULL);
                memcpy(&td->bw_sample_time, &td->start, sizeof(td->start));
                memcpy(&td->iops_sample_time, &td->start, sizeof(td->start));
@@ -1212,9 +1226,7 @@ static void *thread_main(void *data)
 
                prune_io_piece_log(td);
 
-               write_bytes = td->io_bytes[DDIR_WRITE];
                do_io(td);
-               write_bytes = td->io_bytes[DDIR_WRITE] - write_bytes;
 
                clear_state = 1;
 
@@ -1243,7 +1255,7 @@ static void *thread_main(void *data)
 
                fio_gettime(&td->start, NULL);
 
-               do_verify(td, write_bytes);
+               do_verify(td);
 
                td->ts.runtime[DDIR_READ] += utime_since_now(&td->start);
 
diff --git a/io_u.c b/io_u.c
index f020cac38af38e5d2ebb150c059564f023b14b18..8567e11664bebe0a00cb8277d9ad054bc3a7b6a9 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -172,19 +172,31 @@ static int get_off_from_method(struct thread_data *td, struct fio_file *f,
        return 1;
 }
 
+/*
+ * Sort the reads for a verify phase in batches of verifysort_nr, if
+ * specified.
+ */
+static inline int should_sort_io(struct thread_data *td)
+{
+       if (!td->o.verifysort_nr || !td->o.do_verify)
+               return 0;
+       if (!td_random(td))
+               return 0;
+       if (td->runstate != TD_VERIFYING)
+               return 0;
+       if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE)
+               return 0;
+
+       return 1;
+}
+
 static int get_next_rand_offset(struct thread_data *td, struct fio_file *f,
                                enum fio_ddir ddir, uint64_t *b)
 {
        struct rand_off *r;
        int i, ret = 1;
 
-       /*
-        * If sort not enabled, or not a pure random read workload without
-        * any stored write metadata, just return a random offset
-        */
-       if (!td->o.verifysort_nr || !(ddir == DDIR_READ && td->o.do_verify &&
-           td->o.verify != VERIFY_NONE && td_random(td)) ||
-           td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE)
+       if (!should_sort_io(td))
                return get_off_from_method(td, f, ddir, b);
 
        if (!flist_empty(&td->next_rand_list)) {
@@ -545,12 +557,6 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td)
 {
        enum fio_ddir ddir;
 
-       /*
-        * If verify phase started, it's always a READ
-        */
-       if (td->runstate == TD_VERIFYING)
-               return DDIR_READ;
-
        /*
         * see if it's time to fsync
         */
@@ -606,7 +612,7 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td)
 
 static void set_rw_ddir(struct thread_data *td, struct io_u *io_u)
 {
-       io_u->ddir = get_rw_ddir(td);
+       io_u->ddir = io_u->acct_ddir = get_rw_ddir(td);
 
        if (io_u->ddir == DDIR_WRITE && (td->io_ops->flags & FIO_BARRIER) &&
            td->o.barrier_blocks &&
@@ -650,14 +656,15 @@ void clear_io_u(struct thread_data *td, struct io_u *io_u)
 void requeue_io_u(struct thread_data *td, struct io_u **io_u)
 {
        struct io_u *__io_u = *io_u;
+       enum fio_ddir ddir = acct_ddir(__io_u);
 
        dprint(FD_IO, "requeue %p\n", __io_u);
 
        td_io_u_lock(td);
 
        __io_u->flags |= IO_U_F_FREE;
-       if ((__io_u->flags & IO_U_F_FLIGHT) && ddir_rw(__io_u->ddir))
-               td->io_issues[__io_u->ddir]--;
+       if ((__io_u->flags & IO_U_F_FLIGHT) && ddir_rw(ddir))
+               td->io_issues[ddir]--;
 
        __io_u->flags &= ~IO_U_F_FLIGHT;
        if (__io_u->flags & IO_U_F_IN_CUR_DEPTH)
@@ -719,13 +726,9 @@ static int fill_io_u(struct thread_data *td, struct io_u *io_u)
        if (td_random(td) && file_randommap(td, io_u->file))
                mark_random_map(td, io_u);
 
-       /*
-        * If using a write iolog, store this entry.
-        */
 out:
        dprint_io_u(io_u, "fill_io_u");
        td->zone_bytes += io_u->buflen;
-       log_io_u(td, io_u);
        return 0;
 }
 
@@ -1091,6 +1094,7 @@ again:
                io_u->flags &= ~IO_U_F_VER_LIST;
 
                io_u->error = 0;
+               io_u->acct_ddir = -1;
                flist_del(&io_u->list);
                flist_add_tail(&io_u->list, &td->io_u_busylist);
                td->cur_depth++;
index 6809501ffa795fa46e59419d91345bfc3904a0a6..d5a0dc9c88d16c7b53e6d221b6cb9484e6a83e75 100644 (file)
@@ -8,7 +8,7 @@
 #include <guasi.h>
 #endif
 
-#define FIO_IOOPS_VERSION      14
+#define FIO_IOOPS_VERSION      15
 
 enum {
        IO_U_F_FREE             = 1 << 0,
@@ -56,6 +56,12 @@ struct io_u {
        unsigned int flags;
        enum fio_ddir ddir;
 
+       /*
+        * For replay workloads, we may want to account as a different
+        * IO type than what is being submitted.
+        */
+       enum fio_ddir acct_ddir;
+
        /*
         * Allocated/set buffer and length
         */
@@ -210,4 +216,12 @@ static inline void dprint_io_u(struct io_u *io_u, const char *p)
 #define dprint_io_u(io_u, p)
 #endif
 
+static inline enum fio_ddir acct_ddir(struct io_u *io_u)
+{
+       if (io_u->acct_ddir != -1)
+               return io_u->acct_ddir;
+
+       return io_u->ddir;
+}
+
 #endif
index f81c46f6c525571da6f32d5f606d1ee168a75c86..234f8edd13251ab07e7f7b431d3d90279c4c9b9a 100644 (file)
@@ -260,6 +260,11 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u)
 
        assert(fio_file_open(io_u->file));
 
+       /*
+        * If using a write iolog, store this entry.
+        */
+       log_io_u(td, io_u);
+
        io_u->error = 0;
        io_u->resid = 0;
 
@@ -275,8 +280,8 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u)
                                        sizeof(struct timeval));
        }
 
-       if (ddir_rw(io_u->ddir))
-               td->io_issues[io_u->ddir]++;
+       if (ddir_rw(acct_ddir(io_u)))
+               td->io_issues[acct_ddir(io_u)]++;
 
        ret = td->io_ops->queue(td, io_u);
 
index 8255072e4806ed2b871db7077fcaed62a0f92299..ac629dcbb7943a0f7f0f98c21e6a5885ee05d32d 100644 (file)
--- a/libfio.c
+++ b/libfio.c
@@ -67,6 +67,7 @@ static const char *fio_arch_strings[arch_nr] = {
 static void reset_io_counters(struct thread_data *td)
 {
        int ddir;
+
        for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++) {
                td->stat_io_bytes[ddir] = 0;
                td->this_io_bytes[ddir] = 0;
@@ -74,10 +75,12 @@ static void reset_io_counters(struct thread_data *td)
                td->this_io_blocks[ddir] = 0;
                td->rate_bytes[ddir] = 0;
                td->rate_blocks[ddir] = 0;
+               td->io_issues[ddir] = 0;
        }
        td->zone_bytes = 0;
 
        td->last_was_sync = 0;
+       td->rwmix_issues = 0;
 
        /*
         * reset file done count if we are to start over