When enabled, read and write requests are submitted as vectored requests using blkioq_{readv,writev}(), instead of using blkioq_{read,write}(). Signed-off-by: Alberto Faria <afaria@xxxxxxxxxx> --- HOWTO.rst | 4 ++++ engines/libblkio.c | 46 +++++++++++++++++++++++++++++++++++++++++----- fio.1 | 3 +++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/HOWTO.rst b/HOWTO.rst index cdea3258..b9c7c8df 100644 --- a/HOWTO.rst +++ b/HOWTO.rst @@ -2875,6 +2875,10 @@ with the caveat that when used on the command line, they must come after the set after the engine sets any other properties, so those can be overriden. +.. option:: libblkio_vectored=bool : [libblkio] + + Submit vectored read and write requests. Default is 0. + I/O depth ~~~~~~~~~ diff --git a/engines/libblkio.c b/engines/libblkio.c index d2ade3f1..dcf701ad 100644 --- a/engines/libblkio.c +++ b/engines/libblkio.c @@ -28,6 +28,7 @@ struct fio_blkio_options { char *pre_start_props; unsigned int hipri; + unsigned int vectored; }; static struct fio_option options[] = { @@ -68,6 +69,15 @@ static struct fio_option options[] = { .category = FIO_OPT_C_ENGINE, .group = FIO_OPT_G_LIBBLKIO, }, + { + .name = "libblkio_vectored", + .lname = "Use blkioq_{readv,writev}()", + .type = FIO_OPT_STR_SET, + .off1 = offsetof(struct fio_blkio_options, vectored), + .help = "Use blkioq_{readv,writev}() instead of blkioq_{read,write}()", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_LIBBLKIO, + }, { .name = NULL, @@ -251,6 +261,7 @@ struct fio_blkio_data { bool has_mem_region; /* whether mem_region is valid */ struct blkio_mem_region mem_region; /* only if allocated by libblkio */ + struct iovec *iovecs; /* for vectored requests */ struct blkio_completion *completions; }; @@ -267,8 +278,9 @@ static int fio_blkio_init(struct thread_data *td) goto err_free; } + data->iovecs = calloc(td->o.iodepth, sizeof(data->iovecs[0])); data->completions = calloc(td->o.iodepth, sizeof(data->completions[0])); - if (!data->completions) { + if (!data->iovecs || !data->completions) { log_err("fio: calloc() failed\n"); goto err_free; } @@ -310,6 +322,7 @@ err_blkio_destroy: blkio_destroy(&data->b); err_free: free(data->completions); + free(data->iovecs); free(data); return 1; } @@ -362,6 +375,7 @@ static void fio_blkio_cleanup(struct thread_data *td) if (data) { blkio_destroy(&data->b); free(data->completions); + free(data->iovecs); free(data); } } @@ -432,19 +446,41 @@ static int fio_blkio_open_file(struct thread_data *td, struct fio_file *f) static enum fio_q_status fio_blkio_queue(struct thread_data *td, struct io_u *io_u) { + const struct fio_blkio_options *options = td->eo; struct fio_blkio_data *data = td->io_ops_data; fio_ro_check(td, io_u); switch (io_u->ddir) { case DDIR_READ: - blkioq_read(data->q, io_u->offset, io_u->xfer_buf, - (size_t)io_u->xfer_buflen, io_u, 0); + if (options->vectored) { + struct iovec *iov = &data->iovecs[io_u->index]; + iov->iov_base = io_u->xfer_buf; + iov->iov_len = (size_t)io_u->xfer_buflen; + + blkioq_readv(data->q, io_u->offset, iov, 1, + io_u, 0); + } else { + blkioq_read(data->q, io_u->offset, + io_u->xfer_buf, + (size_t)io_u->xfer_buflen, io_u, 0); + } break; case DDIR_WRITE: - blkioq_write(data->q, io_u->offset, io_u->xfer_buf, - (size_t)io_u->xfer_buflen, io_u, 0); + if (options->vectored) { + struct iovec *iov = &data->iovecs[io_u->index]; + iov->iov_base = io_u->xfer_buf; + iov->iov_len = (size_t)io_u->xfer_buflen; + + blkioq_writev(data->q, io_u->offset, iov, 1, + io_u, 0); + } else { + blkioq_write(data->q, io_u->offset, + io_u->xfer_buf, + (size_t)io_u->xfer_buflen, io_u, + 0); + } break; case DDIR_TRIM: diff --git a/fio.1 b/fio.1 index 7c1b315a..a403b415 100644 --- a/fio.1 +++ b/fio.1 @@ -2623,6 +2623,9 @@ the engine sets any other properties, so those can be overriden. .TP .BI (libblkio)hipri \fR=\fPbool Use poll queues. +.TP +.BI (libblkio)libblkio_vectored \fR=\fPbool +Submit vectored read and write requests. Default is 0. .SS "I/O depth" .TP .BI iodepth \fR=\fPint -- 2.38.1