Merge branch 'master' of git://github.com/cvubrugier/fio
[fio.git] / iolog.c
diff --git a/iolog.c b/iolog.c
index ec29971f6a51dfd2d67dc3e00f0c90a76264c7fc..cac1aba21e8bb5b2b53a4e957ebebfd0a13eaf1a 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -10,6 +10,7 @@
 #include "fio.h"
 #include "verify.h"
 #include "trim.h"
+#include "filelock.h"
 
 static const char iolog_ver2[] = "fio version 2 iolog";
 
@@ -57,6 +58,7 @@ void log_file(struct thread_data *td, struct fio_file *f,
 static void iolog_delay(struct thread_data *td, unsigned long delay)
 {
        unsigned long usec = utime_since_now(&td->last_issue);
+       unsigned long this_delay;
 
        if (delay < usec)
                return;
@@ -69,7 +71,14 @@ static void iolog_delay(struct thread_data *td, unsigned long delay)
        if (delay < 100)
                return;
 
-       usec_sleep(td, delay);
+       while (delay && !td->terminate) {
+               this_delay = delay;
+               if (this_delay > 500000)
+                       this_delay = 500000;
+
+               usec_sleep(td, this_delay);
+               delay -= this_delay;
+       }
 }
 
 static int ipo_special(struct thread_data *td, struct io_piece *ipo)
@@ -189,6 +198,9 @@ void log_io_piece(struct thread_data *td, struct io_u *io_u)
        ipo->offset = io_u->offset;
        ipo->len = io_u->buflen;
        ipo->numberio = io_u->numberio;
+       ipo->flags = IP_F_IN_FLIGHT;
+
+       io_u->ipo = ipo;
 
        if (io_u_should_trim(td, io_u)) {
                flist_add_tail(&ipo->trim_list, &td->trim_list);
@@ -209,7 +221,7 @@ void log_io_piece(struct thread_data *td, struct io_u *io_u)
         * drop the old one, which we rely on the rb insert/lookup for
         * handling.
         */
-       if ((!td_random(td) || !td->o.overwrite) &&
+       if (((!td->o.verifysort) || !td_random(td) || !td->o.overwrite) &&
              (file_randommap(td, ipo->file) || td->o.verify == VERIFY_NONE)) {
                INIT_FLIST_HEAD(&ipo->list);
                flist_add_tail(&ipo->list, &td->io_hist_list);
@@ -256,6 +268,33 @@ restart:
        td->io_hist_len++;
 }
 
+void unlog_io_piece(struct thread_data *td, struct io_u *io_u)
+{
+       struct io_piece *ipo = io_u->ipo;
+
+       if (!ipo)
+               return;
+
+       if (ipo->flags & IP_F_ONRB)
+               rb_erase(&ipo->rb_node, &td->io_hist_tree);
+       else if (ipo->flags & IP_F_ONLIST)
+               flist_del(&ipo->list);
+
+       free(ipo);
+       io_u->ipo = NULL;
+       td->io_hist_len--;
+}
+
+void trim_io_piece(struct thread_data *td, struct io_u *io_u)
+{
+       struct io_piece *ipo = io_u->ipo;
+
+       if (!ipo)
+               return;
+
+       ipo->len = io_u->xfer_buflen - io_u->resid;
+}
+
 void write_iolog_close(struct thread_data *td)
 {
        fflush(td->iolog_f);
@@ -320,8 +359,7 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                } else if (r == 2) {
                        rw = DDIR_INVAL;
                        if (!strcmp(act, "add")) {
-                               td->o.nr_files++;
-                               fileno = add_file(td, fname);
+                               fileno = add_file(td, fname, 0, 1);
                                file_action = FIO_LOG_ADD_FILE;
                                continue;
                        } else if (!strcmp(act, "open")) {
@@ -368,7 +406,7 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                } else {
                        ipo->offset = offset;
                        ipo->len = bytes;
-                       if (bytes > td->o.max_bs[rw])
+                       if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw])
                                td->o.max_bs[rw] = bytes;
                        ipo->fileno = fileno;
                        ipo->file_action = file_action;
@@ -513,9 +551,36 @@ void setup_log(struct io_log **log, unsigned long avg_msec, int log_type)
        *log = l;
 }
 
+#ifdef CONFIG_SETVBUF
+static void *set_file_buffer(FILE *f)
+{
+       size_t size = 1048576;
+       void *buf;
+
+       buf = malloc(size);
+       setvbuf(f, buf, _IOFBF, size);
+       return buf;
+}
+
+static void clear_file_buffer(void *buf)
+{
+       free(buf);
+}
+#else
+static void *set_file_buffer(FILE *f)
+{
+       return NULL;
+}
+
+static void clear_file_buffer(void *buf)
+{
+}
+#endif
+
 void __finish_log(struct io_log *log, const char *name)
 {
        unsigned int i;
+       void *buf;
        FILE *f;
 
        f = fopen(name, "a");
@@ -524,6 +589,8 @@ void __finish_log(struct io_log *log, const char *name)
                return;
        }
 
+       buf = set_file_buffer(f);
+
        for (i = 0; i < log->nr_samples; i++) {
                fprintf(f, "%lu, %lu, %u, %u\n",
                                (unsigned long) log->log[i].time,
@@ -532,27 +599,160 @@ void __finish_log(struct io_log *log, const char *name)
        }
 
        fclose(f);
+       clear_file_buffer(buf);
        free(log->log);
        free(log);
 }
 
-void finish_log_named(struct thread_data *td, struct io_log *log,
-                      const char *prefix, const char *postfix)
+static int finish_log_named(struct thread_data *td, struct io_log *log,
+                           const char *prefix, const char *postfix,
+                           int trylock)
 {
-       char file_name[256], *p;
+       char file_name[256];
 
        snprintf(file_name, sizeof(file_name), "%s_%s.log", prefix, postfix);
-       p = basename(file_name);
+
+       if (trylock) {
+               if (fio_trylock_file(file_name))
+                       return 1;
+       } else
+               fio_lock_file(file_name);
 
        if (td->client_type == FIO_CLIENT_TYPE_GUI) {
-               fio_send_iolog(td, log, p);
+               fio_send_iolog(td, log, file_name);
                free(log->log);
                free(log);
        } else
-               __finish_log(log, p);
+               __finish_log(log, file_name);
+
+       fio_unlock_file(file_name);
+       return 0;
 }
 
-void finish_log(struct thread_data *td, struct io_log *log, const char *name)
+static int finish_log(struct thread_data *td, struct io_log *log,
+                     const char *name, int trylock)
 {
-       finish_log_named(td, log, td->o.name, name);
+       return finish_log_named(td, log, td->o.name, name, trylock);
+}
+
+static int write_this_log(struct thread_data *td, struct io_log *log,
+                         const char *log_file, const char *name, int try)
+{
+       int ret;
+
+       if (!log)
+               return 0;
+
+       if (log_file)
+               ret = finish_log_named(td, log, log_file, name, try);
+       else
+               ret = finish_log(td, log, name, try);
+
+       return ret;
+}
+
+static int write_iops_log(struct thread_data *td, int try)
+{
+       struct thread_options *o = &td->o;
+
+       return write_this_log(td, td->iops_log, o->iops_log_file, "iops", try);
+}
+
+static int write_slat_log(struct thread_data *td, int try)
+{
+       struct thread_options *o = &td->o;
+
+       return write_this_log(td, td->slat_log, o->lat_log_file, "slat", try);
+}
+
+static int write_clat_log(struct thread_data *td, int try)
+{
+       struct thread_options *o = &td->o;
+
+       return write_this_log(td, td->clat_log, o->lat_log_file, "clat" , try);
+}
+
+static int write_lat_log(struct thread_data *td, int try)
+{
+       struct thread_options *o = &td->o;
+
+       return write_this_log(td, td->lat_log, o->lat_log_file, "lat", try);
+}
+
+static int write_bandw_log(struct thread_data *td, int try)
+{
+       struct thread_options *o = &td->o;
+
+       return write_this_log(td, td->bw_log, o->bw_log_file, "bw", try);
+}
+
+enum {
+       BW_LOG_MASK     = 1,
+       LAT_LOG_MASK    = 2,
+       SLAT_LOG_MASK   = 4,
+       CLAT_LOG_MASK   = 8,
+       IOPS_LOG_MASK   = 16,
+
+       ALL_LOG_NR      = 5,
+};
+
+struct log_type {
+       unsigned int mask;
+       int (*fn)(struct thread_data *, int);
+};
+
+static struct log_type log_types[] = {
+       {
+               .mask   = BW_LOG_MASK,
+               .fn     = write_bandw_log,
+       },
+       {
+               .mask   = LAT_LOG_MASK,
+               .fn     = write_lat_log,
+       },
+       {
+               .mask   = SLAT_LOG_MASK,
+               .fn     = write_slat_log,
+       },
+       {
+               .mask   = CLAT_LOG_MASK,
+               .fn     = write_clat_log,
+       },
+       {
+               .mask   = IOPS_LOG_MASK,
+               .fn     = write_iops_log,
+       },
+};
+
+void fio_writeout_logs(struct thread_data *td)
+{
+       unsigned int log_mask = 0;
+       unsigned int log_left = ALL_LOG_NR;
+       int old_state, i;
+
+       old_state = td_bump_runstate(td, TD_FINISHING);
+
+       finalize_logs(td);
+
+       while (log_left) {
+               int prev_log_left = log_left;
+
+               for (i = 0; i < ALL_LOG_NR && log_left; i++) {
+                       struct log_type *lt = &log_types[i];
+                       int ret;
+
+                       if (!(log_mask & lt->mask)) {
+                               ret = lt->fn(td, log_left != 1);
+                               if (!ret) {
+                                       log_left--;
+                                       log_mask |= lt->mask;
+                               }
+                       }
+               }
+
+               if (prev_log_left == log_left)
+                       usleep(5000);
+       }
+
+       td_restore_runstate(td, old_state);
 }