Turn the CPU burner into a real io engine
authorJens Axboe <jens.axboe@oracle.com>
Fri, 9 Mar 2007 13:34:23 +0000 (14:34 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Fri, 9 Mar 2007 13:34:23 +0000 (14:34 +0100)
This removes the special casing in fio.c for the cpu engine, and
also gets rid of FIO_CPUIO.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
HOWTO
README
engines/cpu.c
fio.c
fio.h
init.c
ioengines.c
log.c

diff --git a/HOWTO b/HOWTO
index d1a3ad1..1374d05 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -301,6 +301,12 @@ ioengine=str       Defines how the job issues io to the file. The following
                                or receive, if the latter only the port
                                argument is used.
 
+                       cpu     Doesn't transfer any data, but burns CPU
+                               cycles according to the cpuload= and
+                               cpucycle= options. Setting cpuload=85
+                               will cause that job to do nothing but burn
+                               85% of the CPU.
+
                        external Prefix to specify loading an external
                                IO engine object file. Append the engine
                                filename, eg ioengine=external:/tmp/foo.o
diff --git a/README b/README
index 6980340..8b55f31 100644 (file)
--- a/README
+++ b/README
@@ -106,11 +106,11 @@ The job file parameters are:
                        posixaio for POSIX aio, sync for regular read/write io,
                        mmap for mmap'ed io, syslet-rw for syslet driven
                        read/write, splice for using splice/vmsplice,
-                       sgio for direct SG_IO io, or net for network io. sgio
-                       only works on Linux on SCSI (or SCSI-like devices,
-                       such as usb-storage or sata/libata driven) devices.
-                       Fio also has a null io engine, which is mainly used
-                       for testing fio itself.
+                       sgio for direct SG_IO io, net for network io, or cpuio
+                       for a cycler burner load. sgio only works on Linux on
+                       SCSI (or SCSI-like devices, such as usb-storage or
+                       sata/libata driven) devices. Fio also has a null io
+                       engine, which is mainly used for testing fio itself.
        iodepth=x       For async io, allow 'x' ios in flight
        overwrite=x     If 'x', layout a write file first.
        nrfiles=x       Spread io load over 'x' number of files per job,
@@ -176,7 +176,7 @@ The job file parameters are:
        ioscheduler=x   Use ioscheduler 'x' for this job.
        cpuload=x       For a CPU io thread, percentage of CPU time to attempt
                        to burn.
-       cpuchunks=x     Split burn cycles into pieces of x.
+       cpuchunks=x     Split burn cycles into pieces of x usecs.
 
 
 Author
index c89a4c9..7a084e0 100644 (file)
@@ -1,30 +1,64 @@
 #include "../fio.h"
 #include "../os.h"
 
+static int fio_cpuio_queue(struct thread_data *td, struct io_u fio_unused *io_u)
+{
+       __usec_sleep(td->cpucycle);
+       return FIO_Q_COMPLETED;
+}
+
 static int fio_cpuio_setup(struct thread_data fio_unused *td)
 {
+       struct fio_file *f;
+       int i;
+
+       td->total_file_size = -1;
+       td->io_size = td->total_file_size;
+       td->total_io_size = td->io_size;
+
+       for_each_file(td, f, i) {
+               f->real_file_size = -1;
+               f->file_size = -1;
+       }
+
        return 0;
 }
 
 static int fio_cpuio_init(struct thread_data *td)
 {
        if (!td->cpuload) {
-               td_vmsg(td, EINVAL, "cpu thread needs rate", "cpu_load");
+               td_vmsg(td, EINVAL, "cpu thread needs rate (cpuload=)","cpuio");
                return 1;
-       } else if (td->cpuload > 100)
+       }
+
+       if (td->cpuload > 100)
                td->cpuload = 100;
 
-       td->nr_files = 0;
+       /*
+        * set thinktime_sleep and thinktime_spin appropriately
+        */
+       td->thinktime_blocks = 1;
+       td->thinktime_spin = 0;
+       td->thinktime = (td->cpucycle * (100 - td->cpuload)) / td->cpuload;
 
+       td->nr_files = td->open_files = 1;
+       return 0;
+}
+
+static int fio_cpuio_open(struct thread_data fio_unused *td, struct fio_file *f)
+{
+       f->fd = 0;
        return 0;
 }
 
 static struct ioengine_ops ioengine = {
        .name           = "cpuio",
        .version        = FIO_IOOPS_VERSION,
+       .queue          = fio_cpuio_queue,
        .init           = fio_cpuio_init,
        .setup          = fio_cpuio_setup,
-       .flags          = FIO_CPUIO,
+       .open_file      = fio_cpuio_open,
+       .flags          = FIO_SYNCIO | FIO_DISKLESSIO,
 };
 
 static void fio_init fio_cpuio_register(void)
diff --git a/fio.c b/fio.c
index 6ce46ba..36dde3a 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -361,31 +361,6 @@ static void do_verify(struct thread_data *td)
        td_set_runstate(td, TD_RUNNING);
 }
 
-/*
- * Not really an io thread, all it does is burn CPU cycles in the specified
- * manner.
- */
-static void do_cpuio(struct thread_data *td)
-{
-       struct timeval e;
-       int split = 100 / td->cpuload;
-       int i = 0;
-
-       while (!td->terminate) {
-               fio_gettime(&e, NULL);
-
-               if (runtime_exceeded(td, &e))
-                       break;
-
-               if (!(i % split))
-                       __usec_sleep(10000);
-               else
-                       usec_sleep(td, 10000);
-
-               i++;
-       }
-}
-
 /*
  * Main IO worker function. It retrieves io_u's to process and queues
  * and reaps them, checking for rate and errors along the way.
@@ -566,9 +541,6 @@ static int init_io_u(struct thread_data *td)
        int i, max_units;
        char *p;
 
-       if (td->io_ops->flags & FIO_CPUIO)
-               return 0;
-
        if (td->io_ops->flags & FIO_SYNCIO)
                max_units = 1;
        else
@@ -611,7 +583,7 @@ static int switch_ioscheduler(struct thread_data *td)
        FILE *f;
        int ret;
 
-       if (td->io_ops->flags & FIO_CPUIO)
+       if (td->io_ops->flags & FIO_DISKLESSIO)
                return 0;
 
        sprintf(tmp, "%s/queue/scheduler", td->sysfs_root);
@@ -772,10 +744,7 @@ static void *thread_main(void *data)
 
                prune_io_piece_log(td);
 
-               if (td->io_ops->flags & FIO_CPUIO)
-                       do_cpuio(td);
-               else
-                       do_io(td);
+               do_io(td);
 
                clear_state = 1;
 
@@ -878,7 +847,7 @@ static void reap_threads(int *nr_running, int *t_rate, int *m_rate)
                 * ->io_ops is NULL for a thread that has closed its
                 * io engine
                 */
-               if (td->io_ops && td->io_ops->flags & FIO_CPUIO)
+               if (td->io_ops && !strcmp(td->io_ops->name, "cpuio"))
                        cputhreads++;
 
                if (!td->pid || td->runstate == TD_REAPED)
diff --git a/fio.h b/fio.h
index c20f21b..41a1790 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -212,9 +212,8 @@ enum fio_filetype {
 
 enum fio_ioengine_flags {
        FIO_SYNCIO      = 1 << 0,       /* io engine has synchronous ->queue */
-       FIO_CPUIO       = 1 << 1,       /* cpu burner, doesn't do real io */
-       FIO_RAWIO       = 1 << 2,       /* some sort of direct/raw io */
-       FIO_DISKLESSIO  = 1 << 3,       /* no disk involved */
+       FIO_RAWIO       = 1 << 1,       /* some sort of direct/raw io */
+       FIO_DISKLESSIO  = 1 << 2,       /* no disk involved */
 };
 
 /*
diff --git a/init.c b/init.c
index 56df3c7..ba33a5e 100644 (file)
--- a/init.c
+++ b/init.c
@@ -102,6 +102,7 @@ static struct fio_option options[] = {
 #ifdef FIO_HAVE_SYSLET
                          { .ival = "syslet-rw", },
 #endif
+                         { .ival = "cpuio", },
                          { .ival = "external", },
                          },
        },
@@ -474,7 +475,8 @@ static struct fio_option options[] = {
                .name   = "cpuchunks",
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(cpucycle),
-               .help   = "Length of the CPU burn cycles",
+               .help   = "Length of the CPU burn cycles (usecs)",
+               .def    = "50000",
        },
 #ifdef FIO_HAVE_CPU_AFFINITY
        {
@@ -902,7 +904,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
 
        if (!terse_output) {
                if (!job_add_num) {
-                       if (td->io_ops->flags & FIO_CPUIO)
+                       if (!strcmp(td->io_ops->name, "cpuio"))
                                fprintf(f_out, "%s: ioengine=cpu, cpuload=%u, cpucycle=%u\n", td->name, td->cpuload, td->cpucycle);
                        else {
                                char *c1, *c2, *c3, *c4;
@@ -957,7 +959,7 @@ int init_random_state(struct thread_data *td)
        int fd, num_maps, blocks, i;
        struct fio_file *f;
 
-       if (td->io_ops->flags & FIO_CPUIO)
+       if (td->io_ops->flags & FIO_DISKLESSIO)
                return 0;
 
        fd = open("/dev/urandom", O_RDONLY);
index 66991c7..9de7ca1 100644 (file)
@@ -28,12 +28,6 @@ static int check_engine_ops(struct ioengine_ops *ops)
                return 1;
        }
 
-       /*
-        * cpu thread doesn't need to provide anything
-        */
-       if (ops->flags & FIO_CPUIO)
-               return 0;
-
        if (!ops->queue) {
                log_err("%s: no queue handler\n", ops->name);
                return 1;
diff --git a/log.c b/log.c
index 994f497..50caf3d 100644 (file)
--- a/log.c
+++ b/log.c
@@ -172,7 +172,7 @@ int init_iolog(struct thread_data *td)
 {
        int ret = 0;
 
-       if (td->io_ops->flags & FIO_CPUIO)
+       if (td->io_ops->flags & FIO_DISKLESSIO)
                return 0;
 
        if (td->read_iolog_file)