Branch and cache miss speedups
[fio.git] / filesetup.c
index d67f1124618744db85595c2f037ffe07f9788794..2744d4fce0f9597166a3a749445c530594ff33b7 100644 (file)
@@ -11,6 +11,7 @@
 #include "fio.h"
 #include "smalloc.h"
 #include "filehash.h"
+#include "options.h"
 #include "os/os.h"
 #include "hash.h"
 #include "lib/axmap.h"
@@ -21,6 +22,8 @@
 
 static int root_warn;
 
+static FLIST_HEAD(filename_list);
+
 static inline void clear_error(struct thread_data *td)
 {
        td->error = 0;
@@ -734,9 +737,11 @@ int setup_files(struct thread_data *td)
        unsigned long long total_size, extend_size;
        struct thread_options *o = &td->o;
        struct fio_file *f;
-       unsigned int i;
+       unsigned int i, nr_fs_extra = 0;
        int err = 0, need_extend;
        int old_state;
+       const unsigned int bs = td_min_bs(td);
+       uint64_t fs = 0;
 
        dprint(FD_FILE, "setup files\n");
 
@@ -785,6 +790,20 @@ int setup_files(struct thread_data *td)
                goto err_out;
        }
 
+       /*
+        * Calculate per-file size and potential extra size for the
+        * first files, if needed.
+        */
+       if (!o->file_size_low) {
+               uint64_t all_fs;
+
+               fs = o->size / o->nr_files;
+               all_fs = fs * o->nr_files;
+
+               if (all_fs < o->size)
+                       nr_fs_extra = (o->size - all_fs) / bs;
+       }
+
        /*
         * now file sizes are known, so we can set ->io_size. if size= is
         * not given, ->io_size is just equal to ->real_file_size. if size
@@ -798,10 +817,17 @@ int setup_files(struct thread_data *td)
                if (!o->file_size_low) {
                        /*
                         * no file size range given, file size is equal to
-                        * total size divided by number of files. if that is
-                        * zero, set it to the real file size.
+                        * total size divided by number of files. If that is
+                        * zero, set it to the real file size. If the size
+                        * doesn't divide nicely with the min blocksize,
+                        * make the first files bigger.
                         */
-                       f->io_size = o->size / o->nr_files;
+                       f->io_size = fs;
+                       if (nr_fs_extra) {
+                               nr_fs_extra--;
+                               f->io_size += bs;
+                       }
+
                        if (!f->io_size)
                                f->io_size = f->real_file_size - f->file_offset;
                } else if (f->real_file_size < o->file_size_low ||
@@ -984,7 +1010,7 @@ int init_random_map(struct thread_data *td)
 
                        seed = td->rand_seeds[FIO_RAND_BLOCK_OFF];
                        
-                       if (!lfsr_init(&f->lfsr, blocks, seed, seed & 0xF))
+                       if (!lfsr_init(&f->lfsr, blocks, seed, 0))
                                continue;
                } else if (!td->o.norandommap) {
                        f->io_axmap = axmap_new(blocks);
@@ -1078,7 +1104,48 @@ static void get_file_type(struct fio_file *f)
        }
 }
 
-int add_file(struct thread_data *td, const char *fname)
+static void set_already_allocated(const char *fname) {
+       struct file_name *fn;
+
+       fn = malloc(sizeof(struct file_name));
+       fn->filename = strdup(fname);
+       flist_add_tail(&fn->list, &filename_list);
+}
+
+static int is_already_allocated(const char *fname)
+{
+       struct flist_head *entry;
+       char *filename;
+
+       if (!flist_empty(&filename_list))
+       {
+               flist_for_each(entry, &filename_list) {
+                       filename = flist_entry(entry, struct file_name, list)->filename;
+
+                       if (strcmp(filename, fname) == 0)
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void free_already_allocated() {
+       struct flist_head *entry, *tmp;
+       struct file_name *fn;
+
+       if (!flist_empty(&filename_list))
+       {
+               flist_for_each_safe(entry, tmp, &filename_list) {
+                       fn = flist_entry(entry, struct file_name, list);
+                       free(fn->filename);
+                       flist_del(&fn->list);
+                       free(fn);
+               }
+       }
+}
+
+int add_file(struct thread_data *td, const char *fname, int numjob, int inc)
 {
        int cur_files = td->files_index;
        char file_name[PATH_MAX];
@@ -1087,6 +1154,15 @@ int add_file(struct thread_data *td, const char *fname)
 
        dprint(FD_FILE, "add file %s\n", fname);
 
+       if (td->o.directory)
+               len = set_name_idx(file_name, td->o.directory, numjob);
+
+       sprintf(file_name + len, "%s", fname);
+
+       /* clean cloned siblings using existing files */
+       if (numjob && is_already_allocated(file_name))
+               return 0;
+
        f = smalloc(sizeof(*f));
        if (!f) {
                log_err("fio: smalloc OOM\n");
@@ -1126,10 +1202,6 @@ int add_file(struct thread_data *td, const char *fname)
        if (td->io_ops && (td->io_ops->flags & FIO_DISKLESSIO))
                f->real_file_size = -1ULL;
 
-       if (td->o.directory)
-               len = sprintf(file_name, "%s/", td->o.directory);
-
-       sprintf(file_name + len, "%s", fname);
        f->file_name = smalloc_strdup(file_name);
        if (!f->file_name) {
                log_err("fio: smalloc OOM\n");
@@ -1156,6 +1228,18 @@ int add_file(struct thread_data *td, const char *fname)
        if (f->filetype == FIO_TYPE_FILE)
                td->nr_normal_files++;
 
+       set_already_allocated(file_name);
+
+       /*
+        * For adding files after the fact - if openfiles= isn't
+        * given as an option, ensure we allow at least one file open
+        */
+       if (!td->o.open_files)
+               td->o.open_files = 1;
+
+       if (inc)
+               td->o.nr_files++;
+
        dprint(FD_FILE, "file %p \"%s\" added at %d\n", f, f->file_name,
                                                        cur_files);
 
@@ -1172,7 +1256,7 @@ int add_file_exclusive(struct thread_data *td, const char *fname)
                        return i;
        }
 
-       return add_file(td, fname);
+       return add_file(td, fname, 0, 1);
 }
 
 void get_file(struct fio_file *f)
@@ -1243,7 +1327,7 @@ void unlock_file(struct thread_data *td, struct fio_file *f)
 
 void unlock_file_all(struct thread_data *td, struct fio_file *f)
 {
-       if (td->o.file_lock_mode == FILE_LOCK_NONE)
+       if (td->o.file_lock_mode == FILE_LOCK_NONE || !td->file_locks)
                return;
        if (td->file_locks[f->fileno] != FILE_LOCK_NONE)
                unlock_file(td, f);
@@ -1281,8 +1365,7 @@ static int recurse_dir(struct thread_data *td, const char *dirname)
                }
 
                if (S_ISREG(sb.st_mode)) {
-                       add_file(td, full_path);
-                       td->o.nr_files++;
+                       add_file(td, full_path, 0, 1);
                        continue;
                }
                if (!S_ISDIR(sb.st_mode))
@@ -1343,6 +1426,11 @@ void dup_files(struct thread_data *td, struct thread_data *org)
                        __f->filetype = f->filetype;
                }
 
+               if (td->o.file_lock_mode == FILE_LOCK_EXCLUSIVE)
+                       __f->lock = f->lock;
+               else if (td->o.file_lock_mode == FILE_LOCK_READWRITE)
+                       __f->rwlock = f->rwlock;
+
                td->files[i] = __f;
        }
 }
@@ -1381,3 +1469,20 @@ void fio_file_reset(struct thread_data *td, struct fio_file *f)
        if (td->o.random_generator == FIO_RAND_GEN_LFSR)
                lfsr_reset(&f->lfsr, td->rand_seeds[FIO_RAND_BLOCK_OFF]);
 }
+
+int fio_files_done(struct thread_data *td)
+{
+       struct fio_file *f;
+       unsigned int i;
+
+       for_each_file(td, f, i)
+               if (!fio_file_done(f))
+                       return 0;
+
+       return 1;
+}
+
+/* free memory used in initialization phase only */
+void filesetup_mem_free() {
+       free_already_allocated();
+}