Add support for waiting for other jobs by name
[fio.git] / backend.c
index 4a689eb0d6859fb89c9cbb22a7d390a2fd4a5fed..edc0644a113b259cf2d65cf91f96175a5f50201b 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -54,9 +54,9 @@
 #include "lib/getrusage.h"
 #include "idletime.h"
 #include "err.h"
-#include "lib/tp.h"
 #include "workqueue.h"
 #include "lib/mountcheck.h"
+#include "rate-submit.h"
 
 static pthread_t helper_thread;
 static pthread_mutex_t helper_lock;
@@ -808,12 +808,15 @@ static long long usec_for_io(struct thread_data *td, enum fio_ddir ddir)
  *
  * Returns number of bytes written and trimmed.
  */
-static uint64_t do_io(struct thread_data *td)
+static void do_io(struct thread_data *td, uint64_t *bytes_done)
 {
        unsigned int i;
        int ret = 0;
        uint64_t total_bytes, bytes_issued = 0;
 
+       for (i = 0; i < DDIR_RWDIR_CNT; i++)
+               bytes_done[i] = td->bytes_done[i];
+
        if (in_ramp_time(td))
                td_set_runstate(td, TD_RAMP);
        else
@@ -928,9 +931,20 @@ static uint64_t do_io(struct thread_data *td)
                        log_io_piece(td, io_u);
 
                if (td->o.io_submit_mode == IO_MODE_OFFLOAD) {
+                       const unsigned long blen = io_u->xfer_buflen;
+                       const enum fio_ddir ddir = acct_ddir(io_u);
+
                        if (td->error)
                                break;
-                       ret = workqueue_enqueue(&td->io_wq, io_u);
+
+                       workqueue_enqueue(&td->io_wq, &io_u->work);
+                       ret = FIO_Q_QUEUED;
+
+                       if (ddir_rw(ddir)) {
+                               td->io_issues[ddir]++;
+                               td->io_issue_bytes[ddir] += blen;
+                               td->rate_io_issue_bytes[ddir] += blen;
+                       }
 
                        if (should_check_rate(td))
                                td->rate_next_io_time[ddir] = usec_for_io(td, ddir);
@@ -963,7 +977,7 @@ reap:
 
                if (!in_ramp_time(td) && should_check_rate(td)) {
                        if (check_min_rate(td, &comp_time)) {
-                               if (exitall_on_terminate)
+                               if (exitall_on_terminate || td->o.exitall_error)
                                        fio_terminate_threads(td->groupid);
                                td_verror(td, EIO, "check_min_rate");
                                break;
@@ -1035,7 +1049,8 @@ reap:
        if (!ddir_rw_sum(td->this_io_bytes))
                td->done = 1;
 
-       return td->bytes_done[DDIR_WRITE] + td->bytes_done[DDIR_TRIM];
+       for (i = 0; i < DDIR_RWDIR_CNT; i++)
+               bytes_done[i] = td->bytes_done[i] - bytes_done[i];
 }
 
 static void cleanup_io_u(struct thread_data *td)
@@ -1347,28 +1362,10 @@ static uint64_t do_dry_run(struct thread_data *td)
        return td->bytes_done[DDIR_WRITE] + td->bytes_done[DDIR_TRIM];
 }
 
-static void io_workqueue_fn(struct thread_data *td, struct io_u *io_u)
-{
-       const enum fio_ddir ddir = io_u->ddir;
-       int ret;
-
-       dprint(FD_RATE, "io_u %p queued by %u\n", io_u, gettid());
-
-       io_u_set(io_u, IO_U_F_NO_FILE_PUT);
-
-       td->cur_depth++;
-
-       ret = td_io_queue(td, io_u);
-
-       dprint(FD_RATE, "io_u %p ret %d by %u\n", io_u, ret, gettid());
-
-       io_queue_event(td, io_u, &ret, ddir, NULL, 0, NULL);
-
-       if (ret == FIO_Q_QUEUED)
-               ret = io_u_queued_complete(td, 1);
-
-       td->cur_depth--;
-}
+struct fork_data {
+       struct thread_data *td;
+       struct sk_out *sk_out;
+};
 
 /*
  * Entry point for the thread based jobs. The process based jobs end up
@@ -1376,13 +1373,18 @@ static void io_workqueue_fn(struct thread_data *td, struct io_u *io_u)
  */
 static void *thread_main(void *data)
 {
+       struct fork_data *fd = data;
        unsigned long long elapsed_us[DDIR_RWDIR_CNT] = { 0, };
-       struct thread_data *td = data;
+       struct thread_data *td = fd->td;
        struct thread_options *o = &td->o;
+       struct sk_out *sk_out = fd->sk_out;
        pthread_condattr_t attr;
        int clear_state;
        int ret;
 
+       sk_out_assign(sk_out);
+       free(fd);
+
        if (!o->use_thread) {
                setsid();
                td->pid = getpid();
@@ -1562,13 +1564,12 @@ static void *thread_main(void *data)
                        goto err;
        }
 
-       if (td->flags & TD_F_COMPRESS_LOG)
-               tp_init(&td->tp_data);
+       if (iolog_compress_init(td, sk_out))
+               goto err;
 
        fio_verify_init(td);
 
-       if ((o->io_submit_mode == IO_MODE_OFFLOAD) &&
-           workqueue_init(td, &td->io_wq, io_workqueue_fn, td->o.iodepth))
+       if (rate_submit_init(td, sk_out))
                goto err;
 
        fio_gettime(&td->epoch, NULL);
@@ -1600,8 +1601,19 @@ static void *thread_main(void *data)
 
                if (td->o.verify_only && (td_write(td) || td_rw(td)))
                        verify_bytes = do_dry_run(td);
-               else
-                       verify_bytes = do_io(td);
+               else {
+                       uint64_t bytes_done[DDIR_RWDIR_CNT];
+
+                       do_io(td, bytes_done);
+
+                       if (!ddir_rw_sum(bytes_done)) {
+                               fio_mark_td_terminate(td);
+                               verify_bytes = 0;
+                       } else {
+                               verify_bytes = bytes_done[DDIR_WRITE] +
+                                               bytes_done[DDIR_TRIM];
+                       }
+               }
 
                clear_state = 1;
 
@@ -1666,16 +1678,13 @@ static void *thread_main(void *data)
 
        fio_writeout_logs(td);
 
-       if (o->io_submit_mode == IO_MODE_OFFLOAD)
-               workqueue_exit(&td->io_wq);
-
-       if (td->flags & TD_F_COMPRESS_LOG)
-               tp_exit(&td->tp_data);
+       iolog_compress_exit(td);
+       rate_submit_exit(td);
 
        if (o->exec_postrun)
                exec_string(o, o->exec_postrun, (const char *)"postrun");
 
-       if (exitall_on_terminate)
+       if (exitall_on_terminate || (o->exitall_error && td->error))
                fio_terminate_threads(td->groupid);
 
 err:
@@ -1715,6 +1724,7 @@ err:
         */
        check_update_rusage(td);
 
+       sk_out_drop();
        return (void *) (uintptr_t) td->error;
 }
 
@@ -1723,9 +1733,9 @@ err:
  * We cannot pass the td data into a forked process, so attach the td and
  * pass it to the thread worker.
  */
-static int fork_main(int shmid, int offset)
+static int fork_main(struct sk_out *sk_out, int shmid, int offset)
 {
-       struct thread_data *td;
+       struct fork_data *fd;
        void *data, *ret;
 
 #if !defined(__hpux) && !defined(CONFIG_NO_SHM)
@@ -1743,8 +1753,10 @@ static int fork_main(int shmid, int offset)
        data = threads;
 #endif
 
-       td = data + offset * sizeof(struct thread_data);
-       ret = thread_main(td);
+       fd = calloc(1, sizeof(*fd));
+       fd->td = data + offset * sizeof(struct thread_data);
+       fd->sk_out = sk_out;
+       ret = thread_main(fd);
        shmdt(data);
        return (int) (uintptr_t) ret;
 }
@@ -1966,10 +1978,36 @@ mounted:
        return true;
 }
 
+static bool waitee_running(struct thread_data *me)
+{
+       const char *waitee = me->o.wait_for;
+       const char *self = me->o.name;
+       struct thread_data *td;
+       int i;
+
+       if (!waitee)
+               return false;
+
+       for_each_td(td, i) {
+               if (!strcmp(td->o.name, self) || strcmp(td->o.name, waitee))
+                       continue;
+
+               if (td->runstate < TD_EXITED) {
+                       dprint(FD_PROCESS, "%s fenced by %s(%s)\n",
+                                       self, td->o.name,
+                                       runstate_to_name(td->runstate));
+                       return true;
+               }
+       }
+
+       dprint(FD_PROCESS, "%s: %s completed, can run\n", self, waitee);
+       return false;
+}
+
 /*
  * Main function for kicking off and reaping jobs, as needed.
  */
-static void run_threads(void)
+static void run_threads(struct sk_out *sk_out)
 {
        struct thread_data *td;
        unsigned int i, todo, nr_running, m_rate, t_rate, nr_started;
@@ -2089,6 +2127,12 @@ reap:
                                break;
                        }
 
+                       if (waitee_running(td)) {
+                               dprint(FD_PROCESS, "%s: waiting for %s\n",
+                                               td->o.name, td->o.wait_for);
+                               break;
+                       }
+
                        init_disk_util(td);
 
                        td->rusage_sem = fio_mutex_init(FIO_MUTEX_LOCKED);
@@ -2103,14 +2147,20 @@ reap:
                        nr_started++;
 
                        if (td->o.use_thread) {
+                               struct fork_data *fd;
                                int ret;
 
+                               fd = calloc(1, sizeof(*fd));
+                               fd->td = td;
+                               fd->sk_out = sk_out;
+
                                dprint(FD_PROCESS, "will pthread_create\n");
                                ret = pthread_create(&td->thread, NULL,
-                                                       thread_main, td);
+                                                       thread_main, fd);
                                if (ret) {
                                        log_err("pthread_create: %s\n",
                                                        strerror(ret));
+                                       free(fd);
                                        nr_started--;
                                        break;
                                }
@@ -2123,14 +2173,14 @@ reap:
                                dprint(FD_PROCESS, "will fork\n");
                                pid = fork();
                                if (!pid) {
-                                       int ret = fork_main(shm_id, i);
+                                       int ret = fork_main(sk_out, shm_id, i);
 
                                        _exit(ret);
                                } else if (i == fio_debug_jobno)
                                        *fio_debug_jobp = pid;
                        }
                        dprint(FD_MUTEX, "wait on startup_mutex\n");
-                       if (fio_mutex_down_timeout(startup_mutex, 10)) {
+                       if (fio_mutex_down_timeout(startup_mutex, 10000)) {
                                log_err("fio: job startup hung? exiting.\n");
                                fio_terminate_threads(TERMINATE_ALL);
                                fio_abort = 1;
@@ -2233,8 +2283,11 @@ static void free_disk_util(void)
 
 static void *helper_thread_main(void *data)
 {
+       struct sk_out *sk_out = data;
        int ret = 0;
 
+       sk_out_assign(sk_out);
+
        fio_mutex_up(startup_mutex);
 
        while (!ret) {
@@ -2265,10 +2318,11 @@ static void *helper_thread_main(void *data)
                        print_thread_status();
        }
 
+       sk_out_drop();
        return NULL;
 }
 
-static int create_helper_thread(void)
+static int create_helper_thread(struct sk_out *sk_out)
 {
        int ret;
 
@@ -2277,7 +2331,7 @@ static int create_helper_thread(void)
        pthread_cond_init(&helper_cond, NULL);
        pthread_mutex_init(&helper_lock, NULL);
 
-       ret = pthread_create(&helper_thread, NULL, helper_thread_main, NULL);
+       ret = pthread_create(&helper_thread, NULL, helper_thread_main, sk_out);
        if (ret) {
                log_err("Can't create helper thread: %s\n", strerror(ret));
                return 1;
@@ -2289,7 +2343,7 @@ static int create_helper_thread(void)
        return 0;
 }
 
-int fio_backend(void)
+int fio_backend(struct sk_out *sk_out)
 {
        struct thread_data *td;
        int i;
@@ -2319,12 +2373,12 @@ int fio_backend(void)
 
        set_genesis_time();
        stat_init();
-       create_helper_thread();
+       create_helper_thread(sk_out);
 
        cgroup_list = smalloc(sizeof(*cgroup_list));
        INIT_FLIST_HEAD(cgroup_list);
 
-       run_threads();
+       run_threads(sk_out);
 
        wait_for_helper_thread_exit();