Consider the maximum block size difference the minimum for loop exit
[fio.git] / backend.c
index 9b0d7918337c0b0c645e1911c33ad396319df0f3..ae4216db26c69b8fc23d1494a9f648965b882948 100644 (file)
--- a/backend.c
+++ b/backend.c
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/ipc.h>
-#include <sys/shm.h>
 #include <sys/mman.h>
 
 #include "fio.h"
+#ifndef FIO_NO_HAVE_SHM_H
+#include <sys/shm.h>
+#endif
 #include "hash.h"
 #include "smalloc.h"
 #include "verify.h"
@@ -48,6 +50,8 @@
 #include "lib/rand.h"
 #include "memalign.h"
 #include "server.h"
+#include "lib/getrusage.h"
+#include "idletime.h"
 
 static pthread_t disk_util_thread;
 static struct fio_mutex *disk_thread_mutex;
@@ -62,11 +66,13 @@ struct io_log *agg_io_log[DDIR_RWDIR_CNT];
 
 int groupid = 0;
 unsigned int thread_number = 0;
+unsigned int stat_number = 0;
 unsigned int nr_process = 0;
 unsigned int nr_thread = 0;
 int shm_id = 0;
 int temp_stall_ts;
 unsigned long done_secs = 0;
+volatile int disk_util_exit = 0;
 
 #define PAGE_ALIGN(buf)        \
        (char *) (((uintptr_t) (buf) + page_mask) & ~page_mask)
@@ -107,6 +113,14 @@ static void set_sig_handlers(void)
        act.sa_flags = SA_RESTART;
        sigaction(SIGTERM, &act, NULL);
 
+/* Windows uses SIGBREAK as a quit signal from other applications */
+#ifdef WIN32
+       memset(&act, 0, sizeof(act));
+       act.sa_handler = sig_int;
+       act.sa_flags = SA_RESTART;
+       sigaction(SIGBREAK, &act, NULL);
+#endif
+
        memset(&act, 0, sizeof(act));
        act.sa_handler = sig_show_status;
        act.sa_flags = SA_RESTART;
@@ -204,7 +218,7 @@ static int __check_min_rate(struct thread_data *td, struct timeval *now,
 }
 
 static int check_min_rate(struct thread_data *td, struct timeval *now,
-                         unsigned long *bytes_done)
+                         uint64_t *bytes_done)
 {
        int ret = 0;
 
@@ -308,6 +322,21 @@ requeue:
        return 0;
 }
 
+static int fio_file_fsync(struct thread_data *td, struct fio_file *f)
+{
+       int ret;
+
+       if (fio_file_open(f))
+               return fio_io_sync(td, f);
+
+       if (td_io_open_file(td, f))
+               return 1;
+
+       ret = fio_io_sync(td, f);
+       td_io_close_file(td, f);
+       return ret;
+}
+
 static inline void __update_tv_cache(struct thread_data *td)
 {
        fio_gettime(&td->tv_cache, NULL);
@@ -337,17 +366,17 @@ static int break_on_this_error(struct thread_data *td, enum fio_ddir ddir,
        int ret = *retptr;
 
        if (ret < 0 || td->error) {
-               int err;
+               int err = td->error;
+               enum error_type_bit eb;
 
                if (ret < 0)
                        err = -ret;
-               else
-                       err = td->error;
 
-               if (!(td->o.continue_on_error & td_error_type(ddir, err)))
+               eb = td_error_type(ddir, err);
+               if (!(td->o.continue_on_error & (1 << eb)))
                        return 1;
 
-               if (td_non_fatal_error(err)) {
+               if (td_non_fatal_error(td, eb, err)) {
                        /*
                         * Continue with the I/Os in case of
                         * a non fatal error.
@@ -381,8 +410,9 @@ static int break_on_this_error(struct thread_data *td, enum fio_ddir ddir,
  * The main verify engine. Runs over the writes we previously submitted,
  * reads the blocks back in, and checks the crc/md5 of the data.
  */
-static void do_verify(struct thread_data *td)
+static void do_verify(struct thread_data *td, uint64_t verify_bytes)
 {
+       uint64_t bytes_done[DDIR_RWDIR_CNT] = { 0, 0, 0 };
        struct fio_file *f;
        struct io_u *io_u;
        int ret, min_events;
@@ -410,6 +440,7 @@ static void do_verify(struct thread_data *td)
 
        io_u = NULL;
        while (!td->terminate) {
+               enum fio_ddir ddir;
                int ret2, full;
 
                update_tv_cache(td);
@@ -425,18 +456,53 @@ static void do_verify(struct thread_data *td)
                if (flow_threshold_exceeded(td))
                        continue;
 
-               io_u = __get_io_u(td);
-               if (!io_u)
-                       break;
+               if (!td->o.experimental_verify) {
+                       io_u = __get_io_u(td);
+                       if (!io_u)
+                               break;
 
-               if (get_next_verify(td, io_u)) {
-                       put_io_u(td, io_u);
-                       break;
-               }
+                       if (get_next_verify(td, io_u)) {
+                               put_io_u(td, io_u);
+                               break;
+                       }
 
-               if (td_io_prep(td, io_u)) {
-                       put_io_u(td, io_u);
-                       break;
+                       if (td_io_prep(td, io_u)) {
+                               put_io_u(td, io_u);
+                               break;
+                       }
+               } else {
+                       if (ddir_rw_sum(bytes_done) + td->o.rw_min_bs > verify_bytes)
+                               break;
+
+                       while ((io_u = get_io_u(td)) != NULL) {
+                               /*
+                                * We are only interested in the places where
+                                * we wrote or trimmed IOs. Turn those into
+                                * reads for verification purposes.
+                                */
+                               if (io_u->ddir == DDIR_READ) {
+                                       /*
+                                        * Pretend we issued it for rwmix
+                                        * accounting
+                                        */
+                                       td->io_issues[DDIR_READ]++;
+                                       put_io_u(td, io_u);
+                                       continue;
+                               } else if (io_u->ddir == DDIR_TRIM) {
+                                       io_u->ddir = DDIR_READ;
+                                       io_u->flags |= IO_U_F_TRIMMED;
+                                       break;
+                               } else if (io_u->ddir == DDIR_WRITE) {
+                                       io_u->ddir = DDIR_READ;
+                                       break;
+                               } else {
+                                       put_io_u(td, io_u);
+                                       continue;
+                               }
+                       }
+
+                       if (!io_u)
+                               break;
                }
 
                if (td->o.verify_async)
@@ -444,6 +510,8 @@ static void do_verify(struct thread_data *td)
                else
                        io_u->end_io = verify_io_u;
 
+               ddir = io_u->ddir;
+
                ret = td_io_queue(td, io_u);
                switch (ret) {
                case FIO_Q_COMPLETED:
@@ -476,7 +544,7 @@ static void do_verify(struct thread_data *td)
                                requeue_io_u(td, &io_u);
                        } else {
 sync_done:
-                               ret = io_u_sync_complete(td, io_u, NULL);
+                               ret = io_u_sync_complete(td, io_u, bytes_done);
                                if (ret < 0)
                                        break;
                        }
@@ -495,7 +563,7 @@ sync_done:
                        break;
                }
 
-               if (break_on_this_error(td, io_u->ddir, &ret))
+               if (break_on_this_error(td, ddir, &ret))
                        break;
 
                /*
@@ -519,7 +587,7 @@ sync_done:
                                 * and do the verification on them through
                                 * the callback handler
                                 */
-                               if (io_u_queued_complete(td, min_events, NULL) < 0) {
+                               if (io_u_queued_complete(td, min_events, bytes_done) < 0) {
                                        ret = -1;
                                        break;
                                }
@@ -561,9 +629,12 @@ static int io_bytes_exceeded(struct thread_data *td)
 /*
  * Main IO worker function. It retrieves io_u's to process and queues
  * and reaps them, checking for rate and errors along the way.
+ *
+ * Returns number of bytes written and trimmed.
  */
-static void do_io(struct thread_data *td)
+static uint64_t do_io(struct thread_data *td)
 {
+       uint64_t bytes_done[DDIR_RWDIR_CNT] = { 0, 0, 0 };
        unsigned int i;
        int ret = 0;
 
@@ -576,13 +647,12 @@ static void do_io(struct thread_data *td)
                (!flist_empty(&td->trim_list)) || !io_bytes_exceeded(td) ||
                td->o.time_based) {
                struct timeval comp_time;
-               unsigned long bytes_done[DDIR_RWDIR_CNT] = { 0, 0, 0 };
                int min_evts = 0;
                struct io_u *io_u;
                int ret2, full;
                enum fio_ddir ddir;
 
-               if (td->terminate)
+               if (td->terminate || td->done)
                        break;
 
                update_tv_cache(td);
@@ -717,7 +787,7 @@ sync_done:
 
                if (ret < 0)
                        break;
-               if (!ddir_rw_sum(bytes_done))
+               if (!ddir_rw_sum(bytes_done) && !(td->io_ops->flags & FIO_NOIO))
                        continue;
 
                if (!in_ramp_time(td) && should_check_rate(td, bytes_done)) {
@@ -758,7 +828,7 @@ sync_done:
 
                i = td->cur_depth;
                if (i) {
-                       ret = io_u_queued_complete(td, i, NULL);
+                       ret = io_u_queued_complete(td, i, bytes_done);
                        if (td->o.fill_device && td->error == ENOSPC)
                                td->error = 0;
                }
@@ -767,9 +837,11 @@ sync_done:
                        td_set_runstate(td, TD_FSYNCING);
 
                        for_each_file(td, f, i) {
-                               if (!fio_file_open(f))
+                               if (!fio_file_fsync(td, f))
                                        continue;
-                               fio_io_sync(td, f);
+
+                               log_err("fio: end_fsync failed for file %s\n",
+                                                               f->file_name);
                        }
                }
        } else
@@ -780,6 +852,8 @@ sync_done:
         */
        if (!ddir_rw_sum(td->this_io_bytes))
                td->done = 1;
+
+       return bytes_done[DDIR_WRITE] + bytes_done[DDIR_TRIM];
 }
 
 static void cleanup_io_u(struct thread_data *td)
@@ -791,6 +865,10 @@ static void cleanup_io_u(struct thread_data *td)
                io_u = flist_entry(entry, struct io_u, list);
 
                flist_del(&io_u->list);
+
+               if (td->io_ops->io_u_free)
+                       td->io_ops->io_u_free(td, io_u);
+
                fio_memfree(io_u, sizeof(*io_u));
        }
 
@@ -802,15 +880,18 @@ static int init_io_u(struct thread_data *td)
        struct io_u *io_u;
        unsigned int max_bs, min_write;
        int cl_align, i, max_units;
+       int data_xfer = 1;
        char *p;
 
        max_units = td->o.iodepth;
-       max_bs = max(td->o.max_bs[DDIR_READ], td->o.max_bs[DDIR_WRITE]);
-       max_bs = max(td->o.max_bs[DDIR_TRIM], max_bs);
+       max_bs = td_max_bs(td);
        min_write = td->o.min_bs[DDIR_WRITE];
        td->orig_buffer_size = (unsigned long long) max_bs
                                        * (unsigned long long) max_units;
 
+       if ((td->io_ops->flags & FIO_NOIO) || !(td_read(td) || td_write(td)))
+               data_xfer = 0;
+
        if (td->o.mem_type == MEM_SHMHUGE || td->o.mem_type == MEM_MMAPHUGE) {
                unsigned long bs;
 
@@ -823,7 +904,7 @@ static int init_io_u(struct thread_data *td)
                return 1;
        }
 
-       if (allocate_io_mem(td))
+       if (data_xfer && allocate_io_mem(td))
                return 1;
 
        if (td->o.odirect || td->o.mem_align ||
@@ -851,7 +932,7 @@ static int init_io_u(struct thread_data *td)
                INIT_FLIST_HEAD(&io_u->list);
                dprint(FD_MEM, "io_u alloc %p, index %u\n", io_u, i);
 
-               if (!(td->io_ops->flags & FIO_NOIO)) {
+               if (data_xfer) {
                        io_u->buf = p;
                        dprint(FD_MEM, "io_u %p, mem %p\n", io_u, io_u->buf);
 
@@ -869,6 +950,16 @@ static int init_io_u(struct thread_data *td)
                io_u->index = i;
                io_u->flags = IO_U_F_FREE;
                flist_add(&io_u->list, &td->io_u_freelist);
+
+               if (td->io_ops->io_u_init) {
+                       int ret = td->io_ops->io_u_init(td, io_u);
+
+                       if (ret) {
+                               log_err("fio: failed to init engine data: %d\n", ret);
+                               return 1;
+                       }
+               }
+
                p += max_bs;
        }
 
@@ -942,8 +1033,19 @@ static int keep_running(struct thread_data *td)
                return 1;
        }
 
-       if (ddir_rw_sum(td->io_bytes) < td->o.size)
+       if (td->o.size != -1ULL && ddir_rw_sum(td->io_bytes) < td->o.size) {
+               uint64_t diff;
+
+               /*
+                * If the difference is less than the minimum IO size, we
+                * are done.
+                */
+               diff = td->o.size - ddir_rw_sum(td->io_bytes);
+               if (diff < td_max_bs(td))
+                       return 0;
+
                return 1;
+       }
 
        return 0;
 }
@@ -981,6 +1083,8 @@ static void *thread_main(void *data)
        } else
                td->pid = gettid();
 
+       fio_local_clock_init(td->o.use_thread);
+
        dprint(FD_PROCESS, "jobs pid=%d started\n", (int) td->pid);
 
        INIT_FLIST_HEAD(&td->io_u_freelist);
@@ -990,6 +1094,7 @@ static void *thread_main(void *data)
        INIT_FLIST_HEAD(&td->io_hist_list);
        INIT_FLIST_HEAD(&td->verify_list);
        INIT_FLIST_HEAD(&td->trim_list);
+       INIT_FLIST_HEAD(&td->next_rand_list);
        pthread_mutex_init(&td->io_u_lock, NULL);
        td->io_hist_tree = RB_ROOT;
 
@@ -1039,6 +1144,49 @@ static void *thread_main(void *data)
                goto err;
        }
 
+#ifdef CONFIG_LIBNUMA
+       /* numa node setup */
+       if (td->o.numa_cpumask_set || td->o.numa_memmask_set) {
+               int ret;
+
+               if (numa_available() < 0) {
+                       td_verror(td, errno, "Does not support NUMA API\n");
+                       goto err;
+               }
+
+               if (td->o.numa_cpumask_set) {
+                       ret = numa_run_on_node_mask(td->o.numa_cpunodesmask);
+                       if (ret == -1) {
+                               td_verror(td, errno, \
+                                       "numa_run_on_node_mask failed\n");
+                               goto err;
+                       }
+               }
+
+               if (td->o.numa_memmask_set) {
+
+                       switch (td->o.numa_mem_mode) {
+                       case MPOL_INTERLEAVE:
+                               numa_set_interleave_mask(td->o.numa_memnodesmask);
+                               break;
+                       case MPOL_BIND:
+                               numa_set_membind(td->o.numa_memnodesmask);
+                               break;
+                       case MPOL_LOCAL:
+                               numa_set_localalloc();
+                               break;
+                       case MPOL_PREFERRED:
+                               numa_set_preferred(td->o.numa_mem_prefer_node);
+                               break;
+                       case MPOL_DEFAULT:
+                       default:
+                               break;
+                       }
+
+               }
+       }
+#endif
+
        /*
         * May alter parameters that init_io_u() will use, so we need to
         * do this first.
@@ -1091,10 +1239,11 @@ static void *thread_main(void *data)
        }
 
        fio_gettime(&td->epoch, NULL);
-       getrusage(RUSAGE_SELF, &td->ru_start);
-
+       fio_getrusage(&td->ru_start);
        clear_state = 0;
        while (keep_running(td)) {
+               uint64_t verify_bytes;
+
                fio_gettime(&td->start, NULL);
                memcpy(&td->bw_sample_time, &td->start, sizeof(td->start));
                memcpy(&td->iops_sample_time, &td->start, sizeof(td->start));
@@ -1115,7 +1264,7 @@ static void *thread_main(void *data)
 
                prune_io_piece_log(td);
 
-               do_io(td);
+               verify_bytes = do_io(td);
 
                clear_state = 1;
 
@@ -1144,7 +1293,7 @@ static void *thread_main(void *data)
 
                fio_gettime(&td->start, NULL);
 
-               do_verify(td);
+               do_verify(td, verify_bytes);
 
                td->ts.runtime[DDIR_READ] += utime_since_now(&td->start);
 
@@ -1214,8 +1363,8 @@ err:
                verify_async_exit(td);
 
        close_and_free_files(td);
-       close_ioengine(td);
        cleanup_io_u(td);
+       close_ioengine(td);
        cgroup_shutdown(td, &cgroup_mnt);
 
        if (td->o.cpumask_set) {
@@ -1326,7 +1475,7 @@ static void reap_threads(unsigned int *nr_running, unsigned int *t_rate,
                        if (WIFSIGNALED(status)) {
                                int sig = WTERMSIG(status);
 
-                               if (sig != SIGTERM)
+                               if (sig != SIGTERM && sig != SIGUSR2)
                                        log_err("fio: pid=%d, got signal=%d\n",
                                                        (int) td->pid, sig);
                                td->sig = sig;
@@ -1378,10 +1527,12 @@ static void run_threads(void)
 
        if (fio_gtod_offload && fio_start_gtod_thread())
                return;
+       
+       fio_idle_prof_init();
 
        set_sig_handlers();
 
-       if (!terse_output) {
+       if (output_format == FIO_OUTPUT_NORMAL) {
                log_info("Starting ");
                if (nr_thread)
                        log_info("%d thread%s", nr_thread,
@@ -1435,6 +1586,9 @@ static void run_threads(void)
                }
        }
 
+       /* start idle threads before io threads start to run */
+       fio_idle_prof_start();
+
        set_genesis_time();
 
        while (todo) {
@@ -1597,6 +1751,8 @@ static void run_threads(void)
                        usleep(10000);
        }
 
+       fio_idle_prof_stop();
+
        update_io_ticks();
        fio_unpin_memory();
 }
@@ -1606,6 +1762,13 @@ void wait_for_disk_thread_exit(void)
        fio_mutex_down(disk_thread_mutex);
 }
 
+static void free_disk_util(void)
+{
+       disk_util_start_exit();
+       wait_for_disk_thread_exit();
+       disk_util_prune_entries();
+}
+
 static void *disk_thread_main(void *data)
 {
        int ret = 0;