From: Davide Libenzi Date: Wed, 21 Mar 2007 07:46:18 +0000 (+0100) Subject: GUASI IO engine X-Git-Tag: fio-1.15~60 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=609342ff4b7e5ada29d348079ec343d07fae6727;hp=3f344202f614ef3275e7000738d998ca85ebb9cf GUASI IO engine Signed-off-by: Jens Axboe --- diff --git a/Makefile b/Makefile index 0cb82e33..a44c0cad 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ OBJS += engines/sync.o OBJS += engines/null.o OBJS += engines/net.o OBJS += engines/syslet-rw.o +OBJS += engines/guasi.o INSTALL = install prefix = /usr/local diff --git a/engines/guasi.c b/engines/guasi.c new file mode 100644 index 00000000..d64e6509 --- /dev/null +++ b/engines/guasi.c @@ -0,0 +1,262 @@ +/* + * guasi engine + * + * IO engine using the GUASI library. + * + * This is currently disabled, add -lguasi to the fio Makefile target + * and add a #define FIO_HAVE_GUASI to os-linux.h to enable it. You'll + * need the GUASI lib as well: + * + * http://www.xmailserver.org/guasi-lib.html + * + */ +#include +#include +#include +#include +#include + +#include "../fio.h" +#include "../os.h" + +#ifdef FIO_HAVE_GUASI + +#define GFIO_MIN_THREADS 32 + +#include +#include + +#ifdef GFIO_DEBUG +#define GDBG_PRINT(a) printf a +#else +#define GDBG_PRINT(a) (void) 0 +#endif + +#define STFU_GCC(a) a = a + + +struct guasi_data { + guasi_t hctx; + int max_reqs; + guasi_req_t *reqs; + struct io_u **io_us; + int reqs_nr; +}; + +static int fio_guasi_prep(struct thread_data fio_unused *td, struct io_u *io_u) +{ + STFU_GCC(io_u); + + GDBG_PRINT(("fio_guasi_prep(%p)\n", io_u)); + + return 0; +} + +static struct io_u *fio_guasi_event(struct thread_data *td, int event) +{ + struct guasi_data *ld = td->io_ops->data; + struct io_u *io_u; + struct guasi_reqinfo rinf; + + GDBG_PRINT(("fio_guasi_event(%d)\n", event)); + if (guasi_req_info(ld->reqs[event], &rinf) < 0) { + fprintf(stderr, "guasi_req_info(%d) FAILED!\n", event); + return NULL; + } + io_u = rinf.asid; + GDBG_PRINT(("fio_guasi_event(%d) -> %p\n", event, io_u)); + + if (io_u->ddir == DDIR_READ || + io_u->ddir == DDIR_WRITE) { + if (rinf.result != (long) io_u->xfer_buflen) { + if (rinf.result < 0) + io_u->error = rinf.error; + else + io_u->resid = io_u->xfer_buflen - rinf.result; + } else + io_u->error = 0; + } else + io_u->error = rinf.result; + + return io_u; +} + +static int fio_guasi_getevents(struct thread_data *td, int min, int max, + struct timespec *t) +{ + struct guasi_data *ld = td->io_ops->data; + int n = 0, r; + long timeo = -1; + + GDBG_PRINT(("fio_guasi_getevents(%d, %d)\n", min, max)); + if (min > ld->max_reqs) + min = ld->max_reqs; + if (max > ld->max_reqs) + max = ld->max_reqs; + if (t) + timeo = t->tv_sec * 1000L + t->tv_nsec / 1000000L; + do { + r = guasi_fetch(ld->hctx, ld->reqs + n, max - n, timeo); + if (r < 0) + break; + n += r; + if (n >= min) + break; + } while (1); + GDBG_PRINT(("fio_guasi_getevents() -> %d\n", n)); + + return n; +} + +static int fio_guasi_queue(struct thread_data *td, struct io_u *io_u) +{ + struct guasi_data *ld = td->io_ops->data; + + GDBG_PRINT(("fio_guasi_queue(%p)\n", io_u)); + if (ld->reqs_nr == (int) td->iodepth) + return FIO_Q_BUSY; + + ld->io_us[ld->reqs_nr] = io_u; + ld->reqs_nr++; + return FIO_Q_QUEUED; +} + +static void fio_guasi_queued(struct thread_data *td, struct io_u **io_us, + unsigned int nr) +{ + struct timeval now; + struct io_u *io_u = io_us[nr]; + + fio_gettime(&now, NULL); + memcpy(&io_u->issue_time, &now, sizeof(now)); + io_u_queued(td, io_u); +} + +static int fio_guasi_commit(struct thread_data *td) +{ + struct guasi_data *ld = td->io_ops->data; + int i; + struct io_u *io_u; + struct fio_file *f; + + GDBG_PRINT(("fio_guasi_commit()\n")); + for (i = 0; i < ld->reqs_nr; i++) { + io_u = ld->io_us[i]; + f = io_u->file; + io_u->greq = NULL; + if (io_u->ddir == DDIR_READ) + io_u->greq = guasi__pread(ld->hctx, ld, io_u, 0, + f->fd, io_u->xfer_buf, io_u->xfer_buflen, + io_u->offset); + else if (io_u->ddir == DDIR_WRITE) + io_u->greq = guasi__pwrite(ld->hctx, ld, io_u, 0, + f->fd, io_u->xfer_buf, io_u->xfer_buflen, + io_u->offset); + else if (io_u->ddir == DDIR_SYNC) + io_u->greq = guasi__fsync(ld->hctx, ld, io_u, 0, f->fd); + else { + fprintf(stderr, "fio_guasi_commit() FAILED: %d\n", io_u->ddir); + } + if (io_u->greq != NULL) + fio_guasi_queued(td, ld->io_us, i); + } + ld->reqs_nr = 0; + GDBG_PRINT(("fio_guasi_commit() -> %d\n", i)); + + return 0; +} + +static int fio_guasi_cancel(struct thread_data *td, struct io_u *io_u) +{ + struct guasi_data *ld = td->io_ops->data; + + STFU_GCC(ld); + GDBG_PRINT(("fio_guasi_cancel(%p)\n", io_u)); + + return guasi_req_cancel(io_u->greq); +} + +static void fio_guasi_cleanup(struct thread_data *td) +{ + struct guasi_data *ld = td->io_ops->data; + + if (ld) { + guasi_free(ld->hctx); + free(ld->reqs); + free(ld->io_us); + free(ld); + td->io_ops->data = NULL; + } +} + +static int fio_guasi_init(struct thread_data *td) +{ + int maxthr; + struct guasi_data *ld = malloc(sizeof(*ld)); + + GDBG_PRINT(("fio_guasi_init(): depth=%d\n", td->iodepth)); + memset(ld, 0, sizeof(*ld)); + maxthr = td->iodepth > GFIO_MIN_THREADS ? td->iodepth: GFIO_MIN_THREADS; + if ((ld->hctx = guasi_create(GFIO_MIN_THREADS, maxthr, 1)) == NULL) { + td_verror(td, errno, "guasi_create"); + free(ld); + return 1; + } + ld->max_reqs = td->iodepth; + ld->reqs = malloc(ld->max_reqs * sizeof(guasi_req_t)); + ld->io_us = malloc(ld->max_reqs * sizeof(struct io_u *)); + memset(ld->io_us, 0, ld->max_reqs * sizeof(struct io_u *)); + ld->reqs_nr = 0; + + td->io_ops->data = ld; + GDBG_PRINT(("fio_guasi_init(): depth=%d -> %p\n", td->iodepth, ld)); + + return 0; +} + +static struct ioengine_ops ioengine = { + .name = "guasi", + .version = FIO_IOOPS_VERSION, + .init = fio_guasi_init, + .prep = fio_guasi_prep, + .queue = fio_guasi_queue, + .commit = fio_guasi_commit, + .cancel = fio_guasi_cancel, + .getevents = fio_guasi_getevents, + .event = fio_guasi_event, + .cleanup = fio_guasi_cleanup, + .open_file = generic_open_file, + .close_file = generic_close_file, +}; + +#else /* FIO_HAVE_GUASI */ + +/* + * When we have a proper configure system in place, we simply wont build + * and install this io engine. For now install a crippled version that + * just complains and fails to load. + */ +static int fio_guasi_init(struct thread_data fio_unused *td) +{ + fprintf(stderr, "fio: guasi not available\n"); + return 1; +} + +static struct ioengine_ops ioengine = { + .name = "guasi", + .version = FIO_IOOPS_VERSION, + .init = fio_guasi_init, +}; + +#endif + +static void fio_init fio_guasi_register(void) +{ + register_ioengine(&ioengine); +} + +static void fio_exit fio_guasi_unregister(void) +{ + unregister_ioengine(&ioengine); +} + diff --git a/fio.h b/fio.h index a2be6d57..2b4b3c65 100644 --- a/fio.h +++ b/fio.h @@ -24,6 +24,10 @@ #include "syslet.h" #endif +#ifdef FIO_HAVE_GUASI +#include +#endif + enum fio_ddir { DDIR_READ = 0, DDIR_WRITE, @@ -110,6 +114,9 @@ struct io_u { #endif #ifdef FIO_HAVE_SYSLET struct syslet_req req; +#endif +#ifdef FIO_HAVE_GUASI + guasi_req_t greq; #endif }; struct timeval start_time;