mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 14:25:26 +00:00
dpif-linux: Use poll() internally in dpif_linux_recv().
Using poll() internally in dpif_linux_recv(), instead of relying on the results of the main loop poll() call, brings netperf CRR performance back within 1% of par versus the code base before the poll_fd_woke() optimizations were introduced. It also increases the ovs-benchmark results by about 5% versus that baseline, too. My theory is that this is because the main loop takes long enough that a significant number of packets can arrive during the main loop itself, so this reduces the time before OVS gets to those packets.
This commit is contained in:
@@ -28,7 +28,9 @@
|
||||
#include <linux/pkt_sched.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -63,6 +65,7 @@ BUILD_ASSERT_DECL(IS_POW2(LRU_MAX_PORTS));
|
||||
|
||||
enum { N_UPCALL_SOCKS = 16 };
|
||||
BUILD_ASSERT_DECL(IS_POW2(N_UPCALL_SOCKS));
|
||||
BUILD_ASSERT_DECL(N_UPCALL_SOCKS <= 32); /* We use a 32-bit word as a mask. */
|
||||
|
||||
/* This ethtool flag was introduced in Linux 2.6.24, so it might be
|
||||
* missing if we have old headers. */
|
||||
@@ -135,8 +138,8 @@ struct dpif_linux {
|
||||
|
||||
/* Upcall messages. */
|
||||
struct nl_sock *upcall_socks[N_UPCALL_SOCKS];
|
||||
int last_read_upcall;
|
||||
unsigned int listen_mask;
|
||||
uint32_t ready_mask; /* 1-bit for each sock with unread messages. */
|
||||
unsigned int listen_mask; /* Mask of DPIF_UC_* bits. */
|
||||
|
||||
/* Change notification. */
|
||||
struct sset changed_ports; /* Ports that have changed. */
|
||||
@@ -1009,6 +1012,8 @@ dpif_linux_recv_set_mask(struct dpif *dpif_, int listen_mask)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
dpif->ready_mask = 0;
|
||||
}
|
||||
|
||||
dpif->listen_mask = listen_mask;
|
||||
@@ -1088,24 +1093,51 @@ static int
|
||||
dpif_linux_recv(struct dpif *dpif_, struct dpif_upcall *upcall)
|
||||
{
|
||||
struct dpif_linux *dpif = dpif_linux_cast(dpif_);
|
||||
int i;
|
||||
int read_tries = 0;
|
||||
|
||||
if (!dpif->listen_mask) {
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
for (i = 0; i < N_UPCALL_SOCKS; i++) {
|
||||
struct nl_sock *upcall_sock;
|
||||
int dp_ifindex;
|
||||
if (!dpif->ready_mask) {
|
||||
struct pollfd pfds[N_UPCALL_SOCKS];
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
dpif->last_read_upcall = (dpif->last_read_upcall + 1) &
|
||||
(N_UPCALL_SOCKS - 1);
|
||||
upcall_sock = dpif->upcall_socks[dpif->last_read_upcall];
|
||||
for (i = 0; i < N_UPCALL_SOCKS; i++) {
|
||||
pfds[i].fd = nl_sock_fd(dpif->upcall_socks[i]);
|
||||
pfds[i].events = POLLIN;
|
||||
pfds[i].revents = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
retval = poll(pfds, N_UPCALL_SOCKS, 0);
|
||||
} while (retval < 0 && errno == EINTR);
|
||||
if (retval < 0) {
|
||||
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
|
||||
VLOG_WARN_RL(&rl, "poll failed (%s)", strerror(errno));
|
||||
} else if (!retval) {
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
for (i = 0; i < N_UPCALL_SOCKS; i++) {
|
||||
if (pfds[i].revents) {
|
||||
dpif->ready_mask |= 1u << i;
|
||||
}
|
||||
}
|
||||
|
||||
assert(dpif->ready_mask);
|
||||
}
|
||||
|
||||
do {
|
||||
int indx = ffs(dpif->ready_mask) - 1;
|
||||
struct nl_sock *upcall_sock = dpif->upcall_socks[indx];
|
||||
|
||||
dpif->ready_mask &= ~(1u << indx);
|
||||
|
||||
for (;;) {
|
||||
struct ofpbuf *buf;
|
||||
int dp_ifindex;
|
||||
int error;
|
||||
|
||||
if (++read_tries > 50) {
|
||||
@@ -1131,7 +1163,7 @@ dpif_linux_recv(struct dpif *dpif_, struct dpif_upcall *upcall)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (dpif->ready_mask);
|
||||
|
||||
return EAGAIN;
|
||||
}
|
||||
|
Reference in New Issue
Block a user