From: Jens Axboe Date: Fri, 30 Nov 2012 08:59:20 +0000 (+0100) Subject: net: add basic ping/pong type workload support X-Git-Tag: fio-2.0.12~35 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=6f73a7f8e2498f96aeb3df6cefba2496e17aad77 net: add basic ping/pong type workload support If you use ioengine=net and then set pingpong=1, fio will operate in a ping pong type fashion. When the reader receives a package from the writer, it will return the package to the writer again. The writer, in turn, will wait for this package before writing a new package. This makes fio useful for roundrobin measurements on networks. The submission latency then measures how long it took to submit a packet to the local system, while the completion latency is how long it takes for the package to be received and returned by the other end. Signed-off-by: Jens Axboe --- diff --git a/engines/net.c b/engines/net.c index fb554a48..ff8e9e4a 100644 --- a/engines/net.c +++ b/engines/net.c @@ -33,6 +33,7 @@ struct netio_options { unsigned int port; unsigned int proto; unsigned int listen; + unsigned int pingpong; }; struct udp_close_msg { @@ -94,6 +95,12 @@ static struct fio_option options[] = { .off1 = offsetof(struct netio_options, listen), .help = "Listen for incoming TCP connections", }, + { + .name = "pingpong", + .type = FIO_OPT_STR_SET, + .off1 = offsetof(struct netio_options, pingpong), + .help = "Ping-pong IO requests", + }, { .name = NULL, }, @@ -288,7 +295,7 @@ static int fio_netio_send(struct thread_data *td, struct io_u *io_u) { struct netio_data *nd = td->io_ops->data; struct netio_options *o = td->eo; - int ret, flags = OS_MSG_DONTWAIT; + int ret, flags = 0; do { if (o->proto == FIO_TYPE_UDP) { @@ -302,8 +309,8 @@ static int fio_netio_send(struct thread_data *td, struct io_u *io_u) * if we are going to write more, set MSG_MORE */ #ifdef MSG_MORE - if (td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen < - td->o.size) + if ((td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen < + td->o.size) && !o->pingpong) flags |= MSG_MORE; #endif ret = send(io_u->file->fd, io_u->xfer_buf, @@ -315,8 +322,6 @@ static int fio_netio_send(struct thread_data *td, struct io_u *io_u) ret = poll_wait(td, io_u->file->fd, POLLOUT); if (ret <= 0) break; - - flags &= ~OS_MSG_DONTWAIT; } while (1); return ret; @@ -342,7 +347,7 @@ static int fio_netio_recv(struct thread_data *td, struct io_u *io_u) { struct netio_data *nd = td->io_ops->data; struct netio_options *o = td->eo; - int ret, flags = OS_MSG_DONTWAIT; + int ret, flags = 0; do { if (o->proto == FIO_TYPE_UDP) { @@ -367,28 +372,26 @@ static int fio_netio_recv(struct thread_data *td, struct io_u *io_u) ret = poll_wait(td, io_u->file->fd, POLLIN); if (ret <= 0) break; - flags &= ~OS_MSG_DONTWAIT; flags |= MSG_WAITALL; } while (1); return ret; } -static int fio_netio_queue(struct thread_data *td, struct io_u *io_u) +static int __fio_netio_queue(struct thread_data *td, struct io_u *io_u, + enum fio_ddir ddir) { struct netio_data *nd = td->io_ops->data; struct netio_options *o = td->eo; int ret; - fio_ro_check(td, io_u); - - if (io_u->ddir == DDIR_WRITE) { + if (ddir == DDIR_WRITE) { if (!nd->use_splice || o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_UNIX) ret = fio_netio_send(td, io_u); else ret = fio_netio_splice_out(td, io_u); - } else if (io_u->ddir == DDIR_READ) { + } else if (ddir == DDIR_READ) { if (!nd->use_splice || o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_UNIX) ret = fio_netio_recv(td, io_u); @@ -405,7 +408,7 @@ static int fio_netio_queue(struct thread_data *td, struct io_u *io_u) } else { int err = errno; - if (io_u->ddir == DDIR_WRITE && err == EMSGSIZE) + if (ddir == DDIR_WRITE && err == EMSGSIZE) return FIO_Q_BUSY; io_u->error = err; @@ -418,6 +421,28 @@ static int fio_netio_queue(struct thread_data *td, struct io_u *io_u) return FIO_Q_COMPLETED; } +static int fio_netio_queue(struct thread_data *td, struct io_u *io_u) +{ + struct netio_options *o = td->eo; + int ret; + + fio_ro_check(td, io_u); + + ret = __fio_netio_queue(td, io_u, io_u->ddir); + if (!o->pingpong || ret != FIO_Q_COMPLETED) + return ret; + + /* + * For ping-pong mode, receive or send reply as needed + */ + if (td_read(td) && io_u->ddir == DDIR_READ) + ret = __fio_netio_queue(td, io_u, DDIR_WRITE); + else if (td_write(td) && io_u->ddir == DDIR_WRITE) + ret = __fio_netio_queue(td, io_u, DDIR_READ); + + return ret; +} + static int fio_netio_connect(struct thread_data *td, struct fio_file *f) { struct netio_data *nd = td->io_ops->data;