Fixing wraparound behavior for time-based sequential read jobs
[fio.git] / io_u.c
diff --git a/io_u.c b/io_u.c
index ca33e589c6500f36a76e75cbdadc98a73ef4750f..2f5456294cea559bd97504f7c534626eb0933344 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -13,7 +13,6 @@
 
 struct io_completion_data {
        int nr;                         /* input */
-       int account;                    /* input */
 
        int error;                      /* output */
        unsigned long bytes_done[2];    /* output */
@@ -238,20 +237,28 @@ ret:
 static int get_next_rand_block(struct thread_data *td, struct fio_file *f,
                               enum fio_ddir ddir, unsigned long long *b)
 {
-       if (get_next_rand_offset(td, f, ddir, b)) {
-               dprint(FD_IO, "%s: rand offset failed, last=%llu, size=%llu\n",
-                               f->file_name, f->last_pos, f->real_file_size);
-               return 1;
+       if (!get_next_rand_offset(td, f, ddir, b))
+               return 0;
+
+       if (td->o.time_based) {
+               fio_file_reset(f);
+               if (!get_next_rand_offset(td, f, ddir, b))
+                       return 0;
        }
 
-       return 0;
+       dprint(FD_IO, "%s: rand offset failed, last=%llu, size=%llu\n",
+                       f->file_name, f->last_pos, f->real_file_size);
+       return 1;
 }
 
-static int get_next_seq_block(struct thread_data *td, struct fio_file *f,
-                             enum fio_ddir ddir, unsigned long long *b)
+static int get_next_seq_offset(struct thread_data *td, struct fio_file *f,
+                              enum fio_ddir ddir, unsigned long long *offset)
 {
        assert(ddir_rw(ddir));
 
+       if (f->last_pos >= f->io_size + get_start_offset(td) && td->o.time_based)
+               f->last_pos = f->last_pos - f->io_size;
+
        if (f->last_pos < f->real_file_size) {
                unsigned long long pos;
 
@@ -262,7 +269,7 @@ static int get_next_seq_block(struct thread_data *td, struct fio_file *f,
                if (pos)
                        pos += td->o.ddir_seq_add;
 
-               *b = pos / td->o.min_bs[ddir];
+               *offset = pos;
                return 0;
        }
 
@@ -270,31 +277,33 @@ static int get_next_seq_block(struct thread_data *td, struct fio_file *f,
 }
 
 static int get_next_block(struct thread_data *td, struct io_u *io_u,
-                         enum fio_ddir ddir, int rw_seq, unsigned long long *b)
+                         enum fio_ddir ddir, int rw_seq)
 {
        struct fio_file *f = io_u->file;
+       unsigned long long b, offset;
        int ret;
 
        assert(ddir_rw(ddir));
 
+       b = offset = -1ULL;
+
        if (rw_seq) {
                if (td_random(td))
-                       ret = get_next_rand_block(td, f, ddir, b);
+                       ret = get_next_rand_block(td, f, ddir, &b);
                else
-                       ret = get_next_seq_block(td, f, ddir, b);
+                       ret = get_next_seq_offset(td, f, ddir, &offset);
        } else {
                io_u->flags |= IO_U_F_BUSY_OK;
 
                if (td->o.rw_seq == RW_SEQ_SEQ) {
-                       ret = get_next_seq_block(td, f, ddir, b);
+                       ret = get_next_seq_offset(td, f, ddir, &offset);
                        if (ret)
-                               ret = get_next_rand_block(td, f, ddir, b);
+                               ret = get_next_rand_block(td, f, ddir, &b);
                } else if (td->o.rw_seq == RW_SEQ_IDENT) {
                        if (f->last_start != -1ULL)
-                               *b = (f->last_start - f->file_offset)
-                                       / td->o.min_bs[ddir];
+                               offset = f->last_start - f->file_offset;
                        else
-                               *b = 0;
+                               offset = 0;
                        ret = 0;
                } else {
                        log_err("fio: unknown rw_seq=%d\n", td->o.rw_seq);
@@ -302,6 +311,17 @@ static int get_next_block(struct thread_data *td, struct io_u *io_u,
                }
        }
        
+       if (!ret) {
+               if (offset != -1ULL)
+                       io_u->offset = offset;
+               else if (b != -1ULL)
+                       io_u->offset = b * td->o.ba[ddir];
+               else {
+                       log_err("fio: bug in offset generation\n");
+                       ret = 1;
+               }
+       }
+
        return ret;
 }
 
@@ -313,7 +333,6 @@ static int get_next_block(struct thread_data *td, struct io_u *io_u,
 static int __get_next_offset(struct thread_data *td, struct io_u *io_u)
 {
        struct fio_file *f = io_u->file;
-       unsigned long long b;
        enum fio_ddir ddir = io_u->ddir;
        int rw_seq_hit = 0;
 
@@ -324,10 +343,9 @@ static int __get_next_offset(struct thread_data *td, struct io_u *io_u)
                td->ddir_seq_nr = td->o.ddir_seq_nr;
        }
 
-       if (get_next_block(td, io_u, ddir, rw_seq_hit, &b))
+       if (get_next_block(td, io_u, ddir, rw_seq_hit))
                return 1;
 
-       io_u->offset = b * td->o.ba[ddir];
        if (io_u->offset >= f->io_size) {
                dprint(FD_IO, "get_next_offset: offset %llu >= io_size %llu\n",
                                        io_u->offset, f->io_size);
@@ -359,7 +377,7 @@ static inline int io_u_fits(struct thread_data *td, struct io_u *io_u,
 {
        struct fio_file *f = io_u->file;
 
-       return io_u->offset + buflen <= f->io_size + td->o.start_offset;
+       return io_u->offset + buflen <= f->io_size + get_start_offset(td);
 }
 
 static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u)
@@ -1070,6 +1088,7 @@ again:
                assert(io_u->flags & IO_U_F_FREE);
                io_u->flags &= ~(IO_U_F_FREE | IO_U_F_FREE_DEF);
                io_u->flags &= ~(IO_U_F_TRIMMED | IO_U_F_BARRIER);
+               io_u->flags &= ~IO_U_F_VER_LIST;
 
                io_u->error = 0;
                flist_del(&io_u->list);
@@ -1292,9 +1311,6 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
 {
        unsigned long uninitialized_var(lusec);
 
-       if (!icd->account)
-               return;
-
        if (!td->o.disable_clat || !td->o.disable_bw)
                lusec = utime_since(&io_u->issue_time, &icd->time);
 
@@ -1365,7 +1381,9 @@ static void io_completed(struct thread_data *td, struct io_u *io_u,
                td->io_blocks[idx]++;
                td->this_io_blocks[idx]++;
                td->io_bytes[idx] += bytes;
-               td->this_io_bytes[idx] += bytes;
+
+               if (!(io_u->flags & IO_U_F_VER_LIST))
+                       td->this_io_bytes[idx] += bytes;
 
                if (idx == DDIR_WRITE) {
                        f = io_u->file;
@@ -1430,7 +1448,6 @@ static void init_icd(struct thread_data *td, struct io_completion_data *icd,
                fio_gettime(&icd->time, NULL);
 
        icd->nr = nr;
-       icd->account = 1;
 
        icd->error = 0;
        icd->bytes_done[0] = icd->bytes_done[1] = 0;
@@ -1449,8 +1466,6 @@ static void ios_completed(struct thread_data *td,
 
                if (!(io_u->flags & IO_U_F_FREE_DEF))
                        put_io_u(td, io_u);
-
-               icd->account = 0;
        }
 }
 
@@ -1544,8 +1559,11 @@ void io_u_fill_buffer(struct thread_data *td, struct io_u *io_u,
                unsigned int perc = td->o.compress_percentage;
 
                if (perc) {
+                       unsigned int seg = min_write;
+
+                       seg = min(min_write, td->o.compress_chunk);
                        fill_random_buf_percentage(&td->buf_state, io_u->buf,
-                                               perc, min_write, max_bs);
+                                               perc, seg, max_bs);
                } else
                        fill_random_buf(&td->buf_state, io_u->buf, max_bs);
        } else