genfio: Splitting gen_template in 2 parts
[fio.git] / io_u.c
diff --git a/io_u.c b/io_u.c
index e474b48f9ca0c4ab5a26f49363f90e2a4bacc1d2..865c58260d976b916cc2d526a84609c968ca5132 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -191,6 +191,25 @@ static inline int should_sort_io(struct thread_data *td)
        return 1;
 }
 
+static int should_do_random(struct thread_data *td)
+{
+       unsigned int v;
+       unsigned long r;
+
+       if (td->o.perc_rand == 100)
+               return 1;
+
+       if (td->o.use_os_rand) {
+               r = os_random_long(&td->seq_rand_state);
+               v = 1 + (int) (100.0 * (r / (OS_RAND_MAX + 1.0)));
+       } else {
+               r = __rand(&td->__seq_rand_state);
+               v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0)));
+       }
+
+       return v <= td->o.perc_rand;
+}
+
 static int get_next_rand_offset(struct thread_data *td, struct fio_file *f,
                                enum fio_ddir ddir, uint64_t *b)
 {
@@ -285,9 +304,16 @@ static int get_next_block(struct thread_data *td, struct io_u *io_u,
        b = offset = -1ULL;
 
        if (rw_seq) {
-               if (td_random(td))
-                       ret = get_next_rand_block(td, f, ddir, &b);
-               else
+               if (td_random(td)) {
+                       if (should_do_random(td))
+                               ret = get_next_rand_block(td, f, ddir, &b);
+                       else {
+                               io_u->flags |= IO_U_F_BUSY_OK;
+                               ret = get_next_seq_offset(td, f, ddir, &offset);
+                               if (ret)
+                                       ret = get_next_rand_block(td, f, ddir, &b);
+                       }
+               } else
                        ret = get_next_seq_offset(td, f, ddir, &offset);
        } else {
                io_u->flags |= IO_U_F_BUSY_OK;
@@ -314,8 +340,7 @@ static int get_next_block(struct thread_data *td, struct io_u *io_u,
                else if (b != -1ULL)
                        io_u->offset = b * td->o.ba[ddir];
                else {
-                       log_err("fio: bug in offset generation: offset=%llu, b=%llu\n",
-                                                               offset, b);
+                       log_err("fio: bug in offset generation: offset=%llu, b=%llu\n", (unsigned long long) offset, (unsigned long long) b);
                        ret = 1;
                }
        }
@@ -434,6 +459,10 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u)
                        }
                }
 
+               if (td->o.do_verify && td->o.verify != VERIFY_NONE)
+                       buflen = (buflen + td->o.verify_interval - 1) &
+                               ~(td->o.verify_interval - 1);
+
                if (!td->o.bs_unaligned && is_power_of_2(minbs))
                        buflen = (buflen + minbs - 1) & ~(minbs - 1);
 
@@ -486,6 +515,24 @@ static inline enum fio_ddir get_rand_ddir(struct thread_data *td)
        return DDIR_WRITE;
 }
 
+void io_u_quiesce(struct thread_data *td)
+{
+       /*
+        * We are going to sleep, ensure that we flush anything pending as
+        * not to skew our latency numbers.
+        *
+        * Changed to only monitor 'in flight' requests here instead of the
+        * td->cur_depth, b/c td->cur_depth does not accurately represent
+        * io's that have been actually submitted to an async engine,
+        * and cur_depth is meaningless for sync engines.
+        */
+       while (td->io_u_in_flight) {
+               int fio_unused ret;
+
+               ret = io_u_queued_complete(td, 1, NULL);
+       }
+}
+
 static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir)
 {
        enum fio_ddir odir = ddir ^ 1;
@@ -522,20 +569,7 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir)
        } else
                usec = td->rate_pending_usleep[ddir];
 
-       /*
-        * We are going to sleep, ensure that we flush anything pending as
-        * not to skew our latency numbers.
-        *
-        * Changed to only monitor 'in flight' requests here instead of the
-        * td->cur_depth, b/c td->cur_depth does not accurately represent
-        * io's that have been actually submitted to an async engine,
-        * and cur_depth is meaningless for sync engines.
-        */
-       if (td->io_u_in_flight) {
-               int fio_unused ret;
-
-               ret = io_u_queued_complete(td, td->io_u_in_flight, NULL);
-       }
+       io_u_quiesce(td);
 
        fio_gettime(&t, NULL);
        usec_sleep(td, usec);
@@ -646,8 +680,7 @@ void put_io_u(struct thread_data *td, struct io_u *io_u)
 
        if (io_u->flags & IO_U_F_IN_CUR_DEPTH)
                td->cur_depth--;
-       flist_del_init(&io_u->list);
-       flist_add(&io_u->list, &td->io_u_freelist);
+       io_u_qpush(&td->io_u_freelist, io_u);
        td_io_u_unlock(td);
        td_io_u_free_notify(td);
 }
@@ -674,8 +707,8 @@ void requeue_io_u(struct thread_data *td, struct io_u **io_u)
        __io_u->flags &= ~IO_U_F_FLIGHT;
        if (__io_u->flags & IO_U_F_IN_CUR_DEPTH)
                td->cur_depth--;
-       flist_del(&__io_u->list);
-       flist_add_tail(&__io_u->list, &td->io_u_requeues);
+
+       io_u_rpush(&td->io_u_requeues, __io_u);
        td_io_u_unlock(td);
        *io_u = NULL;
 }
@@ -1077,16 +1110,17 @@ static int set_io_u_file(struct thread_data *td, struct io_u *io_u)
 
 struct io_u *__get_io_u(struct thread_data *td)
 {
-       struct io_u *io_u = NULL;
+       struct io_u *io_u;
 
        td_io_u_lock(td);
 
 again:
-       if (!flist_empty(&td->io_u_requeues))
-               io_u = flist_entry(td->io_u_requeues.next, struct io_u, list);
-       else if (!queue_full(td)) {
-               io_u = flist_entry(td->io_u_freelist.next, struct io_u, list);
+       if (!io_u_rempty(&td->io_u_requeues))
+               io_u = io_u_rpop(&td->io_u_requeues);
+       else if (!io_u_qempty(&td->io_u_freelist))
+               io_u = io_u_qpop(&td->io_u_freelist);
 
+       if (io_u) {
                io_u->buflen = 0;
                io_u->resid = 0;
                io_u->file = NULL;
@@ -1101,8 +1135,6 @@ again:
 
                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++;
                io_u->flags |= IO_U_F_IN_CUR_DEPTH;
        } else if (td->o.verify_async) {
@@ -1338,6 +1370,13 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
                tusec = utime_since(&io_u->start_time, &icd->time);
                add_lat_sample(td, idx, tusec, bytes);
 
+               if (td->flags & TD_F_PROFILE_OPS) {
+                       struct prof_io_ops *ops = &td->prof_io_ops;
+
+                       if (ops->io_u_lat)
+                               icd->error = ops->io_u_lat(td, tusec);
+               }
+
                if (td->o.max_latency && tusec > td->o.max_latency) {
                        if (!td->error)
                                log_err("fio: latency of %lu usec exceeds specified max (%u usec)\n", tusec, td->o.max_latency);
@@ -1577,14 +1616,9 @@ void io_u_queued(struct thread_data *td, struct io_u *io_u)
        }
 }
 
-/*
- * "randomly" fill the buffer contents
- */
-void io_u_fill_buffer(struct thread_data *td, struct io_u *io_u,
-                     unsigned int min_write, unsigned int max_bs)
+void fill_io_buffer(struct thread_data *td, void *buf, unsigned int min_write,
+                   unsigned int max_bs)
 {
-       io_u->buf_filled_len = 0;
-
        if (!td->o.zero_buffers) {
                unsigned int perc = td->o.compress_percentage;
 
@@ -1592,10 +1626,23 @@ void io_u_fill_buffer(struct thread_data *td, struct io_u *io_u,
                        unsigned int seg = min_write;
 
                        seg = min(min_write, td->o.compress_chunk);
-                       fill_random_buf_percentage(&td->buf_state, io_u->buf,
+                       if (!seg)
+                               seg = min_write;
+
+                       fill_random_buf_percentage(&td->buf_state, buf,
                                                perc, seg, max_bs);
                } else
-                       fill_random_buf(&td->buf_state, io_u->buf, max_bs);
+                       fill_random_buf(&td->buf_state, buf, max_bs);
        } else
-               memset(io_u->buf, 0, max_bs);
+               memset(buf, 0, max_bs);
+}
+
+/*
+ * "randomly" fill the buffer contents
+ */
+void io_u_fill_buffer(struct thread_data *td, struct io_u *io_u,
+                     unsigned int min_write, unsigned int max_bs)
+{
+       io_u->buf_filled_len = 0;
+       fill_io_buffer(td, io_u->buf, min_write, max_bs);
 }