[dpdk-dev] [PATCH 2/2] net/tap: add Rx trigger
Wiles, Keith
keith.wiles at intel.com
Tue Mar 14 14:57:19 CET 2017
> On Mar 14, 2017, at 8:51 PM, Adrien Mazarguil <adrien.mazarguil at 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.mazarguil at 6wind.com>
> Acked-by: Pascal Mazon <pascal.mazon at 6wind.com>
Acked-by: Keith Wiles <keith.wiles at 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
More information about the dev
mailing list