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 <axboe@kernel.dk>
unsigned int port;
unsigned int proto;
unsigned int listen;
unsigned int port;
unsigned int proto;
unsigned int listen;
};
struct udp_close_msg {
};
struct udp_close_msg {
.off1 = offsetof(struct netio_options, listen),
.help = "Listen for incoming TCP connections",
},
.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",
+ },
{
struct netio_data *nd = td->io_ops->data;
struct netio_options *o = td->eo;
{
struct netio_data *nd = td->io_ops->data;
struct netio_options *o = td->eo;
- int ret, flags = OS_MSG_DONTWAIT;
do {
if (o->proto == FIO_TYPE_UDP) {
do {
if (o->proto == FIO_TYPE_UDP) {
* if we are going to write more, set MSG_MORE
*/
#ifdef MSG_MORE
* 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,
flags |= MSG_MORE;
#endif
ret = send(io_u->file->fd, io_u->xfer_buf,
ret = poll_wait(td, io_u->file->fd, POLLOUT);
if (ret <= 0)
break;
ret = poll_wait(td, io_u->file->fd, POLLOUT);
if (ret <= 0)
break;
-
- flags &= ~OS_MSG_DONTWAIT;
{
struct netio_data *nd = td->io_ops->data;
struct netio_options *o = td->eo;
{
struct netio_data *nd = td->io_ops->data;
struct netio_options *o = td->eo;
- int ret, flags = OS_MSG_DONTWAIT;
do {
if (o->proto == FIO_TYPE_UDP) {
do {
if (o->proto == FIO_TYPE_UDP) {
ret = poll_wait(td, io_u->file->fd, POLLIN);
if (ret <= 0)
break;
ret = poll_wait(td, io_u->file->fd, POLLIN);
if (ret <= 0)
break;
- flags &= ~OS_MSG_DONTWAIT;
flags |= MSG_WAITALL;
} while (1);
return ret;
}
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;
{
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);
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);
if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
o->proto == FIO_TYPE_UNIX)
ret = fio_netio_recv(td, io_u);
} else {
int err = errno;
} 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;
return FIO_Q_BUSY;
io_u->error = err;
return FIO_Q_COMPLETED;
}
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;
static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
{
struct netio_data *nd = td->io_ops->data;