Add exit_on_io_done option to the CPU IO engine
authorJens Axboe <axboe@fb.com>
Wed, 9 Apr 2014 19:57:38 +0000 (13:57 -0600)
committerJens Axboe <axboe@fb.com>
Wed, 9 Apr 2014 19:57:38 +0000 (13:57 -0600)
The CPU IO engine is most often used to saturate the system,
while running an IO load on it. As such, it's useful to have
CPU engine threads exit automatically, when IO has completed.
Add exit_on_io_done as a CPU IO engine option for that purpose.

Signed-off-by: Jens Axboe <axboe@fb.com>
HOWTO
engines/cpu.c
fio.1
fio.h
ioengines.c
libfio.c

diff --git a/HOWTO b/HOWTO
index 7db7b8929a21a46b971bb9a45f5a774e721f96a1..f74360dee4becc4298bf7e7b8685a284550e552d 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -1505,6 +1505,8 @@ that defines them is selected.
 [cpu] cpuchunks=int Split the load into cycles of the given time. In
                microseconds.
 
+[cpu] exit_on_io_done=bool Detect when IO threads are done, then exit.
+
 [netsplice] hostname=str
 [net] hostname=str The host name or IP address to use for TCP or UDP based IO.
                If the job is a TCP listener or UDP reader, the hostname is not
index c798f1884e8dff8df9b079d87d61c8c4259ae10c..85598ef77fb9acd8d4868d6e15de1d9f64bee83f 100644 (file)
@@ -11,6 +11,7 @@ struct cpu_options {
        struct thread_data *td;
        unsigned int cpuload;
        unsigned int cpucycle;
+       unsigned int exit_io_done;
 };
 
 static struct fio_option options[] = {
@@ -35,6 +36,16 @@ static struct fio_option options[] = {
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "exit_on_io_done",
+               .lname  = "Exit when IO threads are done",
+               .type   = FIO_OPT_BOOL,
+               .off1   = offsetof(struct cpu_options, exit_io_done),
+               .help   = "Exit when IO threads finish",
+               .def    = "0",
+               .category = FIO_OPT_C_GENERAL,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = NULL,
        },
@@ -45,6 +56,11 @@ static int fio_cpuio_queue(struct thread_data *td, struct io_u fio_unused *io_u)
 {
        struct cpu_options *co = td->eo;
 
+       if (co->exit_io_done && !fio_running_or_pending_io_threads()) {
+               td->done = 1;
+               return FIO_Q_BUSY;
+       }
+
        usec_spin(co->cpucycle);
        return FIO_Q_COMPLETED;
 }
diff --git a/fio.1 b/fio.1
index 91f96e028e553a67753ec8aa9672bbd8a066b53e..8cf37780044a7ffd0f509ccae04f765cea2297d9 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -1226,14 +1226,6 @@ Output is redirected in a file called \fBjobname.postrun.txt\fR
 .BI ioscheduler \fR=\fPstr
 Attempt to switch the device hosting the file to the specified I/O scheduler.
 .TP
-.BI cpuload \fR=\fPint
-If the job is a CPU cycle-eater, attempt to use the specified percentage of
-CPU cycles.
-.TP
-.BI cpuchunks \fR=\fPint
-If the job is a CPU cycle-eater, split the load into cycles of the
-given time in milliseconds.
-.TP
 .BI disk_util \fR=\fPbool
 Generate disk utilization statistics if the platform supports it. Default: true.
 .TP
@@ -1375,6 +1367,9 @@ Attempt to use the specified percentage of CPU cycles.
 .BI (cpu)cpuchunks \fR=\fPint
 Split the load into cycles of the given time. In microseconds.
 .TP
+.BI (cpu)exit_on_io_done \fR=\fPbool
+Detect when IO threads are done, then exit.
+.TP
 .BI (libaio)userspace_reap
 Normally, with the libaio engine in use, fio will use
 the io_getevents system call to reap newly returned events.
diff --git a/fio.h b/fio.h
index a539f21bee39961a53f297185f3e01fe2df2ee5c..3df5bd9fa53de0dc72839d598a869e2d0a976eba 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -72,6 +72,7 @@ enum {
        TD_F_VER_NONE           = 32,
        TD_F_PROFILE_OPS        = 64,
        TD_F_COMPRESS           = 128,
+       TD_F_NOIO               = 256,
 };
 
 enum {
@@ -439,6 +440,7 @@ extern void add_job_opts(const char **, int);
 extern char *num2str(unsigned long, int, int, int, int);
 extern int ioengine_load(struct thread_data *);
 extern int parse_dryrun(void);
+extern int fio_running_or_pending_io_threads(void);
 
 extern uintptr_t page_mask;
 extern uintptr_t page_size;
index 3c75fa6bfed6812e9027e832ff0d26505034b7d9..0f94d0d9513da64337bbb23284ebb09001b2ebd9 100644 (file)
@@ -375,6 +375,9 @@ int td_io_init(struct thread_data *td)
                        td->error = ret;
        }
 
+       if (!ret && (td->io_ops->flags & FIO_NOIO))
+               td->flags |= TD_F_NOIO;
+
        return ret;
 }
 
index 1fd77e40770065f6c6dfcc0b8c7e80600f188b2e..3fde492c91af727f6d96abf39c308d3ca4b657c7 100644 (file)
--- a/libfio.c
+++ b/libfio.c
@@ -218,6 +218,21 @@ void fio_terminate_threads(int group_id)
        }
 }
 
+int fio_running_or_pending_io_threads(void)
+{
+       struct thread_data *td;
+       int i;
+
+       for_each_td(td, i) {
+               if (td->flags & TD_F_NOIO)
+                       continue;
+               if (td->runstate < TD_EXITED)
+                       return 1;
+       }
+
+       return 0;
+}
+
 static int endian_check(void)
 {
        union {