io_u: rate cleanup and spelling error
[fio.git] / io_u.c
diff --git a/io_u.c b/io_u.c
index 8d42d6541f7dbb9592639619874295153101bd91..42d98ebfe1d6a0dc85193348a77de95667ff117f 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -37,7 +37,7 @@ static bool random_map_free(struct fio_file *f, const uint64_t block)
  */
 static void mark_random_map(struct thread_data *td, struct io_u *io_u)
 {
-       unsigned int min_bs = td->o.rw_min_bs;
+       unsigned int min_bs = td->o.min_bs[io_u->ddir];
        struct fio_file *f = io_u->file;
        unsigned int nr_blocks;
        uint64_t block;
@@ -157,6 +157,66 @@ static int __get_next_rand_offset_gauss(struct thread_data *td,
        return 0;
 }
 
+static int __get_next_rand_offset_zoned_abs(struct thread_data *td,
+                                           struct fio_file *f,
+                                           enum fio_ddir ddir, uint64_t *b)
+{
+       struct zone_split_index *zsi;
+       uint64_t lastb, send, stotal;
+       static int warned;
+       unsigned int v;
+
+       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);
+
+       /*
+        * Find our generated table. 'send' is the end block of this zone,
+        * 'stotal' is our start offset.
+        */
+       zsi = &td->zone_state_index[ddir][v - 1];
+       stotal = zsi->size_prev / td->o.ba[ddir];
+       send = zsi->size / td->o.ba[ddir];
+
+       /*
+        * Should never happen
+        */
+       if (send == -1U) {
+               if (!warned) {
+                       log_err("fio: bug in zoned generation\n");
+                       warned = 1;
+               }
+               goto bail;
+       } else if (send > lastb) {
+               /*
+                * This happens if the user specifies ranges that exceed
+                * the file/device size. We can't handle that gracefully,
+                * so error and exit.
+                */
+               log_err("fio: zoned_abs sizes exceed file size\n");
+               return 1;
+       }
+
+       /*
+        * Generate index from 0..send-stotal
+        */
+       if (__get_next_rand_offset(td, f, ddir, b, send - stotal) == 1)
+               return 1;
+
+       *b += stotal;
+       return 0;
+}
+
 static int __get_next_rand_offset_zoned(struct thread_data *td,
                                        struct fio_file *f, enum fio_ddir ddir,
                                        uint64_t *b)
@@ -249,6 +309,8 @@ static int get_off_from_method(struct thread_data *td, struct fio_file *f,
                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);
+       else if (td->o.random_distribution == FIO_RAND_DIST_ZONED_ABS)
+               return __get_next_rand_offset_zoned_abs(td, f, ddir, b);
 
        log_err("fio: unknown random distribution: %d\n", td->o.random_distribution);
        return 1;
@@ -323,6 +385,17 @@ fetch:
        goto fetch;
 }
 
+static void loop_cache_invalidate(struct thread_data *td, struct fio_file *f)
+{
+       struct thread_options *o = &td->o;
+
+       if (o->invalidate_cache && !o->odirect) {
+               int fio_unused ret;
+
+               ret = file_invalidate_cache(td, f);
+       }
+}
+
 static int get_next_rand_block(struct thread_data *td, struct fio_file *f,
                               enum fio_ddir ddir, uint64_t *b)
 {
@@ -334,6 +407,7 @@ static int get_next_rand_block(struct thread_data *td, struct fio_file *f,
                fio_file_reset(td, f);
                if (!get_next_rand_offset(td, f, ddir, b))
                        return 0;
+               loop_cache_invalidate(td, f);
        }
 
        dprint(FD_IO, "%s: rand offset failed, last=%llu, size=%llu\n",
@@ -349,15 +423,14 @@ static int get_next_seq_offset(struct thread_data *td, struct fio_file *f,
 
        assert(ddir_rw(ddir));
 
+       /*
+        * If we reach the end for a time based run, reset us back to 0
+        * and invalidate the cache, if we need to.
+        */
        if (f->last_pos[ddir] >= f->io_size + get_start_offset(td, f) &&
            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;
+               f->last_pos[ddir] = f->file_offset;
+               loop_cache_invalidate(td, f);
        }
 
        if (f->last_pos[ddir] < f->real_file_size) {
@@ -552,9 +625,9 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u,
        if (!io_u_fits(td, io_u, minbs))
                return 0;
 
-       frand_max = rand_max(&td->bsrange_state);
+       frand_max = rand_max(&td->bsrange_state[ddir]);
        do {
-               r = __rand(&td->bsrange_state);
+               r = __rand(&td->bsrange_state[ddir]);
 
                if (!td->o.bssplit_nr[ddir]) {
                        buflen = 1 + (unsigned int) ((double) maxbs *
@@ -662,7 +735,7 @@ int io_u_quiesce(struct thread_data *td)
 static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir)
 {
        enum fio_ddir odir = ddir ^ 1;
-       long usec;
+       uint64_t usec;
        uint64_t now;
 
        assert(ddir_rw(ddir));
@@ -686,11 +759,11 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir)
                        return odir;
 
                /*
-                * Both directions are ahead of rate. sleep the min
-                * switch if necissary
+                * Both directions are ahead of rate. sleep the min,
+                * switch if necessary
                 */
                if (td->rate_next_io_time[ddir] <=
-                       td->rate_next_io_time[odir]) {
+                   td->rate_next_io_time[odir]) {
                        usec = td->rate_next_io_time[ddir] - now;
                } else {
                        usec = td->rate_next_io_time[odir] - now;
@@ -702,8 +775,7 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir)
        if (td->o.io_submit_mode == IO_MODE_INLINE)
                io_u_quiesce(td);
 
-       usec = usec_sleep(td, usec);
-
+       usec_sleep(td, usec);
        return ddir;
 }
 
@@ -1336,10 +1408,10 @@ static long set_io_u_file(struct thread_data *td, struct io_u *io_u)
 }
 
 static void lat_fatal(struct thread_data *td, struct io_completion_data *icd,
-                     unsigned long tusec, unsigned long max_usec)
+                     unsigned long long tnsec, unsigned long long max_nsec)
 {
        if (!td->error)
-               log_err("fio: latency of %lu usec exceeds specified max (%lu usec)\n", tusec, max_usec);
+               log_err("fio: latency of %llu nsec exceeds specified max (%llu nsec)\n", tnsec, max_nsec);
        td_verror(td, ETIMEDOUT, "max latency exceeded");
        icd->error = ETIMEDOUT;
 }
@@ -1542,22 +1614,19 @@ static bool check_get_trim(struct thread_data *td, struct io_u *io_u)
 {
        if (!(td->flags & TD_F_TRIM_BACKLOG))
                return false;
+       if (!td->trim_entries)
+               return false;
 
-       if (td->trim_entries) {
-               int get_trim = 0;
-
-               if (td->trim_batch) {
-                       td->trim_batch--;
-                       get_trim = 1;
-               } else if (!(td->io_hist_len % td->o.trim_backlog) &&
-                        td->last_ddir != DDIR_READ) {
-                       td->trim_batch = td->o.trim_batch;
-                       if (!td->trim_batch)
-                               td->trim_batch = td->o.trim_backlog;
-                       get_trim = 1;
-               }
-
-               if (get_trim && get_next_trim(td, io_u))
+       if (td->trim_batch) {
+               td->trim_batch--;
+               if (get_next_trim(td, io_u))
+                       return true;
+       } else if (!(td->io_hist_len % td->o.trim_backlog) &&
+                    td->last_ddir != DDIR_READ) {
+               td->trim_batch = td->o.trim_batch;
+               if (!td->trim_batch)
+                       td->trim_batch = td->o.trim_backlog;
+               if (get_next_trim(td, io_u))
                        return true;
        }
 
@@ -1599,32 +1668,40 @@ static bool check_get_verify(struct thread_data *td, struct io_u *io_u)
  */
 static void small_content_scramble(struct io_u *io_u)
 {
-       unsigned int i, nr_blocks = io_u->buflen / 512;
-       uint64_t boffset;
+       unsigned int i, nr_blocks = io_u->buflen >> 9;
        unsigned int offset;
-       char *p, *end;
+       uint64_t boffset, *iptr;
+       char *p;
 
        if (!nr_blocks)
                return;
 
        p = io_u->xfer_buf;
        boffset = io_u->offset;
-       io_u->buf_filled_len = 0;
+
+       if (io_u->buf_filled_len)
+               io_u->buf_filled_len = 0;
+
+       /*
+        * Generate random index between 0..7. We do chunks of 512b, if
+        * we assume a cacheline is 64 bytes, then we have 8 of those.
+        * Scramble content within the blocks in the same cacheline to
+        * speed things up.
+        */
+       offset = (io_u->start_time.tv_nsec ^ boffset) & 7;
 
        for (i = 0; i < nr_blocks; i++) {
                /*
-                * Fill the byte offset into a "random" start offset of
-                * the buffer, given by the product of the usec time
-                * and the actual offset.
+                * Fill offset into start of cacheline, time into end
+                * of cacheline
                 */
-               offset = ((io_u->start_time.tv_nsec/1000) ^ boffset) & 511;
-               offset &= ~(sizeof(uint64_t) - 1);
-               if (offset >= 512 - sizeof(uint64_t))
-                       offset -= sizeof(uint64_t);
-               memcpy(p + offset, &boffset, sizeof(boffset));
-
-               end = p + 512 - sizeof(io_u->start_time);
-               memcpy(end, &io_u->start_time, sizeof(io_u->start_time));
+               iptr = (void *) p + (offset << 6);
+               *iptr = boffset;
+
+               iptr = (void *) p + 64 - 2 * sizeof(uint64_t);
+               iptr[0] = io_u->start_time.tv_sec;
+               iptr[1] = io_u->start_time.tv_nsec;
+
                p += 512;
                boffset += 512;
        }
@@ -1779,7 +1856,7 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
        if (td->parent)
                td = td->parent;
 
-       if (!td->o.stats)
+       if (!td->o.stats || td_ioengine_flagged(td, FIO_NOSTATS))
                return;
 
        if (no_reduce)
@@ -1795,14 +1872,14 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
                        struct prof_io_ops *ops = &td->prof_io_ops;
 
                        if (ops->io_u_lat)
-                               icd->error = ops->io_u_lat(td, tnsec/1000);
+                               icd->error = ops->io_u_lat(td, tnsec);
                }
 
-               if (td->o.max_latency && tnsec/1000 > td->o.max_latency)
-                       lat_fatal(td, icd, tnsec/1000, td->o.max_latency);
-               if (td->o.latency_target && tnsec/1000 > td->o.latency_target) {
+               if (td->o.max_latency && tnsec > td->o.max_latency)
+                       lat_fatal(td, icd, tnsec, td->o.max_latency);
+               if (td->o.latency_target && tnsec > td->o.latency_target) {
                        if (lat_target_failed(td))
-                               lat_fatal(td, icd, tnsec/1000, td->o.latency_target);
+                               lat_fatal(td, icd, tnsec, td->o.latency_target);
                }
        }
 
@@ -1899,11 +1976,12 @@ static void io_completed(struct thread_data *td, struct io_u **io_u_ptr,
                int ret;
 
                td->io_blocks[ddir]++;
-               td->this_io_blocks[ddir]++;
                td->io_bytes[ddir] += bytes;
 
-               if (!(io_u->flags & IO_U_F_VER_LIST))
+               if (!(io_u->flags & IO_U_F_VER_LIST)) {
+                       td->this_io_blocks[ddir]++;
                        td->this_io_bytes[ddir] += bytes;
+               }
 
                if (ddir == DDIR_WRITE)
                        file_log_write_comp(td, f, io_u->offset, bytes);
@@ -2188,7 +2266,7 @@ int do_io_u_trim(const struct thread_data *td, struct io_u *io_u)
        struct fio_file *f = io_u->file;
        int ret;
 
-       ret = os_trim(f->fd, io_u->offset, io_u->xfer_buflen);
+       ret = os_trim(f, io_u->offset, io_u->xfer_buflen);
        if (!ret)
                return io_u->xfer_buflen;