Merge branch 'master' into gfio
[fio.git] / backend.c
index 9cc8dbc3ce1e029b4729e23e150428e4217b60e4..6f40038799831a4f521af7ac25942b660e56978b 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -57,13 +57,13 @@ static struct flist_head *cgroup_list;
 static char *cgroup_mnt;
 static int exit_value;
 static volatile int fio_abort;
+static unsigned int nr_process = 0;
+static unsigned int nr_thread = 0;
 
-struct io_log *agg_io_log[2];
+struct io_log *agg_io_log[DDIR_RWDIR_CNT];
 
 int groupid = 0;
 unsigned int thread_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;
@@ -208,10 +208,12 @@ static int check_min_rate(struct thread_data *td, struct timeval *now,
 {
        int ret = 0;
 
-       if (bytes_done[0])
-               ret |= __check_min_rate(td, now, 0);
-       if (bytes_done[1])
-               ret |= __check_min_rate(td, now, 1);
+       if (bytes_done[DDIR_READ])
+               ret |= __check_min_rate(td, now, DDIR_READ);
+       if (bytes_done[DDIR_WRITE])
+               ret |= __check_min_rate(td, now, DDIR_WRITE);
+       if (bytes_done[DDIR_TRIM])
+               ret |= __check_min_rate(td, now, DDIR_TRIM);
 
        return ret;
 }
@@ -335,17 +337,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.
@@ -545,11 +547,13 @@ static int io_bytes_exceeded(struct thread_data *td)
        unsigned long long bytes;
 
        if (td_rw(td))
-               bytes = td->this_io_bytes[0] + td->this_io_bytes[1];
+               bytes = td->this_io_bytes[DDIR_READ] + td->this_io_bytes[DDIR_WRITE];
        else if (td_write(td))
-               bytes = td->this_io_bytes[1];
+               bytes = td->this_io_bytes[DDIR_WRITE];
+       else if (td_read(td))
+               bytes = td->this_io_bytes[DDIR_READ];
        else
-               bytes = td->this_io_bytes[0];
+               bytes = td->this_io_bytes[DDIR_TRIM];
 
        return bytes >= td->o.size;
 }
@@ -572,7 +576,7 @@ 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[2] = { 0, 0 };
+               unsigned long bytes_done[DDIR_RWDIR_CNT] = { 0, 0, 0 };
                int min_evts = 0;
                struct io_u *io_u;
                int ret2, full;
@@ -649,8 +653,9 @@ static void do_io(struct thread_data *td)
                                requeue_io_u(td, &io_u);
                        } else {
 sync_done:
-                               if (__should_check_rate(td, 0) ||
-                                   __should_check_rate(td, 1))
+                               if (__should_check_rate(td, DDIR_READ) ||
+                                   __should_check_rate(td, DDIR_WRITE) ||
+                                   __should_check_rate(td, DDIR_TRIM))
                                        fio_gettime(&comp_time, NULL);
 
                                ret = io_u_sync_complete(td, io_u, bytes_done);
@@ -697,8 +702,9 @@ sync_done:
                        if (full && !min_evts)
                                min_evts = 1;
 
-                       if (__should_check_rate(td, 0) ||
-                           __should_check_rate(td, 1))
+                       if (__should_check_rate(td, DDIR_READ) ||
+                           __should_check_rate(td, DDIR_WRITE) ||
+                           __should_check_rate(td, DDIR_TRIM))
                                fio_gettime(&comp_time, NULL);
 
                        do {
@@ -711,7 +717,7 @@ sync_done:
 
                if (ret < 0)
                        break;
-               if (!(bytes_done[0] + bytes_done[1]))
+               if (!ddir_rw_sum(bytes_done))
                        continue;
 
                if (!in_ramp_time(td) && should_check_rate(td, bytes_done)) {
@@ -726,7 +732,7 @@ sync_done:
                if (td->o.thinktime) {
                        unsigned long long b;
 
-                       b = td->io_blocks[0] + td->io_blocks[1];
+                       b = ddir_rw_sum(td->io_blocks);
                        if (!(b % td->o.thinktime_blocks)) {
                                int left;
 
@@ -772,7 +778,7 @@ sync_done:
        /*
         * stop job if we failed doing any IO
         */
-       if ((td->this_io_bytes[0] + td->this_io_bytes[1]) == 0)
+       if (!ddir_rw_sum(td->this_io_bytes))
                td->done = 1;
 }
 
@@ -796,14 +802,19 @@ 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);
        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_rw(td))
+               data_xfer = 0;
+
        if (td->o.mem_type == MEM_SHMHUGE || td->o.mem_type == MEM_MMAPHUGE) {
                unsigned long bs;
 
@@ -816,7 +827,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 ||
@@ -844,7 +855,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);
 
@@ -926,8 +937,6 @@ static int switch_ioscheduler(struct thread_data *td)
 
 static int keep_running(struct thread_data *td)
 {
-       unsigned long long io_done;
-
        if (td->done)
                return 0;
        if (td->o.time_based)
@@ -937,9 +946,7 @@ static int keep_running(struct thread_data *td)
                return 1;
        }
 
-       io_done = td->io_bytes[DDIR_READ] + td->io_bytes[DDIR_WRITE]
-                       + td->io_skip_bytes;
-       if (io_done < td->o.size)
+       if (ddir_rw_sum(td->io_bytes) < td->o.size)
                return 1;
 
        return 0;
@@ -969,10 +976,12 @@ static void *thread_main(void *data)
 {
        unsigned long long elapsed;
        struct thread_data *td = data;
+       struct thread_options *o = &td->o;
        pthread_condattr_t attr;
        int clear_state;
+       int ret;
 
-       if (!td->o.use_thread) {
+       if (!o->use_thread) {
                setsid();
                td->pid = getpid();
        } else
@@ -980,6 +989,9 @@ static void *thread_main(void *data)
 
        dprint(FD_PROCESS, "jobs pid=%d started\n", (int) td->pid);
 
+       if (is_backend)
+               fio_server_send_start(td);
+
        INIT_FLIST_HEAD(&td->io_u_freelist);
        INIT_FLIST_HEAD(&td->io_u_busylist);
        INIT_FLIST_HEAD(&td->io_u_requeues);
@@ -1006,16 +1018,17 @@ static void *thread_main(void *data)
         * eating a file descriptor
         */
        fio_mutex_remove(td->mutex);
+       td->mutex = NULL;
 
        /*
         * A new gid requires privilege, so we need to do this before setting
         * the uid.
         */
-       if (td->o.gid != -1U && setgid(td->o.gid)) {
+       if (o->gid != -1U && setgid(o->gid)) {
                td_verror(td, errno, "setgid");
                goto err;
        }
-       if (td->o.uid != -1U && setuid(td->o.uid)) {
+       if (o->uid != -1U && setuid(o->uid)) {
                td_verror(td, errno, "setuid");
                goto err;
        }
@@ -1024,18 +1037,24 @@ static void *thread_main(void *data)
         * If we have a gettimeofday() thread, make sure we exclude that
         * thread from this job
         */
-       if (td->o.gtod_cpu)
-               fio_cpu_clear(&td->o.cpumask, td->o.gtod_cpu);
+       if (o->gtod_cpu)
+               fio_cpu_clear(&o->cpumask, o->gtod_cpu);
 
        /*
         * Set affinity first, in case it has an impact on the memory
         * allocations.
         */
-       if (td->o.cpumask_set && fio_setaffinity(td->pid, td->o.cpumask) == -1) {
-               td_verror(td, errno, "cpu_set_affinity");
-               goto err;
+       if (o->cpumask_set) {
+               ret = fio_setaffinity(td->pid, o->cpumask);
+               if (ret == -1) {
+                       td_verror(td, errno, "cpu_set_affinity");
+                       goto err;
+               }
        }
 
+       if (fio_pin_memory(td))
+               goto err;
+
        /*
         * May alter parameters that init_io_u() will use, so we need to
         * do this first.
@@ -1046,11 +1065,12 @@ static void *thread_main(void *data)
        if (init_io_u(td))
                goto err;
 
-       if (td->o.verify_async && verify_async_init(td))
+       if (o->verify_async && verify_async_init(td))
                goto err;
 
-       if (td->ioprio_set) {
-               if (ioprio_set(IOPRIO_WHO_PROCESS, 0, td->ioprio) == -1) {
+       if (o->ioprio) {
+               ret = ioprio_set(IOPRIO_WHO_PROCESS, 0, o->ioprio_class, o->ioprio);
+               if (ret == -1) {
                        td_verror(td, errno, "ioprio_set");
                        goto err;
                }
@@ -1060,15 +1080,15 @@ static void *thread_main(void *data)
                goto err;
 
        errno = 0;
-       if (nice(td->o.nice) == -1 && errno != 0) {
+       if (nice(o->nice) == -1 && errno != 0) {
                td_verror(td, errno, "nice");
                goto err;
        }
 
-       if (td->o.ioscheduler && switch_ioscheduler(td))
+       if (o->ioscheduler && switch_ioscheduler(td))
                goto err;
 
-       if (!td->o.create_serialize && setup_files(td))
+       if (!o->create_serialize && setup_files(td))
                goto err;
 
        if (td_io_init(td))
@@ -1077,16 +1097,16 @@ static void *thread_main(void *data)
        if (init_random_map(td))
                goto err;
 
-       if (td->o.exec_prerun) {
-               if (exec_string(td->o.exec_prerun))
-                       goto err;
-       }
+       if (o->exec_prerun && exec_string(o->exec_prerun))
+               goto err;
 
-       if (td->o.pre_read) {
+       if (o->pre_read) {
                if (pre_read_files(td) < 0)
                        goto err;
        }
 
+       fio_verify_init(td);
+
        fio_gettime(&td->epoch, NULL);
        getrusage(RUSAGE_SELF, &td->ru_start);
 
@@ -1097,10 +1117,13 @@ static void *thread_main(void *data)
                memcpy(&td->iops_sample_time, &td->start, sizeof(td->start));
                memcpy(&td->tv_cache, &td->start, sizeof(td->start));
 
-               if (td->o.ratemin[0] || td->o.ratemin[1]) {
-                       memcpy(&td->lastrate[0], &td->bw_sample_time,
+               if (td->o.ratemin[DDIR_READ] || td->o.ratemin[DDIR_WRITE] ||
+                               td->o.ratemin[DDIR_TRIM]) {
+                       memcpy(&td->lastrate[DDIR_READ], &td->bw_sample_time,
                                                sizeof(td->bw_sample_time));
-                       memcpy(&td->lastrate[1], &td->bw_sample_time,
+                       memcpy(&td->lastrate[DDIR_WRITE], &td->bw_sample_time,
+                                               sizeof(td->bw_sample_time));
+                       memcpy(&td->lastrate[DDIR_TRIM], &td->bw_sample_time,
                                                sizeof(td->bw_sample_time));
                }
 
@@ -1121,6 +1144,10 @@ static void *thread_main(void *data)
                        elapsed = utime_since_now(&td->start);
                        td->ts.runtime[DDIR_WRITE] += elapsed;
                }
+               if (td_trim(td) && td->io_bytes[DDIR_TRIM]) {
+                       elapsed = utime_since_now(&td->start);
+                       td->ts.runtime[DDIR_TRIM] += elapsed;
+               }
 
                if (td->error || td->terminate)
                        break;
@@ -1143,11 +1170,15 @@ static void *thread_main(void *data)
        }
 
        update_rusage_stat(td);
-       td->ts.runtime[0] = (td->ts.runtime[0] + 999) / 1000;
-       td->ts.runtime[1] = (td->ts.runtime[1] + 999) / 1000;
+       td->ts.runtime[DDIR_READ] = (td->ts.runtime[DDIR_READ] + 999) / 1000;
+       td->ts.runtime[DDIR_WRITE] = (td->ts.runtime[DDIR_WRITE] + 999) / 1000;
+       td->ts.runtime[DDIR_TRIM] = (td->ts.runtime[DDIR_TRIM] + 999) / 1000;
        td->ts.total_run_time = mtime_since_now(&td->epoch);
-       td->ts.io_bytes[0] = td->io_bytes[0];
-       td->ts.io_bytes[1] = td->io_bytes[1];
+       td->ts.io_bytes[DDIR_READ] = td->io_bytes[DDIR_READ];
+       td->ts.io_bytes[DDIR_WRITE] = td->io_bytes[DDIR_WRITE];
+       td->ts.io_bytes[DDIR_TRIM] = td->io_bytes[DDIR_TRIM];
+
+       fio_unpin_memory(td);
 
        fio_mutex_down(writeout_mutex);
        if (td->bw_log) {
@@ -1206,8 +1237,8 @@ err:
        cleanup_io_u(td);
        cgroup_shutdown(td, &cgroup_mnt);
 
-       if (td->o.cpumask_set) {
-               int ret = fio_cpuset_exit(&td->o.cpumask);
+       if (o->cpumask_set) {
+               int ret = fio_cpuset_exit(&o->cpumask);
 
                td_verror(td, ret, "fio_cpuset_exit");
        }
@@ -1337,8 +1368,8 @@ static void reap_threads(unsigned int *nr_running, unsigned int *t_rate,
                continue;
 reaped:
                (*nr_running)--;
-               (*m_rate) -= (td->o.ratemin[0] + td->o.ratemin[1]);
-               (*t_rate) -= (td->o.rate[0] + td->o.rate[1]);
+               (*m_rate) -= ddir_rw_sum(td->o.ratemin);
+               (*t_rate) -= ddir_rw_sum(td->o.rate);
                if (!td->pid)
                        pending--;
 
@@ -1361,15 +1392,20 @@ static void run_threads(void)
        unsigned long spent;
        unsigned int i, todo, nr_running, m_rate, t_rate, nr_started;
 
-       if (fio_pin_memory())
-               return;
-
        if (fio_gtod_offload && fio_start_gtod_thread())
                return;
 
        set_sig_handlers();
 
-       if (!terse_output) {
+       nr_thread = nr_process = 0;
+       for_each_td(td, i) {
+               if (td->o.use_thread)
+                       nr_thread++;
+               else
+                       nr_process++;
+       }
+
+       if (output_format == FIO_OUTPUT_NORMAL) {
                log_info("Starting ");
                if (nr_thread)
                        log_info("%d thread%s", nr_thread,
@@ -1560,33 +1596,24 @@ static void run_threads(void)
                                td_set_runstate(td, TD_RUNNING);
                        nr_running++;
                        nr_started--;
-                       m_rate += td->o.ratemin[0] + td->o.ratemin[1];
-                       t_rate += td->o.rate[0] + td->o.rate[1];
+                       m_rate += ddir_rw_sum(td->o.ratemin);
+                       t_rate += ddir_rw_sum(td->o.rate);
                        todo--;
                        fio_mutex_up(td->mutex);
                }
 
                reap_threads(&nr_running, &t_rate, &m_rate);
 
-               if (todo) {
-                       if (is_backend)
-                               fio_server_idle_loop();
-                       else
-                               usleep(100000);
-               }
+               if (todo)
+                       usleep(100000);
        }
 
        while (nr_running) {
                reap_threads(&nr_running, &t_rate, &m_rate);
-
-               if (is_backend)
-                       fio_server_idle_loop();
-               else
-                       usleep(10000);
+               usleep(10000);
        }
 
        update_io_ticks();
-       fio_unpin_memory();
 }
 
 void wait_for_disk_thread_exit(void)
@@ -1620,7 +1647,7 @@ static int create_disk_util_thread(void)
 
        setup_disk_util();
 
-       disk_thread_mutex = fio_mutex_init(0);
+       disk_thread_mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
 
        ret = pthread_create(&disk_util_thread, NULL, disk_thread_main, NULL);
        if (ret) {
@@ -1657,14 +1684,15 @@ int fio_backend(void)
                return 0;
 
        if (write_bw_log) {
-               setup_log(&agg_io_log[DDIR_READ], 0);
-               setup_log(&agg_io_log[DDIR_WRITE], 0);
+               setup_log(&agg_io_log[DDIR_READ], 0, IO_LOG_TYPE_BW);
+               setup_log(&agg_io_log[DDIR_WRITE], 0, IO_LOG_TYPE_BW);
+               setup_log(&agg_io_log[DDIR_TRIM], 0, IO_LOG_TYPE_BW);
        }
 
-       startup_mutex = fio_mutex_init(0);
+       startup_mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
        if (startup_mutex == NULL)
                return 1;
-       writeout_mutex = fio_mutex_init(1);
+       writeout_mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED);
        if (writeout_mutex == NULL)
                return 1;
 
@@ -1682,6 +1710,8 @@ int fio_backend(void)
                        __finish_log(agg_io_log[DDIR_READ], "agg-read_bw.log");
                        __finish_log(agg_io_log[DDIR_WRITE],
                                        "agg-write_bw.log");
+                       __finish_log(agg_io_log[DDIR_TRIM],
+                                       "agg-write_bw.log");
                }
        }