> On Mar 14, 2017, at 8:51 PM, Adrien Mazarguil <adrien.mazarg...@6wind.com> > wrote: > > This commit adds a signal-based trigger to the Rx burst function in order > to avoid unnecessary system calls while Rx queues are empty. > > Triggered Rx bursts put less pressure on the kernel, free up CPU resources > for applications and result in a noticeable performance improvement when > sharing CPU threads with other PMDs. > > Measuring the traffic forwarding rate between two physical devices in > testpmd (IO mode, single thread, 64B packets) before and after adding two > tap PMD instances (4 ports total) that do not process any traffic and > comparing results yields: > > Without Rx trigger: > > -15% (--burst=32) > -62% (--burst=1) > > With Rx trigger: > > -0.3% (--burst=32) > -6% (--burst=1) > > Signed-off-by: Adrien Mazarguil <adrien.mazarg...@6wind.com> > Acked-by: Pascal Mazon <pascal.ma...@6wind.com>
Acked-by: Keith Wiles <keith.wi...@intel.com> > --- > drivers/net/tap/rte_eth_tap.c | 59 ++++++++++++++++++++++++++++++++++++++ > 1 file changed, 59 insertions(+) > > diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c > index c757a7c..d5d467a 100644 > --- a/drivers/net/tap/rte_eth_tap.c > +++ b/drivers/net/tap/rte_eth_tap.c > @@ -31,6 +31,8 @@ > * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > */ > > +#include <rte_atomic.h> > +#include <rte_common.h> > #include <rte_mbuf.h> > #include <rte_ethdev.h> > #include <rte_malloc.h> > @@ -42,6 +44,9 @@ > #include <sys/socket.h> > #include <sys/ioctl.h> > #include <sys/mman.h> > +#include <errno.h> > +#include <signal.h> > +#include <stdint.h> > #include <unistd.h> > #include <arpa/inet.h> > #include <linux/if.h> > @@ -72,6 +77,8 @@ static const char *valid_arguments[] = { > > static int tap_unit; > > +static volatile uint32_t tap_trigger; /* Rx trigger */ > + > static struct rte_eth_link pmd_link = { > .link_speed = ETH_SPEED_NUM_10G, > .link_duplex = ETH_LINK_FULL_DUPLEX, > @@ -89,6 +96,7 @@ struct pkt_stats { > > struct rx_queue { > struct rte_mempool *mp; /* Mempool for RX packets */ > + uint32_t trigger_seen; /* Last seen Rx trigger value */ > uint16_t in_port; /* Port ID */ > int fd; > > @@ -111,6 +119,13 @@ struct pmd_internals { > struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */ > }; > > +static void > +tap_trigger_cb(int sig __rte_unused) > +{ > + /* Valid trigger values are nonzero */ > + tap_trigger = (tap_trigger + 1) | 0x80000000; > +} > + > /* Tun/Tap allocation routine > * > * name is the number of the interface to use, unless NULL to take the host > @@ -175,6 +190,43 @@ tun_alloc(struct pmd_internals *pmd, uint16_t qid) > goto error; > } > > + /* Set up trigger to optimize empty Rx bursts */ > + errno = 0; > + do { > + struct sigaction sa; > + int flags = fcntl(fd, F_GETFL); > + > + if (flags == -1 || sigaction(SIGIO, NULL, &sa) == -1) > + break; > + if (sa.sa_handler != tap_trigger_cb) { > + /* > + * Make sure SIGIO is not already taken. This is done > + * as late as possible to leave the application a > + * chance to set up its own signal handler first. > + */ > + if (sa.sa_handler != SIG_IGN && > + sa.sa_handler != SIG_DFL) { > + errno = EBUSY; > + break; > + } > + sa = (struct sigaction){ > + .sa_flags = SA_RESTART, > + .sa_handler = tap_trigger_cb, > + }; > + if (sigaction(SIGIO, &sa, NULL) == -1) > + break; > + } > + /* Enable SIGIO on file descriptor */ > + fcntl(fd, F_SETFL, flags | O_ASYNC); > + fcntl(fd, F_SETOWN, getpid()); > + } while (0); > + if (errno) { > + /* Disable trigger globally in case of error */ > + tap_trigger = 0; > + RTE_LOG(WARNING, PMD, "Rx trigger disabled: %s\n", > + strerror(errno)); > + } > + > if (qid == 0) { > if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { > RTE_LOG(ERR, PMD, "ioctl failed (SIOCGIFHWADDR) (%s)\n", > @@ -204,7 +256,13 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, > uint16_t nb_pkts) > struct rx_queue *rxq = queue; > uint16_t num_rx; > unsigned long num_rx_bytes = 0; > + uint32_t trigger = tap_trigger; > > + if (trigger == rxq->trigger_seen) > + return 0; > + if (trigger) > + rxq->trigger_seen = trigger; > + rte_compiler_barrier(); > for (num_rx = 0; num_rx < nb_pkts; ) { > /* allocate the next mbuf */ > mbuf = rte_pktmbuf_alloc(rxq->mp); > @@ -563,6 +621,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev, > } > > internals->rxq[rx_queue_id].mp = mp; > + internals->rxq[rx_queue_id].trigger_seen = 1; /* force initial burst */ > internals->rxq[rx_queue_id].in_port = dev->data->port_id; > > /* Now get the space available for data in the mbuf */ > -- > 2.1.4 > Regards, Keith