[PATCH] Separate io engines into separate loadable objects
[fio.git] / fio.c
diff --git a/fio.c b/fio.c
index 11799e0db8e6c52ad07bd6b273fa05895d208261..a2651f0325490d780ee7a9352fa01d53b81350b5 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -2,6 +2,7 @@
  * fio - the flexible io tester
  *
  * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -433,7 +434,7 @@ static void populate_io_u(struct thread_data *td, struct io_u *io_u)
 
 static int td_io_prep(struct thread_data *td, struct io_u *io_u)
 {
-       if (td->io_prep && td->io_prep(td, io_u))
+       if (td->io_ops->prep && td->io_ops->prep(td, io_u))
                return 1;
 
        return 0;
@@ -568,8 +569,8 @@ static int get_next_verify(struct thread_data *td, struct io_u *io_u)
 
 static int sync_td(struct thread_data *td)
 {
-       if (td->io_sync)
-               return td->io_sync(td);
+       if (td->io_ops->sync)
+               return td->io_ops->sync(td);
 
        return 0;
 }
@@ -577,14 +578,14 @@ static int sync_td(struct thread_data *td)
 static int io_u_getevents(struct thread_data *td, int min, int max,
                          struct timespec *t)
 {
-       return td->io_getevents(td, min, max, t);
+       return td->io_ops->getevents(td, min, max, t);
 }
 
 static int io_u_queue(struct thread_data *td, struct io_u *io_u)
 {
        gettimeofday(&io_u->issue_time, NULL);
 
-       return td->io_queue(td, io_u);
+       return td->io_ops->queue(td, io_u);
 }
 
 #define iocb_time(iocb)        ((unsigned long) (iocb)->data)
@@ -628,7 +629,7 @@ static void ios_completed(struct thread_data *td,struct io_completion_data *icd)
        icd->bytes_done[0] = icd->bytes_done[1] = 0;
 
        for (i = 0; i < icd->nr; i++) {
-               io_u = td->io_event(td, i);
+               io_u = td->io_ops->event(td, i);
 
                io_completed(td, io_u, icd);
                put_io_u(td, io_u);
@@ -659,11 +660,11 @@ static void cleanup_pending_aio(struct thread_data *td)
        /*
         * now cancel remaining active events
         */
-       if (td->io_cancel) {
+       if (td->io_ops->cancel) {
                list_for_each_safe(entry, n, &td->io_u_busylist) {
                        io_u = list_entry(entry, struct io_u, list);
 
-                       r = td->io_cancel(td, io_u);
+                       r = td->io_ops->cancel(td, io_u);
                        if (!r)
                                put_io_u(td, io_u);
                }
@@ -748,7 +749,7 @@ static void do_verify(struct thread_data *td)
                        break;
                }
 
-               v_io_u = td->io_event(td, 0);
+               v_io_u = td->io_ops->event(td, 0);
                icd.nr = 1;
                icd.error = 0;
                io_completed(td, v_io_u, &icd);
@@ -776,6 +777,31 @@ 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) {
+               gettimeofday(&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.
@@ -869,30 +895,12 @@ static void do_io(struct thread_data *td)
        }
 }
 
-static void cleanup_io(struct thread_data *td)
-{
-       if (td->io_cleanup)
-               td->io_cleanup(td);
-}
-
 static int init_io(struct thread_data *td)
 {
-       if (td->io_engine == FIO_SYNCIO)
-               return fio_syncio_init(td);
-       else if (td->io_engine == FIO_MMAPIO)
-               return fio_mmapio_init(td);
-       else if (td->io_engine == FIO_LIBAIO)
-               return fio_libaio_init(td);
-       else if (td->io_engine == FIO_POSIXAIO)
-               return fio_posixaio_init(td);
-       else if (td->io_engine == FIO_SGIO)
-               return fio_sgio_init(td);
-       else if (td->io_engine == FIO_SPLICEIO)
-               return fio_spliceio_init(td);
-       else {
-               log_err("bad io_engine %d\n", td->io_engine);
-               return 1;
-       }
+       if (td->io_ops->init)
+               return td->io_ops->init(td);
+
+       return 0;
 }
 
 static void cleanup_io_u(struct thread_data *td)
@@ -928,7 +936,10 @@ static int init_io_u(struct thread_data *td)
        int i, max_units;
        char *p;
 
-       if (td->io_engine & FIO_SYNCIO)
+       if (td->io_ops->flags & FIO_CPUIO)
+               return 0;
+
+       if (td->io_ops->flags & FIO_SYNCIO)
                max_units = 1;
        else
                max_units = td->iodepth;
@@ -1198,6 +1209,9 @@ static int setup_file(struct thread_data *td)
        struct stat st;
        int flags = 0;
 
+       if (td->io_ops->flags & FIO_CPUIO)
+               return 0;
+
        if (stat(td->file_name, &st) == -1) {
                if (errno != ENOENT) {
                        td_verror(td, errno);
@@ -1248,10 +1262,10 @@ static int setup_file(struct thread_data *td)
        if (get_file_size(td))
                return 1;
 
-       if (td->io_engine != FIO_MMAPIO)
-               return setup_file_plain(td);
-       else
+       if (td->io_ops->flags & FIO_MMAPIO)
                return setup_file_mmap(td);
+       else
+               return setup_file_plain(td);
 }
 
 static int switch_ioscheduler(struct thread_data *td)
@@ -1304,7 +1318,7 @@ static int switch_ioscheduler(struct thread_data *td)
 
 static void clear_io_state(struct thread_data *td)
 {
-       if (td->io_engine == FIO_SYNCIO)
+       if (td->io_ops->flags & FIO_SYNCIO)
                lseek(td->fd, SEEK_SET, 0);
 
        td->last_pos = 0;
@@ -1389,7 +1403,10 @@ static void *thread_main(void *data)
                clear_io_state(td);
                prune_io_piece_log(td);
 
-               do_io(td);
+               if (td->io_ops->flags & FIO_CPUIO)
+                       do_cpuio(td);
+               else
+                       do_io(td);
 
                td->runtime[td->ddir] += mtime_since_now(&td->start);
                if (td_rw(td) && td->io_bytes[td->ddir ^ 1])
@@ -1435,7 +1452,7 @@ err:
        }
        if (td->mmap)
                munmap(td->mmap, td->file_size);
-       cleanup_io(td);
+       close_ioengine(td);
        cleanup_io_u(td);
        td_set_runstate(td, TD_EXITED);
        return NULL;
@@ -1693,14 +1710,17 @@ static void print_thread_status(void)
  */
 static void reap_threads(int *nr_running, int *t_rate, int *m_rate)
 {
-       int i;
+       int i, cputhreads;
 
        /*
         * reap exited threads (TD_EXITED -> TD_REAPED)
         */
-       for (i = 0; i < thread_number; i++) {
+       for (i = 0, cputhreads = 0; i < thread_number; i++) {
                struct thread_data *td = &threads[i];
 
+               if (td->io_ops->flags & FIO_CPUIO)
+                       cputhreads++;
+
                if (td->runstate != TD_EXITED)
                        continue;
 
@@ -1718,6 +1738,9 @@ static void reap_threads(int *nr_running, int *t_rate, int *m_rate)
                (*m_rate) -= td->ratemin;
                (*t_rate) -= td->rate;
        }
+
+       if (*nr_running == cputhreads)
+               terminate_threads(TERMINATE_ALL);
 }
 
 static void fio_unpin_memory(void *pinned)