fio: enable overlap checking with offload submission
authorVincent Fu <vincent.fu@wdc.com>
Mon, 1 Oct 2018 18:22:10 +0000 (14:22 -0400)
committerVincent Fu <vincent.fu@wdc.com>
Mon, 15 Oct 2018 19:57:23 +0000 (15:57 -0400)
Enable use of the serialize_overlap option with
io_submit_mode=offload. Threads with both of these options enabled will
check each other's in-flight IOs for overlap. If overlap is found,
submission of the new IO will be held back until the overlapping IO has
completed.

Threads must be used when fio is run in this mode because jobs need to
access each other's io_u's. io_u's are not allocated from the shared memory
area.

This fixes "fio serialize across jobs"
https://www.spinics.net/lists/fio/msg07133.html

Tested-by: Jeff Furlong <jeff.furlong@wdc.com>
backend.c
fio.h
ioengines.c
rate-submit.c

index 76e456f..cc3c4e7 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -29,6 +29,7 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <math.h>
+#include <pthread.h>
 
 #include "fio.h"
 #include "smalloc.h"
@@ -65,6 +66,7 @@ unsigned int stat_number = 0;
 int shm_id = 0;
 int temp_stall_ts;
 unsigned long done_secs = 0;
+pthread_mutex_t overlap_check = PTHREAD_MUTEX_INITIALIZER;
 
 #define JOB_START_TIMEOUT      (5 * 1000)
 
@@ -567,7 +569,7 @@ static int unlink_all_files(struct thread_data *td)
 /*
  * Check if io_u will overlap an in-flight IO in the queue
  */
-static bool in_flight_overlap(struct io_u_queue *q, struct io_u *io_u)
+bool in_flight_overlap(struct io_u_queue *q, struct io_u *io_u)
 {
        bool overlap;
        struct io_u *check_io_u;
@@ -1872,7 +1874,11 @@ static void *thread_main(void *data)
                         "perhaps try --debug=io option for details?\n",
                         td->o.name, td->io_ops->name);
 
+       if (td->o.serialize_overlap && td->o.io_submit_mode == IO_MODE_OFFLOAD)
+               pthread_mutex_lock(&overlap_check);
        td_set_runstate(td, TD_FINISHING);
+       if (td->o.serialize_overlap && td->o.io_submit_mode == IO_MODE_OFFLOAD)
+               pthread_mutex_unlock(&overlap_check);
 
        update_rusage_stat(td);
        td->ts.total_run_time = mtime_since_now(&td->epoch);
diff --git a/fio.h b/fio.h
index 53bcda1..e394e16 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -852,4 +852,7 @@ enum {
 extern void exec_trigger(const char *);
 extern void check_trigger_file(void);
 
+extern bool in_flight_overlap(struct io_u_queue *q, struct io_u *io_u);
+extern pthread_mutex_t overlap_check;
+
 #endif
index ba02952..47f606a 100644 (file)
@@ -288,6 +288,8 @@ enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u)
 
        assert((io_u->flags & IO_U_F_FLIGHT) == 0);
        io_u_set(td, io_u, IO_U_F_FLIGHT);
+       if (td->o.serialize_overlap && td->o.io_submit_mode == IO_MODE_OFFLOAD)
+               pthread_mutex_unlock(&overlap_check);
 
        assert(fio_file_open(io_u->file));
 
index 2f02fe2..8ecd285 100644 (file)
@@ -9,6 +9,36 @@
 #include "lib/getrusage.h"
 #include "rate-submit.h"
 
+static void check_overlap(struct io_u *io_u)
+{
+       int i;
+       struct thread_data *td;
+       bool overlap = false;
+
+       do {
+               /*
+                * Allow only one thread to check for overlap at a
+                * time to prevent two threads from thinking the coast
+                * is clear and then submitting IOs that overlap with
+                * each other
+                */
+               pthread_mutex_lock(&overlap_check);
+               for_each_td(td, i) {
+                       if (td->runstate <= TD_SETTING_UP ||
+                               td->runstate >= TD_FINISHING ||
+                               !td->o.serialize_overlap ||
+                               td->o.io_submit_mode != IO_MODE_OFFLOAD)
+                               continue;
+
+                       overlap = in_flight_overlap(&td->io_u_all, io_u);
+                       if (overlap) {
+                               pthread_mutex_unlock(&overlap_check);
+                               break;
+                       }
+               }
+       } while (overlap);
+}
+
 static int io_workqueue_fn(struct submit_worker *sw,
                           struct workqueue_work *work)
 {
@@ -17,6 +47,9 @@ static int io_workqueue_fn(struct submit_worker *sw,
        struct thread_data *td = sw->priv;
        int ret;
 
+       if (td->o.serialize_overlap)
+               check_overlap(io_u);
+
        dprint(FD_RATE, "io_u %p queued by %u\n", io_u, gettid());
 
        io_u_set(td, io_u, IO_U_F_NO_FILE_PUT);