Switch last_was_sync and terminate to bool and pack better
[fio.git] / io_u.c
diff --git a/io_u.c b/io_u.c
index 6b950014aa7cb6382d5ce2be00e18b30c745ba7f..404c75b382ab5e187a23ea33134092e05b40f2a8 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -759,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;
@@ -775,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;
 }
 
@@ -923,6 +922,45 @@ void requeue_io_u(struct thread_data *td, struct io_u **io_u)
        *io_u = NULL;
 }
 
+static void __fill_io_u_zone(struct thread_data *td, struct io_u *io_u)
+{
+       struct fio_file *f = io_u->file;
+
+       /*
+        * See if it's time to switch to a new zone
+        */
+       if (td->zone_bytes >= td->o.zone_size && td->o.zone_skip) {
+               td->zone_bytes = 0;
+               f->file_offset += td->o.zone_range + td->o.zone_skip;
+
+               /*
+                * Wrap from the beginning, if we exceed the file size
+                */
+               if (f->file_offset >= f->real_file_size)
+                       f->file_offset = f->real_file_size - f->file_offset;
+               f->last_pos[io_u->ddir] = f->file_offset;
+               td->io_skip_bytes += td->o.zone_skip;
+       }
+
+       /*
+        * If zone_size > zone_range, then maintain the same zone until
+        * zone_bytes >= zone_size.
+        */
+       if (f->last_pos[io_u->ddir] >= (f->file_offset + td->o.zone_range)) {
+               dprint(FD_IO, "io_u maintain zone offset=%" PRIu64 "/last_pos=%" PRIu64 "\n",
+                               f->file_offset, f->last_pos[io_u->ddir]);
+               f->last_pos[io_u->ddir] = f->file_offset;
+       }
+
+       /*
+        * For random: if 'norandommap' is not set and zone_size > zone_range,
+        * map needs to be reset as it's done with zone_range everytime.
+        */
+       if ((td->zone_bytes % td->o.zone_range) == 0) {
+               fio_file_reset(td, f);
+       }
+}
+
 static int fill_io_u(struct thread_data *td, struct io_u *io_u)
 {
        unsigned int is_random;
@@ -939,21 +977,10 @@ static int fill_io_u(struct thread_data *td, struct io_u *io_u)
                goto out;
 
        /*
-        * See if it's time to switch to a new zone
+        * When file is zoned zone_range is always positive
         */
-       if (td->zone_bytes >= td->o.zone_size && td->o.zone_skip) {
-               struct fio_file *f = io_u->file;
-
-               td->zone_bytes = 0;
-               f->file_offset += td->o.zone_range + td->o.zone_skip;
-
-               /*
-                * Wrap from the beginning, if we exceed the file size
-                */
-               if (f->file_offset >= f->real_file_size)
-                       f->file_offset = f->real_file_size - f->file_offset;
-               f->last_pos[io_u->ddir] = f->file_offset;
-               td->io_skip_bytes += td->o.zone_skip;
+       if (td->o.zone_range) {
+               __fill_io_u_zone(td, io_u);
        }
 
        /*
@@ -972,9 +999,8 @@ static int fill_io_u(struct thread_data *td, struct io_u *io_u)
        }
 
        if (io_u->offset + io_u->buflen > io_u->file->real_file_size) {
-               dprint(FD_IO, "io_u %p, offset + buflen exceeds file size\n",
-                       io_u);
-               dprint(FD_IO, "  offset=%llu/buflen=%lu > %llu\n",
+               dprint(FD_IO, "io_u %p, off=0x%llx + len=0x%lx exceeds file size=0x%llx\n",
+                       io_u,
                        (unsigned long long) io_u->offset, io_u->buflen,
                        (unsigned long long) io_u->file->real_file_size);
                return 1;
@@ -987,7 +1013,7 @@ static int fill_io_u(struct thread_data *td, struct io_u *io_u)
                mark_random_map(td, io_u);
 
 out:
-       dprint_io_u(io_u, "fill_io_u");
+       dprint_io_u(io_u, "fill");
        td->zone_bytes += io_u->buflen;
        return 0;
 }
@@ -1409,10 +1435,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;
 }
@@ -1615,22 +1641,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;
        }
 
@@ -1672,32 +1695,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;
        }
@@ -1868,14 +1899,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);
                }
        }
 
@@ -1890,7 +1921,8 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
 
                if (no_reduce && per_unit_log(td->iops_log))
                        add_iops_sample(td, io_u, bytes);
-       }
+       } else if (ddir_sync(idx) && !td->o.disable_clat)
+               add_sync_clat_sample(&td->ts, llnsec);
 
        if (td->ts.nr_block_infos && io_u->ddir == DDIR_TRIM) {
                uint32_t *info = io_u_block_info(td, io_u);
@@ -1928,6 +1960,12 @@ static void file_log_write_comp(const struct thread_data *td, struct fio_file *f
                f->last_write_idx = 0;
 }
 
+static bool should_account(struct thread_data *td)
+{
+       return ramp_time_over(td) && (td->runstate == TD_RUNNING ||
+                                          td->runstate == TD_VERIFYING);
+}
+
 static void io_completed(struct thread_data *td, struct io_u **io_u_ptr,
                         struct io_completion_data *icd)
 {
@@ -1935,7 +1973,7 @@ static void io_completed(struct thread_data *td, struct io_u **io_u_ptr,
        enum fio_ddir ddir = io_u->ddir;
        struct fio_file *f = io_u->file;
 
-       dprint_io_u(io_u, "io complete");
+       dprint_io_u(io_u, "complete");
 
        assert(io_u->flags & IO_U_F_FLIGHT);
        io_u_clear(td, io_u, IO_U_F_FLIGHT | IO_U_F_BUSY_OK);
@@ -1956,15 +1994,17 @@ static void io_completed(struct thread_data *td, struct io_u **io_u_ptr,
        }
 
        if (ddir_sync(ddir)) {
-               td->last_was_sync = 1;
+               td->last_was_sync = true;
                if (f) {
                        f->first_write = -1ULL;
                        f->last_write = -1ULL;
                }
+               if (should_account(td))
+                       account_io_completion(td, io_u, icd, ddir, io_u->buflen);
                return;
        }
 
-       td->last_was_sync = 0;
+       td->last_was_sync = false;
        td->last_ddir = ddir;
 
        if (!io_u->error && ddir_rw(ddir)) {
@@ -1972,17 +2012,17 @@ 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);
 
-               if (ramp_time_over(td) && (td->runstate == TD_RUNNING ||
-                                          td->runstate == TD_VERIFYING))
+               if (should_account(td))
                        account_io_completion(td, io_u, icd, ddir, bytes);
 
                icd->bytes_done[ddir] += bytes;