Improve random pattern without norandommap
[fio.git] / io_u.c
diff --git a/io_u.c b/io_u.c
index d5dd84b96ddf9b00fa89134551fc323bce923eb3..c824d7ecce4ef8246c9304c5f4a7ef77fa458a0d 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -84,7 +84,7 @@ static int get_next_free_block(struct thread_data *td, struct fio_file *f,
        *b = (i * BLOCKS_PER_MAP);
        while ((*b) * td->o.rw_min_bs < f->real_file_size) {
                if (f->file_map[i] != -1UL) {
-                       *b += ffz(f->file_map[i]);
+                       *b += fio_ffz(f->file_map[i]);
                        f->last_free_lookup = i;
                        return 0;
                }
@@ -109,20 +109,40 @@ static int get_next_rand_offset(struct thread_data *td, struct fio_file *f,
                        *b = 0;
                else
                        *b = ((max_blocks - 1) * r / (unsigned long long) (RAND_MAX+1.0));
+               /*
+                * if we are not maintaining a random map, we are done.
+                */
                if (td->o.norandommap)
-                       break;
+                       return 0;
+
+               /*
+                * calculate map offset and chec if it's free
+                */
                rb = *b + (f->file_offset / td->o.min_bs[ddir]);
-               loops--;
-       } while (!random_map_free(td, f, rb) && loops);
+               if (random_map_free(td, f, rb))
+                       return 0;
+
+       } while (--loops);
 
        /*
-        * if we failed to retrieve a truly random offset within
-        * the loops assigned, see if there are free ones left at all
+        * we get here, if we didn't suceed in looking up a block. generate
+        * a random start offset into the filemap, and find the first free
+        * block from there.
         */
-       if (!loops && get_next_free_block(td, f, b))
-               return 1;
+       loops = 10;
+       do {
+               f->last_free_lookup = (f->num_maps - 1) * (r / (RAND_MAX+1.0));
+               if (!get_next_free_block(td, f, b))
+                       return 0;
 
-       return 0;
+               r = os_random_long(&td->random_state);
+       } while (--loops);
+
+       /*
+        * that didn't work either, try exhaustive search from the start
+        */
+       f->last_free_lookup = 0;
+       return get_next_free_block(td, f, b);
 }
 
 /*
@@ -265,6 +285,9 @@ void put_io_u(struct thread_data *td, struct io_u *io_u)
        assert((io_u->flags & IO_U_F_FREE) == 0);
        io_u->flags |= IO_U_F_FREE;
 
+       if (io_u->file)
+               put_file(td, io_u->file);
+
        io_u->file = NULL;
        list_del(&io_u->list);
        list_add(&io_u->list, &td->io_u_freelist);
@@ -289,7 +312,7 @@ static int fill_io_u(struct thread_data *td, struct io_u *io_u)
        /*
         * If using an iolog, grab next piece if any available.
         */
-       if (td->o.read_iolog)
+       if (td->o.read_iolog_file)
                return read_iolog_get(td, io_u);
 
        /*
@@ -540,12 +563,14 @@ struct io_u *get_io_u(struct thread_data *td)
 
 set_file:
                io_u->file = f;
+               get_file(f);
 
                if (!fill_io_u(td, io_u))
                        break;
 
                /*
-                * No more to do for this file, close it
+                * td_io_close() does a put_file() as well, so no need to
+                * do that here.
                 */
                io_u->file = NULL;
                td_io_close_file(td, f);
@@ -627,8 +652,6 @@ static void io_completed(struct thread_data *td, struct io_u *io_u,
        assert(io_u->flags & IO_U_F_FLIGHT);
        io_u->flags &= ~IO_U_F_FLIGHT;
 
-       put_file(td, io_u->file);
-
        if (io_u->ddir == DDIR_SYNC) {
                td->last_was_sync = 1;
                return;