This adds support for doing vectored I/O to libaio. Instead of using pread/pwrite calls, this allows libaio to use preadv/pwritev calls which uses iovecs. option: libaio_vectored=1 Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@xxxxxxxxx> --- HOWTO.rst | 4 ++++ engines/libaio.c | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/HOWTO.rst b/HOWTO.rst index 504a64b8..3f2bde18 100644 --- a/HOWTO.rst +++ b/HOWTO.rst @@ -2515,6 +2515,10 @@ with the caveat that when used on the command line, they must come after the not support torn-write protection. To learn a file's torn-write limits, issue statx with STATX_WRITE_ATOMIC. +.. option:: libaio_vectored=bool : [libaio] + + Submit vectored read and write requests. + .. option:: fdp=bool : [io_uring_cmd] [xnvme] Enable Flexible Data Placement mode for write commands. diff --git a/engines/libaio.c b/engines/libaio.c index c2d43793..aff4025e 100644 --- a/engines/libaio.c +++ b/engines/libaio.c @@ -37,6 +37,7 @@ struct libaio_data { struct io_u **io_us; struct io_u **io_u_index; + struct iovec *iovecs; /* for vectored requests */ /* * Basic ring buffer. 'head' is incremented in _queue(), and @@ -60,6 +61,7 @@ struct libaio_options { unsigned int userspace_reap; struct cmdprio_options cmdprio_options; unsigned int nowait; + unsigned int vectored; }; static struct fio_option options[] = { @@ -81,6 +83,16 @@ static struct fio_option options[] = { .category = FIO_OPT_C_ENGINE, .group = FIO_OPT_G_LIBAIO, }, + { + .name = "libaio_vectored", + .lname = "Use libaio preadv,pwritev", + .type = FIO_OPT_BOOL, + .off1 = offsetof(struct libaio_options, vectored), + .help = "Use libaio {preadv,pwritev} instead of libaio {pread,pwrite}", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_LIBAIO, + }, + CMDPRIO_OPTIONS(struct libaio_options, FIO_OPT_G_LIBAIO), { .name = NULL, @@ -101,13 +113,32 @@ static int fio_libaio_prep(struct thread_data *td, struct io_u *io_u) struct libaio_options *o = td->eo; struct fio_file *f = io_u->file; struct iocb *iocb = &io_u->iocb; + struct libaio_data *ld = td->io_ops_data; if (io_u->ddir == DDIR_READ) { - io_prep_pread(iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset); + if (o->vectored) { + struct iovec *iov = &ld->iovecs[io_u->index]; + + iov->iov_base = io_u->xfer_buf; + iov->iov_len = (size_t)io_u->xfer_buflen; + io_prep_preadv(iocb, f->fd, iov, 1, io_u->offset); + } else { + io_prep_pread(iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, + io_u->offset); + } if (o->nowait) iocb->aio_rw_flags |= RWF_NOWAIT; } else if (io_u->ddir == DDIR_WRITE) { - io_prep_pwrite(iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset); + if (o->vectored) { + struct iovec *iov = &ld->iovecs[io_u->index]; + + iov->iov_base = io_u->xfer_buf; + iov->iov_len = (size_t)io_u->xfer_buflen; + io_prep_pwritev(iocb, f->fd, iov, 1, io_u->offset); + } else { + io_prep_pwrite(iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, + io_u->offset); + } if (o->nowait) iocb->aio_rw_flags |= RWF_NOWAIT; #ifdef FIO_HAVE_RWF_ATOMIC @@ -394,6 +425,7 @@ static void fio_libaio_cleanup(struct thread_data *td) io_destroy(ld->aio_ctx); fio_cmdprio_cleanup(&ld->cmdprio); + free(ld->iovecs); free(ld->aio_events); free(ld->iocbs); free(ld->io_us); @@ -428,6 +460,7 @@ static int fio_libaio_init(struct thread_data *td) ld->aio_events = calloc(ld->entries, sizeof(struct io_event)); ld->iocbs = calloc(ld->entries, sizeof(struct iocb *)); ld->io_us = calloc(ld->entries, sizeof(struct io_u *)); + ld->iovecs = calloc(ld->entries, sizeof(ld->iovecs[0])); td->io_ops_data = ld; -- 2.39.5