io_u: if we're doing backwards IO, wrap to end (not start)
[fio.git] / io_u.c
diff --git a/io_u.c b/io_u.c
index 9628d5e32c791e1a847013be81cad3488687a024..f9870e70bc8d408ab7bf72adcf46cddf6818b4da 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -86,24 +86,19 @@ struct rand_off {
 };
 
 static int __get_next_rand_offset(struct thread_data *td, struct fio_file *f,
-                                 enum fio_ddir ddir, uint64_t *b)
+                                 enum fio_ddir ddir, uint64_t *b,
+                                 uint64_t lastb)
 {
        uint64_t r;
 
        if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE ||
            td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64) {
-               uint64_t frand_max, lastb;
 
-               lastb = last_block(td, f, ddir);
-               if (!lastb)
-                       return 1;
-
-               frand_max = rand_max(&td->random_state);
                r = __rand(&td->random_state);
 
                dprint(FD_RANDOM, "off rand %llu\n", (unsigned long long) r);
 
-               *b = lastb * (r / ((uint64_t) frand_max + 1.0));
+               *b = lastb * (r / (rand_max(&td->random_state) + 1.0));
        } else {
                uint64_t off = 0;
 
@@ -161,6 +156,70 @@ static int __get_next_rand_offset_gauss(struct thread_data *td,
        return 0;
 }
 
+static int __get_next_rand_offset_zoned(struct thread_data *td,
+                                       struct fio_file *f, enum fio_ddir ddir,
+                                       uint64_t *b)
+{
+       unsigned int v, send, stotal;
+       uint64_t offset, lastb;
+       static int warned;
+       struct zone_split_index *zsi;
+
+       lastb = last_block(td, f, ddir);
+       if (!lastb)
+               return 1;
+
+       if (!td->o.zone_split_nr[ddir]) {
+bail:
+               return __get_next_rand_offset(td, f, ddir, b, lastb);
+       }
+
+       /*
+        * Generate a value, v, between 1 and 100, both inclusive
+        */
+       v = rand32_between(&td->zone_state, 1, 100);
+
+       zsi = &td->zone_state_index[ddir][v - 1];
+       stotal = zsi->size_perc_prev;
+       send = zsi->size_perc;
+
+       /*
+        * Should never happen
+        */
+       if (send == -1U) {
+               if (!warned) {
+                       log_err("fio: bug in zoned generation\n");
+                       warned = 1;
+               }
+               goto bail;
+       }
+
+       /*
+        * 'send' is some percentage below or equal to 100 that
+        * marks the end of the current IO range. 'stotal' marks
+        * the start, in percent.
+        */
+       if (stotal)
+               offset = stotal * lastb / 100ULL;
+       else
+               offset = 0;
+
+       lastb = lastb * (send - stotal) / 100ULL;
+
+       /*
+        * Generate index from 0..send-of-lastb
+        */
+       if (__get_next_rand_offset(td, f, ddir, b, lastb) == 1)
+               return 1;
+
+       /*
+        * Add our start offset, if any
+        */
+       if (offset)
+               *b += offset;
+
+       return 0;
+}
 
 static int flist_cmp(void *data, struct flist_head *a, struct flist_head *b)
 {
@@ -173,14 +232,22 @@ static int flist_cmp(void *data, struct flist_head *a, struct flist_head *b)
 static int get_off_from_method(struct thread_data *td, struct fio_file *f,
                               enum fio_ddir ddir, uint64_t *b)
 {
-       if (td->o.random_distribution == FIO_RAND_DIST_RANDOM)
-               return __get_next_rand_offset(td, f, ddir, b);
-       else if (td->o.random_distribution == FIO_RAND_DIST_ZIPF)
+       if (td->o.random_distribution == FIO_RAND_DIST_RANDOM) {
+               uint64_t lastb;
+
+               lastb = last_block(td, f, ddir);
+               if (!lastb)
+                       return 1;
+
+               return __get_next_rand_offset(td, f, ddir, b, lastb);
+       } else if (td->o.random_distribution == FIO_RAND_DIST_ZIPF)
                return __get_next_rand_offset_zipf(td, f, ddir, b);
        else if (td->o.random_distribution == FIO_RAND_DIST_PARETO)
                return __get_next_rand_offset_pareto(td, f, ddir, b);
        else if (td->o.random_distribution == FIO_RAND_DIST_GAUSS)
                return __get_next_rand_offset_gauss(td, f, ddir, b);
+       else if (td->o.random_distribution == FIO_RAND_DIST_ZONED)
+               return __get_next_rand_offset_zoned(td, f, ddir, b);
 
        log_err("fio: unknown random distribution: %d\n", td->o.random_distribution);
        return 1;
@@ -207,16 +274,12 @@ static inline bool should_sort_io(struct thread_data *td)
 
 static bool should_do_random(struct thread_data *td, enum fio_ddir ddir)
 {
-       uint64_t frand_max;
        unsigned int v;
-       unsigned long r;
 
        if (td->o.perc_rand[ddir] == 100)
                return true;
 
-       frand_max = rand_max(&td->seq_rand_state[ddir]);
-       r = __rand(&td->seq_rand_state[ddir]);
-       v = 1 + (int) (100.0 * (r / (frand_max + 1.0)));
+       v = rand32_between(&td->seq_rand_state[ddir], 1, 100);
 
        return v <= td->o.perc_rand[ddir];
 }
@@ -285,8 +348,15 @@ static int get_next_seq_offset(struct thread_data *td, struct fio_file *f,
        assert(ddir_rw(ddir));
 
        if (f->last_pos[ddir] >= f->io_size + get_start_offset(td, f) &&
-           o->time_based)
-               f->last_pos[ddir] = f->last_pos[ddir] - f->io_size;
+           o->time_based) {
+               struct thread_options *o = &td->o;
+               uint64_t io_size = f->io_size + (f->io_size % o->min_bs[ddir]);
+
+               if (io_size > f->last_pos[ddir])
+                       f->last_pos[ddir] = 0;
+               else
+                       f->last_pos[ddir] = f->last_pos[ddir] - io_size;
+       }
 
        if (f->last_pos[ddir] < f->real_file_size) {
                uint64_t pos;
@@ -301,10 +371,15 @@ static int get_next_seq_offset(struct thread_data *td, struct fio_file *f,
                        /*
                         * If we reach beyond the end of the file
                         * with holed IO, wrap around to the
-                        * beginning again.
+                        * beginning again. If we're doing backwards IO,
+                        * wrap to the end.
                         */
-                       if (pos >= f->real_file_size)
-                               pos = f->file_offset;
+                       if (pos >= f->real_file_size) {
+                               if (o->ddir_seq_add > 0)
+                                       pos = f->file_offset;
+                               else
+                                       pos = f->real_file_size + o->ddir_seq_add;
+                       }
                }
 
                *offset = pos;
@@ -483,7 +558,7 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u,
 
                                buflen = bsp->bs;
                                perc += bsp->perc;
-                               if ((r <= ((frand_max / 100L) * perc)) &&
+                               if ((r * 100UL <= frand_max * perc) &&
                                    io_u_fits(td, io_u, buflen))
                                        break;
                        }
@@ -529,12 +604,9 @@ static void set_rwmix_bytes(struct thread_data *td)
 
 static inline enum fio_ddir get_rand_ddir(struct thread_data *td)
 {
-       uint64_t frand_max = rand_max(&td->rwmix_state);
        unsigned int v;
-       unsigned long r;
 
-       r = __rand(&td->rwmix_state);
-       v = 1 + (int) (100.0 * (r / (frand_max + 1.0)));
+       v = rand32_between(&td->rwmix_state, 1, 100);
 
        if (v <= td->o.rwmix[DDIR_READ])
                return DDIR_READ;
@@ -1600,7 +1672,7 @@ void io_u_log_error(struct thread_data *td, struct io_u *io_u)
 {
        __io_u_log_error(td, io_u);
        if (td->parent)
-               __io_u_log_error(td, io_u);
+               __io_u_log_error(td->parent, io_u);
 }
 
 static inline bool gtod_reduce(struct thread_data *td)
@@ -1643,16 +1715,18 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
                }
        }
 
-       if (!td->o.disable_clat) {
-               add_clat_sample(td, idx, lusec, bytes, io_u->offset);
-               io_u_mark_latency(td, lusec);
-       }
+       if (ddir_rw(idx)) {
+               if (!td->o.disable_clat) {
+                       add_clat_sample(td, idx, lusec, bytes, io_u->offset);
+                       io_u_mark_latency(td, lusec);
+               }
 
-       if (!td->o.disable_bw)
-               add_bw_sample(td, idx, bytes, &icd->time);
+               if (!td->o.disable_bw && per_unit_log(td->bw_log))
+                       add_bw_sample(td, io_u, bytes, lusec);
 
-       if (no_reduce)
-               add_iops_sample(td, idx, bytes, &icd->time);
+               if (no_reduce && per_unit_log(td->iops_log))
+                       add_iops_sample(td, io_u, bytes);
+       }
 
        if (td->ts.nr_block_infos && io_u->ddir == DDIR_TRIM) {
                uint32_t *info = io_u_block_info(td, io_u);
@@ -1668,6 +1742,28 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
        }
 }
 
+static void file_log_write_comp(const struct thread_data *td, struct fio_file *f,
+                               uint64_t offset, unsigned int bytes)
+{
+       int idx;
+
+       if (!f)
+               return;
+
+       if (f->first_write == -1ULL || offset < f->first_write)
+               f->first_write = offset;
+       if (f->last_write == -1ULL || ((offset + bytes) > f->last_write))
+               f->last_write = offset + bytes;
+
+       if (!f->last_write_comp)
+               return;
+
+       idx = f->last_write_idx++;
+       f->last_write_comp[idx] = offset;
+       if (f->last_write_idx == td->o.iodepth)
+               f->last_write_idx = 0;
+}
+
 static void io_completed(struct thread_data *td, struct io_u **io_u_ptr,
                         struct io_completion_data *icd)
 {
@@ -1718,23 +1814,8 @@ static void io_completed(struct thread_data *td, struct io_u **io_u_ptr,
                if (!(io_u->flags & IO_U_F_VER_LIST))
                        td->this_io_bytes[ddir] += bytes;
 
-               if (ddir == DDIR_WRITE) {
-                       if (f) {
-                               if (f->first_write == -1ULL ||
-                                   io_u->offset < f->first_write)
-                                       f->first_write = io_u->offset;
-                               if (f->last_write == -1ULL ||
-                                   ((io_u->offset + bytes) > f->last_write))
-                                       f->last_write = io_u->offset + bytes;
-                       }
-                       if (td->last_write_comp) {
-                               int idx = td->last_write_idx++;
-
-                               td->last_write_comp[idx] = io_u->offset;
-                               if (td->last_write_idx == td->o.iodepth)
-                                       td->last_write_idx = 0;
-                       }
-               }
+               if (ddir == DDIR_WRITE)
+                       file_log_write_comp(td, f, io_u->offset, bytes);
 
                if (ramp_time_over(td) && (td->runstate == TD_RUNNING ||
                                           td->runstate == TD_VERIFYING))
@@ -1888,9 +1969,7 @@ void io_u_queued(struct thread_data *td, struct io_u *io_u)
  */
 static struct frand_state *get_buf_state(struct thread_data *td)
 {
-       uint64_t frand_max;
        unsigned int v;
-       unsigned long r;
 
        if (!td->o.dedupe_percentage)
                return &td->buf_state;
@@ -1899,9 +1978,7 @@ static struct frand_state *get_buf_state(struct thread_data *td)
                return &td->buf_state;
        }
 
-       frand_max = rand_max(&td->dedupe_state);
-       r = __rand(&td->dedupe_state);
-       v = 1 + (int) (100.0 * (r / (frand_max + 1.0)));
+       v = rand32_between(&td->dedupe_state, 1, 100);
 
        if (v <= td->o.dedupe_percentage)
                return &td->buf_state_prev;