AF_XDP Preferred Busy Polling
cover AF_XDP Preferred Busy Polling
Single-core performance of AF_XDP at high loads can be poor because a heavily loaded NAPI context will never enter or allow for busy-polling.
1C testpmd rxonly (both IRQs and PMD on core 0):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 -- --forward-mode=rxonly 0.088Mpps
In order to achieve decent performance at high loads, it is currently recommended ensure the IRQs for the netdev and the core running the PMD are different.
2C testpmd rxonly (IRQs on core 0, PMD on core 1):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=0 -- \
--forward-mode=rxonly
19.26Mpps
However using an extra core is of course not ideal. The SO_PREFER_BUSY_POLL socket option was introduced in kernel v5.11 to help improve 1C performance. See [1].
This series sets this socket option on xsks created with DPDK (ie. instances of the AF_XDP PMD) unless explicitly disabled or not supported by the kernel. It was chosen to be enabled by default in order to bring the AF_XDP PMD in line with most other PMDs which execute on a single core.
The following system and netdev settings are recommended in conjunction with busy polling:
echo 2 | sudo tee /sys/class/net/eth0/napi_defer_hard_irqs
echo 200000 | sudo tee /sys/class/net/eth0/gro_flush_timeout
With the RFC these must be manually configured, but for the v1 these may be set from the PMD since the performance is tightly coupled with these settings.
Re-running the 1C test with busy polling support and the above settings:
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 -- --forward-mode=rxonly 10.45Mpps
A new vdev arg is introduced called 'busy_budget' whose default value is 64. busy_budget is the value supplied to the kernel with the SO_BUSY_POLL_BUDGET socket option and represents the busy-polling NAPI budget ie. the number of packets the kernel will attempt to process in the netdev's NAPI context. If set to 0, preferred busy polling is disabled.
To set the busy budget to 256:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=256 14.06Mpps
To set the busy budget to 512:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=512 14.32Mpps
To disable preferred busy polling:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=0
[1] https://lwn.net/Articles/837010/
Ciara Loftus (3):
net/af_xdp: Increase max batch size to 512
net/af_xdp: Use recvfrom() instead of poll()
net/af_xdp: preferred busy polling
doc/guides/nics/af_xdp.rst | 38 +++++++++++- drivers/net/af_xdp/compat.h | 13 ++++ drivers/net/af_xdp/rte_eth_af_xdp.c | 95 ++++++++++++++++++++++------- 3 files changed, 124 insertions(+), 22 deletions(-)
Signature · 1 line
2.17.1
RFC PATCH 1/3 net/af_xdp: Increase max batch size to 512
Prior to this the max size was 32 which was unnecessarily small. Also enforce the max batch size for TX for both copy and zero copy modes. Prior to this only copy mode enforced the max size.
--- drivers/net/af_xdp/rte_eth_af_xdp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/af_xdp/rte_eth_af_xdp.c +4 -4
@@ -66,8 +66,8 @@ RTE_LOG_REGISTER(af_xdp_logtype, pmd.net.af_xdp, NOTICE);#define ETH_AF_XDP_DFLT_START_QUEUE_IDX 0#define ETH_AF_XDP_DFLT_QUEUE_COUNT 1 -#define ETH_AF_XDP_RX_BATCH_SIZE 32 -#define ETH_AF_XDP_TX_BATCH_SIZE 32 +#define ETH_AF_XDP_RX_BATCH_SIZE 512 +#define ETH_AF_XDP_TX_BATCH_SIZE 512struct xsk_umem_info {
@@ -535,8 +535,6 @@ af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)uint32_t idx_tx;struct xsk_ring_cons *cq = &txq->pair->cq; - nb_pkts =RTE_MIN (nb_pkts,ETH_AF_XDP_TX_BATCH_SIZE ); -pull_umem_cq (umem, nb_pkts, cq); nb_pkts = rte_ring_dequeue_bulk(umem->buf_ring, addrs,
@@ -580,6 +578,8 @@ af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)static uint16_t eth_af_xdp_tx (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) { + nb_pkts =RTE_MIN (nb_pkts,ETH_AF_XDP_TX_BATCH_SIZE ); +#if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG )return af_xdp_tx_zc (queue, bufs, nb_pkts);#else
Signature · 1 line
2.17.1
RFC PATCH 2/3 net/af_xdp: Use recvfrom() instead of poll()
In reply to Ciara Loftuspoll() is more expensive and requires more tuning when used with the upcoming busy polling functionality.
--- drivers/net/af_xdp/rte_eth_af_xdp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/af_xdp/rte_eth_af_xdp.c +4 -3
@@ -263,9 +263,9 @@ af_xdp_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)if (nb_pkts ==0 ) {#if defined(XDP_USE_NEED_WAKEUP )if (xsk_ring_prod__needs_wakeup (fq)) - (void )poll (rxq->fds,1 ,1000 ); +recvfrom (xsk_socket__fd (rxq->xsk),NULL ,0 , +MSG_DONTWAIT ,NULL ,NULL );#endif -return 0 ; }
@@ -336,7 +336,8 @@ af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)if (nb_pkts ==0 ) {#if defined(XDP_USE_NEED_WAKEUP )if (xsk_ring_prod__needs_wakeup (fq)) - (void )poll (rxq->fds,1 ,1000 ); +recvfrom (xsk_socket__fd (rxq->xsk),NULL ,0 , +MSG_DONTWAIT ,NULL ,NULL );#endif return 0 ; }
Signature · 1 line
2.17.1
RFC PATCH 3/3 net/af_xdp: preferred busy polling
In reply to Ciara LoftusThis commit introduces support for preferred busy polling to the AF_XDP PMD. This feature aims to improve single-core performance for AF_XDP sockets under heavy load.
A new vdev arg is introduced called 'busy_budget' whose default value is 64. busy_budget is the value supplied to the kernel with the SO_BUSY_POLL_BUDGET socket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:
--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee /sys/class/net/eth0/napi_defer_hard_irqs echo 200000 | sudo tee /sys/class/net/eth0/gro_flush_timeout
.. where eth0 is the interface being used by the PMD.
--- doc/guides/nics/af_xdp.rst | 38 +++++++++++++- drivers/net/af_xdp/compat.h | 13 +++++ drivers/net/af_xdp/rte_eth_af_xdp.c | 80 ++++++++++++++++++++++++----- 3 files changed, 116 insertions(+), 15 deletions(-)
doc/guides/nics/af_xdp.rst +37 -1
@@ -35,6 +35,7 @@ The following options can be provided to set up an af_xdp port in DPDK. * ``shared_umem`` - PMD will attempt to share UMEM with others (optional, default 0); * ``xdp_prog`` - path to custom xdp program (optional, default none); +* ``busy_budget`` - busy polling budget (optional, default 64); Prerequisites -------------
@@ -51,6 +52,7 @@ This is a Linux-specific PMD, thus the following prerequisites apply: * For shared_umem, it requires kernel version v5.10 or later and libbpf version v0.2.0 or later. * For 32-bit OS, a kernel with version 5.4 or later is required. +* For busy polling, kernel version v5.11 or later is required. Set up an af_xdp interface -----------------------------
@@ -107,4 +109,38 @@ Limitations .. code-block:: console --vdev net_af_xdp0,iface=ens786f1,shared_umem=1 \ - --vdev net_af_xdp1,iface=ens786f2,shared_umem=1 \ + --vdev net_af_xdp1,iface=ens786f2,shared_umem=1 \ + +- **Preferred Busy Polling** + + The SO_PREFER_BUSY_POLL socket option was introduced in kernel v5.11. It can + deliver a performance improvement for sockets with heavy traffic loads and + can significantly improve single-core performance in this context. + + The feature is enabled by default in the AF_XDP PMD. To disable it, set the + 'busy_budget' vdevarg to zero: + + .. code-block:: console + + --vdev net_af_xdp0,iface=ens786f1,busy_budget=0 + + The default 'busy_budget' is 64 and it represents the number of packets the + kernel will attempt to process in the netdev's NAPI context. You can change + the value for example to 256 like so: + + .. code-block:: console + + --vdev net_af_xdp0,iface=ens786f1,busy_budget=256 + + It is also strongly recommended to set the following for optimal performance: + + .. code-block:: console + + echo 2 | sudo tee /sys/class/net/ens786f1/napi_defer_hard_irqs + echo 200000 | sudo tee /sys/class/net/ens786f1/gro_flush_timeout + + The above defers interrupts for interface ens786f1 and instead schedules its + NAPI context from a watchdog timer instead of from softirqs. More information + on this feature can be found at [1]. + + [1] https://lwn.net/Articles/837010/
drivers/net/af_xdp/compat.h +13 -0
@@ -39,3 +39,16 @@ create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused,return -1 ; }#endif + +#ifdef XDP_USE_NEED_WAKEUP +static int +syscall_needed (struct xsk_ring_prod *q,uint32_t busy_budget) +{ +return xsk_ring_prod__needs_wakeup (q) | busy_budget; +} +#else +syscall_needed(struct xsk_ring_prod *q __rte_unused, uint32_t busy_budget) +{ +return busy_budget; +} +#endif
drivers/net/af_xdp/rte_eth_af_xdp.c +66 -14
184 lines not on this page · raw message
Signature · 1 line
2.17.1
cover AF_XDP Preferred Busy Polling
In reply to Ciara LoftusSingle-core performance of AF_XDP at high loads can be poor because a heavily loaded NAPI context will never enter or allow for busy-polling.
1C testpmd rxonly (both IRQs and PMD on core 0):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=1 -- \
--forward-mode=rxonly
0.088Mpps
In order to achieve decent performance at high loads, it is currently recommended ensure the IRQs for the netdev queue and the core running the PMD are different.
2C testpmd rxonly (IRQs on core 0, PMD on core 1):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=0 -- \
--forward-mode=rxonly
19.26Mpps
However using an extra core is of course not ideal. The SO_PREFER_BUSY_POLL socket option was introduced in kernel v5.11 to help improve 1C performance. See [1].
This series sets this socket option on xsks created with DPDK (ie. instances of the AF_XDP PMD) unless explicitly disabled or not supported by the kernel. It was chosen to be enabled by default in order to bring the AF_XDP PMD in line with most other PMDs which execute on a single core.
The following system and netdev settings are recommended in conjunction with busy polling:
echo 2 | sudo tee /sys/class/net/eth0/napi_defer_hard_irqs
echo 200000 | sudo tee /sys/class/net/eth0/gro_flush_timeout
Re-running the 1C test with busy polling support and the above settings:
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=1 -- \
--forward-mode=rxonly
10.45Mpps
A new vdev arg is introduced called 'busy_budget' whose default value is 64. busy_budget is the value supplied to the kernel with the SO_BUSY_POLL_BUDGET socket option and represents the busy-polling NAPI budget ie. the number of packets the kernel will attempt to process in the netdev's NAPI context.
To set the busy budget to 256:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=256 14.06Mpps
If you still wish to run using 2 cores (one for PMD once for IRQs) it is recommended to disable busy polling to achieve optimal 2C performance:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=0 19.09Mpps
RFC->v1:
* Fixed behaviour of busy_budget=0
* Ensure we bail out if any of the new setsockopts fail
[1] https://lwn.net/Articles/837010/
Ciara Loftus (3):
net/af_xdp: Increase max batch size to 512
net/af_xdp: Use recvfrom() instead of poll()
net/af_xdp: preferred busy polling
doc/guides/nics/af_xdp.rst | 38 ++++++++++- drivers/net/af_xdp/compat.h | 13 ++++ drivers/net/af_xdp/rte_eth_af_xdp.c | 100 ++++++++++++++++++++++------ 3 files changed, 129 insertions(+), 22 deletions(-)
Signature · 1 line
2.17.1
PATCH 1/3 net/af_xdp: Increase max batch size to 512
Prior to this the max size was 32 which was unnecessarily small. Also enforce the max batch size for TX for both copy and zero copy modes. Prior to this only copy mode enforced the max size.
--- drivers/net/af_xdp/rte_eth_af_xdp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/af_xdp/rte_eth_af_xdp.c +4 -4
@@ -66,8 +66,8 @@ RTE_LOG_REGISTER(af_xdp_logtype, pmd.net.af_xdp, NOTICE);#define ETH_AF_XDP_DFLT_START_QUEUE_IDX 0#define ETH_AF_XDP_DFLT_QUEUE_COUNT 1 -#define ETH_AF_XDP_RX_BATCH_SIZE 32 -#define ETH_AF_XDP_TX_BATCH_SIZE 32 +#define ETH_AF_XDP_RX_BATCH_SIZE 512 +#define ETH_AF_XDP_TX_BATCH_SIZE 512struct xsk_umem_info {
@@ -535,8 +535,6 @@ af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)uint32_t idx_tx;struct xsk_ring_cons *cq = &txq->pair->cq; - nb_pkts =RTE_MIN (nb_pkts,ETH_AF_XDP_TX_BATCH_SIZE ); -pull_umem_cq (umem, nb_pkts, cq); nb_pkts = rte_ring_dequeue_bulk(umem->buf_ring, addrs,
@@ -580,6 +578,8 @@ af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)static uint16_t eth_af_xdp_tx (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) { + nb_pkts =RTE_MIN (nb_pkts,ETH_AF_XDP_TX_BATCH_SIZE ); +#if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG )return af_xdp_tx_zc (queue, bufs, nb_pkts);#else
Signature · 1 line
2.17.1
Re: [dpdk-dev] [PATCH 1/3] net/af_xdp: Increase max batch size to 512
Quoted 2 lines · Ciara Loftus
Prior to this the max size was 32 which was unnecessarily small.
Can you please describe the impact? Why changed from 32 to 512?
I assume this is to improve the performance but can you please explicitly document it in the commit log?
Quoted 4 lines
Also enforce the max batch size for TX for both copy and zero copy modes. Prior to this only copy mode enforced the max size.
By enforcing, the PMD ignores the user provided burst value if it is more than PMS supported MAX, and this ignoring is done in silent. Also there is no way to discover this MAX value without checking the code.
Overall, why this max values are required at all? After quick check I can see they are used for some bulk operations, which I assume can be eliminated, what do you think?
Quoted 1 line
Signed-off-by Ciara Loftus <[email protected]>
<...>
Re: [dpdk-dev] [PATCH 1/3] net/af_xdp: Increase max batch size to 512
Quoted 8 lines · Ciara Loftus
Quoted 2 lines
Prior to this the max size was 32 which was unnecessarily small.
Can you please describe the impact? Why changed from 32 to 512? I assume this is to improve the performance but can you please explicitly document it in the commit log?
Indeed - improved performance due to bulk operations and fewer ring accesses and syscalls. The value 512 was arbitrary. I will change this to the default ring size as defined by libbpf (2048) in v2. Will update the commit log with this info.
Quoted 11 lines
Quoted 5 lines
Also enforce the max batch size for TX for both copy and zero copy modes. Prior to this only copy mode enforced the max size.
By enforcing, the PMD ignores the user provided burst value if it is more than PMS supported MAX, and this ignoring is done in silent. Also there is no way to
discover this MAX value without checking the code.
Quoted 4 lines
Overall, why this max values are required at all? After quick check I can see they are used for some bulk operations, which I assume can be eliminated, what
do you think?
We need to size some arrays at compile time with this max value.
Instead of removing the bulk operations which may impact performance, how about taking an approach where we split batches that are > 2048 into smaller batches and still handle all the packets instead of discarding those > 2048. Something like what's done in ixgbe for example:
http://code.dpdk.org/dpdk/v21.02/source/drivers/net/ixgbe/ixgbe_rxtx.c#L318
Thanks,
Ciara
Quoted 4 lines
Quoted 2 lines
Signed-off-by Ciara Loftus <[email protected]><...>
Re: [dpdk-dev] [PATCH 1/3] net/af_xdp: Increase max batch size to 512
Quoted 29 lines · Ciara
Quoted 8 lines · Ciara Loftus
Quoted 2 lines
Prior to this the max size was 32 which was unnecessarily small.
Can you please describe the impact? Why changed from 32 to 512? I assume this is to improve the performance but can you please explicitly document it in the commit log?
Indeed - improved performance due to bulk operations and fewer ring accesses and syscalls. The value 512 was arbitrary. I will change this to the default ring size as defined by libbpf (2048) in v2. Will update the commit log with this info.
Quoted 11 lines
Quoted 5 lines
Also enforce the max batch size for TX for both copy and zero copy modes. Prior to this only copy mode enforced the max size.
By enforcing, the PMD ignores the user provided burst value if it is more than PMS supported MAX, and this ignoring is done in silent. Also there is no way to
discover this MAX value without checking the code.Quoted 4 lines
Overall, why this max values are required at all? After quick check I can see they are used for some bulk operations, which I assume can be eliminated, what
do you think?
Quoted 5 lines
We need to size some arrays at compile time with this max value.
Instead of removing the bulk operations which may impact performance, how about taking an approach where we split batches that are > 2048 into smaller batches and still handle all the packets instead of discarding those > 2048. Something like what's done in ixgbe for example:
http://code.dpdk.org/dpdk/v21.02/source/drivers/net/ixgbe/ixgbe_rxtx.c#L318
`
If there is no reasonable way to eliminate the fix sized arrays, above suggestion looks good.
Thanks,
ferruh
PATCH 2/3 net/af_xdp: Use recvfrom() instead of poll()
In reply to Ciara Loftuspoll() is more expensive and requires more tuning when used with the upcoming busy polling functionality.
--- drivers/net/af_xdp/rte_eth_af_xdp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/af_xdp/rte_eth_af_xdp.c +4 -3
@@ -263,9 +263,9 @@ af_xdp_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)if (nb_pkts ==0 ) {#if defined(XDP_USE_NEED_WAKEUP )if (xsk_ring_prod__needs_wakeup (fq)) - (void )poll (rxq->fds,1 ,1000 ); +recvfrom (xsk_socket__fd (rxq->xsk),NULL ,0 , +MSG_DONTWAIT ,NULL ,NULL );#endif -return 0 ; }
@@ -336,7 +336,8 @@ af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)if (nb_pkts ==0 ) {#if defined(XDP_USE_NEED_WAKEUP )if (xsk_ring_prod__needs_wakeup (fq)) - (void )poll (rxq->fds,1 ,1000 ); +recvfrom (xsk_socket__fd (rxq->xsk),NULL ,0 , +MSG_DONTWAIT ,NULL ,NULL );#endif return 0 ; }
Signature · 1 line
2.17.1
PATCH 3/3 net/af_xdp: preferred busy polling
In reply to Ciara LoftusThis commit introduces support for preferred busy polling to the AF_XDP PMD. This feature aims to improve single-core performance for AF_XDP sockets under heavy load.
A new vdev arg is introduced called 'busy_budget' whose default value is 64. busy_budget is the value supplied to the kernel with the SO_BUSY_POLL_BUDGET socket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:
--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee /sys/class/net/eth0/napi_defer_hard_irqs echo 200000 | sudo tee /sys/class/net/eth0/gro_flush_timeout
.. where eth0 is the interface being used by the PMD.
--- doc/guides/nics/af_xdp.rst | 38 ++++++++++++- drivers/net/af_xdp/compat.h | 13 +++++ drivers/net/af_xdp/rte_eth_af_xdp.c | 85 ++++++++++++++++++++++++----- 3 files changed, 121 insertions(+), 15 deletions(-)
doc/guides/nics/af_xdp.rst +37 -1
@@ -35,6 +35,7 @@ The following options can be provided to set up an af_xdp port in DPDK. * ``shared_umem`` - PMD will attempt to share UMEM with others (optional, default 0); * ``xdp_prog`` - path to custom xdp program (optional, default none); +* ``busy_budget`` - busy polling budget (optional, default 64); Prerequisites -------------
@@ -51,6 +52,7 @@ This is a Linux-specific PMD, thus the following prerequisites apply: * For shared_umem, it requires kernel version v5.10 or later and libbpf version v0.2.0 or later. * For 32-bit OS, a kernel with version 5.4 or later is required. +* For busy polling, kernel version v5.11 or later is required. Set up an af_xdp interface -----------------------------
@@ -107,4 +109,38 @@ Limitations .. code-block:: console --vdev net_af_xdp0,iface=ens786f1,shared_umem=1 \ - --vdev net_af_xdp1,iface=ens786f2,shared_umem=1 \ + --vdev net_af_xdp1,iface=ens786f2,shared_umem=1 \ + +- **Preferred Busy Polling** + + The SO_PREFER_BUSY_POLL socket option was introduced in kernel v5.11. It can + deliver a performance improvement for sockets with heavy traffic loads and + can significantly improve single-core performance in this context. + + The feature is enabled by default in the AF_XDP PMD. To disable it, set the + 'busy_budget' vdevarg to zero: + + .. code-block:: console + + --vdev net_af_xdp0,iface=ens786f1,busy_budget=0 + + The default 'busy_budget' is 64 and it represents the number of packets the + kernel will attempt to process in the netdev's NAPI context. You can change + the value for example to 256 like so: + + .. code-block:: console + + --vdev net_af_xdp0,iface=ens786f1,busy_budget=256 + + It is also strongly recommended to set the following for optimal performance: + + .. code-block:: console + + echo 2 | sudo tee /sys/class/net/ens786f1/napi_defer_hard_irqs + echo 200000 | sudo tee /sys/class/net/ens786f1/gro_flush_timeout + + The above defers interrupts for interface ens786f1 and instead schedules its + NAPI context from a watchdog timer instead of from softirqs. More information + on this feature can be found at [1]. + + [1] https://lwn.net/Articles/837010/
drivers/net/af_xdp/compat.h +13 -0
@@ -39,3 +39,16 @@ create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused,return -1 ; }#endif + +#ifdef XDP_USE_NEED_WAKEUP +static int +syscall_needed (struct xsk_ring_prod *q,uint32_t busy_budget) +{ +return xsk_ring_prod__needs_wakeup (q) | busy_budget; +} +#else +syscall_needed(struct xsk_ring_prod *q __rte_unused, uint32_t busy_budget) +{ +return busy_budget; +} +#endif
drivers/net/af_xdp/rte_eth_af_xdp.c +71 -14
189 lines not on this page · raw message
Signature · 1 line
2.17.1
Re: [dpdk-dev] [PATCH 3/3] net/af_xdp: preferred busy polling
Quoted 21 lines · Ciara Loftus
This commit introduces support for preferred busy polling to the
AF_XDPPMD. This feature aims to improve single-core performance forAF_XDPsockets under heavy load.A new vdev arg is introduced called '
busy_budget' whose default value is 64.busy_budgetis the value supplied to the kernel with theSO_BUSY_POLL_BUDGETsocket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee
/sys/class/net/eth0/napi_defer_hard_irqsecho 200000 | sudo tee/sys/class/net/eth0/gro_flush_timeout
Quoted 8 lines
.. where eth0 is the interface being used by the PMD.
Signed-off-by Ciara Loftus <[email protected]>--- doc/guides/nics/af_xdp.rst | 38 ++++++++++++- drivers/net/af_xdp/compat.h | 13 +++++ drivers/net/af_xdp/rte_eth_af_xdp.c | 85 ++++++++++++++++++++++++----- 3 files changed, 121 insertions(+), 15 deletions(-)
Can you please update the release notes too to announce the feature?
<...>
Quoted 6 lines
drivers/net/af_xdp/compat.h +2
-0@@ -39,3 +39,16 @@ create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused, return -1; }#endif + +#ifdef XDP_USE_NEED_WAKEUP
drivers/net/af_xdp/compat.h create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused, · line 53
Quoted 10 lines
drivers/net/af_xdp/compat.h +10
-0+static int +syscall_needed (struct xsk_ring_prod *q,uint32_t busy_budget) +{ +return xsk_ring_prod__needs_wakeup (q) | busy_budget; +} +#else +syscall_needed(struct xsk_ring_prod *q __rte_unused, uint32_t busy_budget) +{ +return busy_budget; +}
Is the return type missing in the definition?
Also for the case when both 'XDP_USE_NEED_WAKEUP' & 'SO_PREFER_BUSY_POLL' this function will always return '0', but current implementation doesn't know this in the compile time and compiler can't optimize for it, do you think does it make sense to do this optimization?
<...>
drivers/net/af_xdp/rte_eth_af_xdp.c rte_pmd_af_xdp_probe(struct rte_vdev_device *dev) · line 1677
Quoted 9 lines
drivers/net/af_xdp/rte_eth_af_xdp.c +5
-0@@ -1628,8 +1670,22 @@ rte_pmd_af_xdp_probe(struct rte_vdev_device *dev)return -EINVAL ; } +#ifdef SO_PREFER_BUSY_POLL + busy_budget = busy_budget ==-1 ?ETH_AF_XDP_DFLT_BUSY_BUDGET : + busy_budget; +if (!busy_budget) +AF_XDP_LOG (ERR ,"Preferred busy polling disabled\n" );
Is this an error case? What do you think changing the log level to DEBUG or INFO?
Also how these compile time flags will work if the compiled environment and run environment kernel version are different and incompatible?
Overall can it be possible to detect the support on runtime via 'setsockopt()' without compile time macros and eliminate the compile time flags? Does it make sense?
Re: [dpdk-dev] [PATCH 3/3] net/af_xdp: preferred busy polling
Quoted 30 lines · Ciara Loftus
Quoted 21 lines
This commit introduces support for preferred busy polling to the
AF_XDPPMD. This feature aims to improve single-core performance forAF_XDPsockets under heavy load.A new vdev arg is introduced called '
busy_budget' whose default value is 64.busy_budgetis the value supplied to the kernel with theSO_BUSY_POLL_BUDGETsocket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee
/sys/class/net/eth0/napi_defer_hard_irqsecho 200000 | sudo tee/sys/class/net/eth0/gro_flush_timeoutQuoted 7 lines
.. where eth0 is the interface being used by the PMD.
Signed-off-by Ciara Loftus <[email protected]>--- doc/guides/nics/af_xdp.rst | 38 ++++++++++++- drivers/net/af_xdp/compat.h | 13 +++++ drivers/net/af_xdp/rte_eth_af_xdp.c | 85
Quoted 4 lines
++++++++++++++++++++++++-----
Quoted 1 line
3 files changed, 121 insertions(+), 15 deletions(-)Can you please update the release notes too to announce the feature?
Will do.
Quoted 19 lines
<...>
Review create_shared_socket(struct xsk_socket **xsk_ptr
Quoted 1 line
(quoted diff) +0
-0@@ -39,3 +39,16 @@ create_shared_socket(struct xsk_socket **xsk_ptr
__rte_unused,drivers/net/af_xdp/compat.h create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused,
Quoted 12 lines
drivers/net/af_xdp/compat.h +9
-0return -1 ; }#endif + +#ifdef XDP_USE_NEED_WAKEUP +static int +syscall_needed (struct xsk_ring_prod *q,uint32_t busy_budget) +{ +return xsk_ring_prod__needs_wakeup (q) | busy_budget; +} +#else +syscall_needed(struct xsk_ring_prod *q __rte_unused, uint32_t
busy_budget)
Quoted 5 lines
drivers/net/af_xdp/compat.h create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused, · line 53
Quoted 3 lines
drivers/net/af_xdp/compat.h +3
-0+{ +return busy_budget; +}Is the return type missing in the definition?
Yes. Thanks for spotting this.
Quoted 7 lines
Also for the case when both '
XDP_USE_NEED_WAKEUP' & 'SO_PREFER_BUSY_POLL' this
function will always return '0', but current implementation doesn't know this in
the compile time and compiler can't optimize for it, do you think does it make sense to do this optimization?
It makes sense assuming the compile environment and run environment are the same.
However you make a valid point below. If the environments are different, we can't make this optimization because we can’t rely on the presence of the flags alone to tell us if these features are supported. More below.
Quoted 11 lines
<...>
Review rte_pmd_af_xdp_probe(struct rte_vdev_device
Quoted 1 line
(quoted diff) +0
-0@@ -1628,8 +1670,22 @@ rte_pmd_af_xdp_probe(struct rte_vdev_device*dev)
drivers/net/af_xdp/rte_eth_af_xdp.c rte_pmd_af_xdp_probe(struct rte_vdev_device *dev)
Quoted 5 lines
drivers/net/af_xdp/rte_eth_af_xdp.c +2
-0return -EINVAL ; } +#ifdef SO_PREFER_BUSY_POLL + busy_budget = busy_budget == -1 ?
ETH_AF_XDP_DFLT_BUSY_BUDGET:
Quoted 6 lines
drivers/net/af_xdp/rte_eth_af_xdp.c rte_pmd_af_xdp_probe(struct rte_vdev_device *dev) · line 1677
Quoted 3 lines
drivers/net/af_xdp/rte_eth_af_xdp.c +3
-0+ busy_budget; +if (!busy_budget) +AF_XDP_LOG (ERR ,"Preferred busy polling disabled\n" );Is this an error case? What do you think changing the log level to DEBUG or INFO?
+1 for INFO
Quoted 4 lines
Also how these compile time flags will work if the compiled environment and run
environment kernel version are different and incompatible?
This is a valid point. Right now if XDP_USE_NEED_WAKEUP is defined we assume the functionality is available in the kernel. If it's not, socket creation will fail and we abort. Perhaps we should retry socket creation without the flag if we get this failure. And record if support is available in a runtime variable. I'll look at adding this as another patch to the v2 series.
Quoted 5 lines
Overall can it be possible to detect the support on runtime via '
setsockopt()' without compile time macros and eliminate the compile time flags? Does it make
sense?
I think this can be done. It should allow applications compiled on older kernels without SO_PREFER_BUSY_POLL run on newer kernels with the feature. I will tackle this in the v2.
Thanks for your feedback!
Ciara
Re: [dpdk-dev] [PATCH 3/3] net/af_xdp: preferred busy polling
Quoted 104 lines
Quoted 30 lines · Ciara Loftus
Quoted 21 lines
This commit introduces support for preferred busy polling to the
AF_XDPPMD. This feature aims to improve single-core performance forAF_XDPsockets under heavy load.A new vdev arg is introduced called '
busy_budget' whose default value is 64.busy_budgetis the value supplied to the kernel with theSO_BUSY_POLL_BUDGETsocket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee
/sys/class/net/eth0/napi_defer_hard_irqsecho 200000 | sudo tee/sys/class/net/eth0/gro_flush_timeoutQuoted 7 lines
.. where eth0 is the interface being used by the PMD.
Signed-off-by Ciara Loftus <[email protected]>--- doc/guides/nics/af_xdp.rst | 38 ++++++++++++- drivers/net/af_xdp/compat.h | 13 +++++ drivers/net/af_xdp/rte_eth_af_xdp.c | 85Quoted 4 lines
++++++++++++++++++++++++-----
Quoted 1 line
3 files changed, 121 insertions(+), 15 deletions(-)Can you please update the release notes too to announce the feature?
Will do.
Quoted 19 lines
<...>
Review create_shared_socket(struct xsk_socket **xsk_ptr
Quoted 1 line
(quoted diff) +0
-0@@ -39,3 +39,16 @@ create_shared_socket(struct xsk_socket **xsk_ptr
__rte_unused,drivers/net/af_xdp/compat.h create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused,
Quoted 12 lines
drivers/net/af_xdp/compat.h +9
-0return -1 ; }#endif + +#ifdef XDP_USE_NEED_WAKEUP +static int +syscall_needed (struct xsk_ring_prod *q,uint32_t busy_budget) +{ +return xsk_ring_prod__needs_wakeup (q) | busy_budget; +} +#else +syscall_needed(struct xsk_ring_prod *q __rte_unused, uint32_t
busy_budget)Quoted 5 lines
drivers/net/af_xdp/compat.h create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused, · line 53
Quoted 3 lines
drivers/net/af_xdp/compat.h +3
-0+{ +return busy_budget; +}Is the return type missing in the definition?
Yes. Thanks for spotting this.
Quoted 4 lines
Also for the case when both '
XDP_USE_NEED_WAKEUP' & 'SO_PREFER_BUSY_POLL' this
function will always return '0', but current implementation doesn't knowthis
Quoted 2 lines
in
the compile time and compiler can't optimize for it, do you think does itmake
Quoted 1 line
sense to do this optimization?
It makes sense assuming the compile environment and run environment are the same.
However you make a valid point below. If the environments are different, we can't make this optimization because we can’t rely on the presence of the flags alone to tell us if these features are supported. More below.Quoted 4 lines
<...>
Review rte_pmd_af_xdp_probe(struct
Quoted 1 line
(quoted diff) +0
-0@@ -1628,8 +1670,22 @@ rte_pmd_af_xdp_probe(struct
rte_vdev_deviceQuoted 7 lines
*dev)
drivers/net/af_xdp/rte_eth_af_xdp.c rte_pmd_af_xdp_probe(struct rte_vdev_device *dev)
Quoted 5 lines
drivers/net/af_xdp/rte_eth_af_xdp.c +2
-0return -EINVAL ; } +#ifdef SO_PREFER_BUSY_POLL + busy_budget = busy_budget == -1 ?
ETH_AF_XDP_DFLT_BUSY_BUDGET:Quoted 6 lines
drivers/net/af_xdp/rte_eth_af_xdp.c rte_pmd_af_xdp_probe(struct rte_vdev_device *dev) · line 1677
Quoted 3 lines
drivers/net/af_xdp/rte_eth_af_xdp.c +3
-0+ busy_budget; +if (!busy_budget) +AF_XDP_LOG (ERR ,"Preferred busy polling disabled\n" );Is this an error case? What do you think changing the log level to DEBUG or INFO?
+1 for INFO
Quoted 2 lines
Also how these compile time flags will work if the compiled environment
and
Quoted 8 lines
Quoted 2 lines
run
environment kernel version are different and incompatible?This is a valid point. Right now if
XDP_USE_NEED_WAKEUPis defined we assume the functionality is available in the kernel. If it's not, socket creation will fail and we abort. Perhaps we should retry socket creation without the flag if we get this failure. And record if support is available in a runtime variable. I'll look at adding this as another patch to the v2 series.
Hi Ferruh,
I looked at this a little more. For the v2 I'll make sure busy poll can work in these environments with different compile-time and run-time kernels and use setsockopt() to detect support in the kernel. Since it will require significant changes and validation I'll submit a separate series ensuring the same for the other existing flags (XDP_USE_NEED_WAKEUP / XDP_UMEM_UNALIGNED_CHUNK_FLAG / shared umem).
Thanks,
Ciara
Quoted 16 lines
Quoted 3 lines
Overall can it be possible to detect the support on runtime via
'
setsockopt()'Quoted 3 lines
without compile time macros and eliminate the compile time flags? Does it make
sense?I think this can be done. It should allow applications compiled on older kernels without
SO_PREFER_BUSY_POLLrun on newer kernels with the feature.
I will tackle this in the v2.Thanks for your feedback!
Ciara
v2 cover AF_XDP Preferred Busy Polling
In reply to Ciara LoftusSingle-core performance of AF_XDP at high loads can be poor because a heavily loaded NAPI context will never enter or allow for busy-polling.
1C testpmd rxonly (both IRQs and PMD on core 0):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=1 -- \
--forward-mode=rxonly
0.088Mpps
In order to achieve decent performance at high loads, it is currently recommended ensure the IRQs for the netdev queue and the core running the PMD are different.
2C testpmd rxonly (IRQs on core 0, PMD on core 1):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=0 -- \
--forward-mode=rxonly
19.26Mpps
However using an extra core is of course not ideal. The SO_PREFER_BUSY_POLL socket option was introduced in kernel v5.11 to help improve 1C performance. See [1].
This series sets this socket option on xsks created with DPDK (ie. instances of the AF_XDP PMD) unless explicitly disabled or not supported by the kernel. It was chosen to be enabled by default in order to bring the AF_XDP PMD in line with most other PMDs which execute on a single core.
The following system and netdev settings are recommended in conjunction with busy polling:
echo 2 | sudo tee /sys/class/net/eth0/napi_defer_hard_irqs
echo 200000 | sudo tee /sys/class/net/eth0/gro_flush_timeout
Re-running the 1C test with busy polling support and the above settings:
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=1 -- \
--forward-mode=rxonly
10.45Mpps
A new vdev arg is introduced called 'busy_budget' whose default value is 64. busy_budget is the value supplied to the kernel with the SO_BUSY_POLL_BUDGET socket option and represents the busy-polling NAPI budget ie. the number of packets the kernel will attempt to process in the netdev's NAPI context.
To set the busy budget to 256:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=256 14.06Mpps
If you still wish to run using 2 cores (one for PMD once for IRQs) it is recommended to disable busy polling to achieve optimal 2C performance:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=0 19.09Mpps
v1->v2:
* Set batch size to default size of ring (2048)
* Split batches > 2048 into multiples of 2048 or less and process all packets in the same manner that is done for other drivers eg. ixgbe:
http://code.dpdk.org/dpdk/v21.02/source/drivers/net/ixgbe/ixgbe_rxtx.c#L318
* Update commit log with reasoning behing batching changes
* Update release notes with note on busy polling support
* Fix return type for sycall_needed function when the wakeup flag is not present
* Apprpriate log leveling
* Set default_*xportconf burst sizes to the default busy budget size (64)
* Detect support for busy polling via setsockopt instead of using the presence of the flag
RFC->v1:
* Fixed behaviour of busy_budget=0
* Ensure we bail out any of the new setsockopts fail
[1] https://lwn.net/Articles/837010/
Ciara Loftus (3):
net/af_xdp: allow bigger batch sizes
net/af_xdp: Use recvfrom() instead of poll()
net/af_xdp: preferred busy polling
doc/guides/nics/af_xdp.rst | 38 ++++- doc/guides/rel_notes/release_21_05.rst | 4 + drivers/net/af_xdp/compat.h | 14 ++ drivers/net/af_xdp/rte_eth_af_xdp.c | 190 ++++++++++++++++++++++--- 4 files changed, 222 insertions(+), 24 deletions(-)
Signature · 1 line
2.17.1
PATCH v2 1/3 net/af_xdp: allow bigger batch sizes
Prior to this commit, the maximum batch sizes for zero-copy and copy-mode rx and copy-mode tx were set to 32. Apart from zero-copy tx, the user could never rx/tx any more than 32 packets at a time and without inspecting the code the user wouldn't be aware of this.
This commit removes these upper limits placed on the user and instead sets an internal batch size equal to the default ring size (2048). Batches larger than this are still processed, however they are split into smaller batches similar to how it's done in other drivers. This is necessary because some arrays used during rx/tx need to be sized at compile-time.
Allowing a larger batch size allows for fewer batches and thus larger bulk operations, fewer ring accesses and fewer syscalls which should yield improved performance.
--- drivers/net/af_xdp/rte_eth_af_xdp.c | 67 ++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 10 deletions(-)
drivers/net/af_xdp/rte_eth_af_xdp.c +57 -10
@@ -66,8 +66,8 @@ RTE_LOG_REGISTER(af_xdp_logtype, pmd.net.af_xdp, NOTICE);#define ETH_AF_XDP_DFLT_START_QUEUE_IDX 0#define ETH_AF_XDP_DFLT_QUEUE_COUNT 1 -#define ETH_AF_XDP_RX_BATCH_SIZE 32 -#define ETH_AF_XDP_TX_BATCH_SIZE 32 +#define ETH_AF_XDP_RX_BATCH_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCS +#define ETH_AF_XDP_TX_BATCH_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCSstruct xsk_umem_info {
@@ -329,8 +329,7 @@ af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)struct rte_mbuf *mbufs[ETH_AF_XDP_RX_BATCH_SIZE ];if (xsk_prod_nb_free (fq, free_thresh) >= free_thresh) - (void )reserve_fill_queue (umem,ETH_AF_XDP_RX_BATCH_SIZE , -NULL , fq); + (void )reserve_fill_queue (umem, nb_pkts,NULL , fq); nb_pkts =xsk_ring_cons__peek (rx, nb_pkts, &idx_rx);if (nb_pkts ==0 ) {
@@ -379,10 +378,8 @@ af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)#endif static uint16_t -eth_af_xdp_rx (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) +af_xdp_rx (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) { - nb_pkts =RTE_MIN (nb_pkts,ETH_AF_XDP_RX_BATCH_SIZE ); -#if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG )return af_xdp_rx_zc (queue, bufs, nb_pkts);#else
@@ -390,6 +387,32 @@ eth_af_xdp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)#endif } +static uint16_t +eth_af_xdp_rx (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) +{ +uint16_t nb_rx; + +if (likely (nb_pkts <=ETH_AF_XDP_RX_BATCH_SIZE )) +return af_xdp_rx (queue, bufs, nb_pkts); + +/* Split larger batch into smaller batches of size +* ETH_AF_XDP_RX_BATCH_SIZE or less. +*/ + nb_rx =0 ; +while (nb_pkts) { +uint16_t ret, n; + + n = (uint16_t )RTE_MIN (nb_pkts,ETH_AF_XDP_RX_BATCH_SIZE ); + ret =af_xdp_rx (queue, &bufs[nb_rx], n); + nb_rx = (uint16_t )(nb_rx + ret); + nb_pkts = (uint16_t )(nb_pkts - ret); +if (ret < n) +break ; + } + +return nb_rx; +} +static void pull_umem_cq (struct xsk_umem_info *umem,int size,struct xsk_ring_cons *cq) {
@@ -535,8 +558,6 @@ af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)uint32_t idx_tx;struct xsk_ring_cons *cq = &txq->pair->cq; - nb_pkts =RTE_MIN (nb_pkts,ETH_AF_XDP_TX_BATCH_SIZE ); -pull_umem_cq (umem, nb_pkts, cq); nb_pkts = rte_ring_dequeue_bulk(umem->buf_ring, addrs,
@@ -575,6 +596,32 @@ af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)return nb_pkts; } + +static uint16_t +af_xdp_tx_cp_batch (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) +{ +uint16_t nb_tx; + +if (likely (nb_pkts <=ETH_AF_XDP_TX_BATCH_SIZE )) +return af_xdp_tx_cp (queue, bufs, nb_pkts); + + nb_tx =0 ; +while (nb_pkts) { +uint16_t ret, n; + +/* Split larger batch into smaller batches of size +* ETH_AF_XDP_TX_BATCH_SIZE or less. +*/ + n = (uint16_t )RTE_MIN (nb_pkts,ETH_AF_XDP_TX_BATCH_SIZE ); + ret =af_xdp_tx_cp (queue, &bufs[nb_tx], n); + nb_tx = (uint16_t )(nb_tx + ret); + nb_pkts = (uint16_t )(nb_pkts - ret); +if (ret < n) +break ; + } + +return nb_tx; +}#endif static uint16_t
@@ -583,7 +630,7 @@ eth_af_xdp_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)#if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG )return af_xdp_tx_zc (queue, bufs, nb_pkts);#else -return af_xdp_tx_cp (queue, bufs, nb_pkts); +return af_xdp_tx_cp_batch (queue, bufs, nb_pkts);#endif }
Signature · 1 line
2.17.1
Re: [dpdk-dev] [PATCH v2 1/3] net/af_xdp: allow bigger batch sizes
Quoted 25 lines · Ciara Loftus
Prior to this commit, the maximum batch sizes for zero-copy and copy-mode rx and copy-mode tx were set to 32. Apart from zero-copy tx, the user could never rx/tx any more than 32 packets at a time and without inspecting the code the user wouldn't be aware of this.
This commit removes these upper limits placed on the user and instead sets an internal batch size equal to the default ring size (2048). Batches larger than this are still processed, however they are split into smaller batches similar to how it's done in other drivers. This is necessary because some arrays used during rx/tx need to be sized at compile-time.
Allowing a larger batch size allows for fewer batches and thus larger bulk operations, fewer ring accesses and fewer syscalls which should yield improved performance.
Signed-off-by Ciara Loftus <[email protected]>--- drivers/net/af_xdp/rte_eth_af_xdp.c | 67 ++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 10 deletions(-)drivers/net/af_xdp/rte_eth_af_xdp.c +0
-0
drivers/net/af_xdp/rte_eth_af_xdp.c RTE_LOG_REGISTER(af_xdp_logtype, pmd.net.af_xdp, NOTICE); · line 71
Quoted 8 lines
drivers/net/af_xdp/rte_eth_af_xdp.c +2
-2@@ -66,8 +66,8 @@ RTE_LOG_REGISTER(af_xdp_logtype, pmd.net.af_xdp, NOTICE);#define ETH_AF_XDP_DFLT_START_QUEUE_IDX 0#define ETH_AF_XDP_DFLT_QUEUE_COUNT 1 -#define ETH_AF_XDP_RX_BATCH_SIZE 32 -#define ETH_AF_XDP_TX_BATCH_SIZE 32 +#define ETH_AF_XDP_RX_BATCH_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCS +#define ETH_AF_XDP_TX_BATCH_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCS
Just to double check, can there be a library version that these macros not defined, should it be checked?
Re: [dpdk-dev] [PATCH v2 1/3] net/af_xdp: allow bigger batch sizes
Quoted 39 lines · Ciara Loftus
Quoted 1 line
Prior to this commit, the maximum batch sizes for zero-copy and copy-
mode
Quoted 2 lines
rx and copy-mode tx were set to 32. Apart from zero-copy tx, the user could never rx/tx any more than 32 packets at a time and without
inspecting
Quoted 8 lines
the code the user wouldn't be aware of this.
This commit removes these upper limits placed on the user and instead sets an internal batch size equal to the default ring size (2048). Batches larger than this are still processed, however they are split into smaller batches similar to how it's done in other drivers. This is necessary because some arrays used during rx/tx need to be sized at compile-time.
Quoted 7 lines
Allowing a larger batch size allows for fewer batches and thus larger bulk operations, fewer ring accesses and fewer syscalls which should yield improved performance.
Signed-off-by Ciara Loftus <[email protected]>--- drivers/net/af_xdp/rte_eth_af_xdp.c | 67++++++++++++++++++++++++-----
Review
Quoted 3 lines
1 file changed, 57 insertions(+), 10 deletions(-)(quoted diff) +0
-0
b/drivers/net/af_xdp/rte_eth_af_xdp.cdrivers/net/af_xdp/rte_eth_af_xdp.c RTE_LOG_REGISTER(af_xdp_logtype,
Quoted 4 lines
index
3957227bf0..be524e4784100644drivers/net/af_xdp/rte_eth_af_xdp.c +0
-0@@ -66,8 +66,8 @@ RTE_LOG_REGISTER(af_xdp_logtype,pmd.net.af_xdp, NOTICE);
drivers/net/af_xdp/rte_eth_af_xdp.c RTE_LOG_REGISTER(af_xdp_logtype, pmd.net.af_xdp, NOTICE);
Quoted 6 lines
drivers/net/af_xdp/rte_eth_af_xdp.c +1
-2#define ETH_AF_XDP_DFLT_START_QUEUE_IDX 0#define ETH_AF_XDP_DFLT_QUEUE_COUNT 1 -#define ETH_AF_XDP_RX_BATCH_SIZE 32 -#define ETH_AF_XDP_TX_BATCH_SIZE 32 +#define ETH_AF_XDP_RX_BATCH_SIZE
XSK_RING_CONS__DEFAULT_NUM_DESCS
Quoted 6 lines
drivers/net/af_xdp/rte_eth_af_xdp.c RTE_LOG_REGISTER(af_xdp_logtype, · line 70
Quoted 1 line
drivers/net/af_xdp/rte_eth_af_xdp.c +1
-0+#define ETH_AF_XDP_TX_BATCH_SIZE
XSK_RING_CONS__DEFAULT_NUM_DESCSQuoted 1 line
Just to double check, can there be a library version that these macros not defined, should it be checked?
There can't be a library version with AF_XDP support without these macros, as they've been around since the very beginning:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1cad078842396
We only build the PMD if xsk.h is available, and since these macros have been in the file since it has existed, we're safe.
PATCH v2 2/3 net/af_xdp: Use recvfrom() instead of poll()
In reply to Ciara Loftuspoll() is more expensive and requires more tuning when used with the upcoming busy polling functionality.
--- drivers/net/af_xdp/rte_eth_af_xdp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/af_xdp/rte_eth_af_xdp.c +4 -2
@@ -263,7 +263,8 @@ af_xdp_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)if (nb_pkts ==0 ) {#if defined(XDP_USE_NEED_WAKEUP )if (xsk_ring_prod__needs_wakeup (fq)) - (void )poll (rxq->fds,1 ,1000 ); +recvfrom (xsk_socket__fd (rxq->xsk),NULL ,0 , +MSG_DONTWAIT ,NULL ,NULL );#endif return 0 ;
@@ -335,7 +336,8 @@ af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)if (nb_pkts ==0 ) {#if defined(XDP_USE_NEED_WAKEUP )if (xsk_ring_prod__needs_wakeup (fq)) - (void )poll (rxq->fds,1 ,1000 ); +recvfrom (xsk_socket__fd (rxq->xsk),NULL ,0 , +MSG_DONTWAIT ,NULL ,NULL );#endif return 0 ; }
Signature · 1 line
2.17.1
PATCH v2 3/3 net/af_xdp: preferred busy polling
In reply to Ciara LoftusThis commit introduces support for preferred busy polling to the AF_XDP PMD. This feature aims to improve single-core performance for AF_XDP sockets under heavy load.
A new vdev arg is introduced called 'busy_budget' whose default value is 64. busy_budget is the value supplied to the kernel with the SO_BUSY_POLL_BUDGET socket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:
--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee /sys/class/net/eth0/napi_defer_hard_irqs echo 200000 | sudo tee /sys/class/net/eth0/gro_flush_timeout
.. where eth0 is the interface being used by the PMD.
--- doc/guides/nics/af_xdp.rst | 38 +++++++- doc/guides/rel_notes/release_21_05.rst | 4 + drivers/net/af_xdp/compat.h | 14 +++ drivers/net/af_xdp/rte_eth_af_xdp.c | 117 ++++++++++++++++++++++--- 4 files changed, 161 insertions(+), 12 deletions(-)
doc/guides/nics/af_xdp.rst +37 -1
@@ -35,6 +35,7 @@ The following options can be provided to set up an af_xdp port in DPDK. * ``shared_umem`` - PMD will attempt to share UMEM with others (optional, default 0); * ``xdp_prog`` - path to custom xdp program (optional, default none); +* ``busy_budget`` - busy polling budget (optional, default 64); Prerequisites -------------
@@ -51,6 +52,7 @@ This is a Linux-specific PMD, thus the following prerequisites apply: * For shared_umem, it requires kernel version v5.10 or later and libbpf version v0.2.0 or later. * For 32-bit OS, a kernel with version 5.4 or later is required. +* For busy polling, kernel version v5.11 or later is required. Set up an af_xdp interface -----------------------------
@@ -107,4 +109,38 @@ Limitations .. code-block:: console --vdev net_af_xdp0,iface=ens786f1,shared_umem=1 \ - --vdev net_af_xdp1,iface=ens786f2,shared_umem=1 \ + --vdev net_af_xdp1,iface=ens786f2,shared_umem=1 \ + +- **Preferred Busy Polling** + + The SO_PREFER_BUSY_POLL socket option was introduced in kernel v5.11. It can + deliver a performance improvement for sockets with heavy traffic loads and + can significantly improve single-core performance in this context. + + The feature is enabled by default in the AF_XDP PMD. To disable it, set the + 'busy_budget' vdevarg to zero: + + .. code-block:: console + + --vdev net_af_xdp0,iface=ens786f1,busy_budget=0 + + The default 'busy_budget' is 64 and it represents the number of packets the + kernel will attempt to process in the netdev's NAPI context. You can change + the value for example to 256 like so: + + .. code-block:: console + + --vdev net_af_xdp0,iface=ens786f1,busy_budget=256 + + It is also strongly recommended to set the following for optimal performance: + + .. code-block:: console + + echo 2 | sudo tee /sys/class/net/ens786f1/napi_defer_hard_irqs + echo 200000 | sudo tee /sys/class/net/ens786f1/gro_flush_timeout + + The above defers interrupts for interface ens786f1 and instead schedules its + NAPI context from a watchdog timer instead of from softirqs. More information + on this feature can be found at [1]. + + [1] https://lwn.net/Articles/837010/
doc/guides/rel_notes/release_21_05.rst +4 -0
@@ -70,6 +70,10 @@ New Features * Added command to display Rx queue used descriptor count. ``show port (port_id) rxq (queue_id) desc used count`` +* **Updated the AF_XDP driver.** + + * Added support for preferred busy polling. + Removed Items -------------
drivers/net/af_xdp/compat.h +14 -0
@@ -39,3 +39,17 @@ create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused,return -1 ; }#endif + +#ifdef XDP_USE_NEED_WAKEUP +static int +syscall_needed (struct xsk_ring_prod *q,uint32_t busy_budget) +{ +return xsk_ring_prod__needs_wakeup (q) | busy_budget; +} +#else +static int +syscall_needed(struct xsk_ring_prod *q __rte_unused, uint32_t busy_budget) +{ +return busy_budget; +} +#endif
drivers/net/af_xdp/rte_eth_af_xdp.c +106 -11
231 lines not on this page · raw message
Signature · 1 line
2.17.1
Re: [dpdk-dev] [PATCH v2 3/3] net/af_xdp: preferred busy polling
Quoted 24 lines · Ciara Loftus
This commit introduces support for preferred busy polling to the
AF_XDPPMD. This feature aims to improve single-core performance forAF_XDPsockets under heavy load.A new vdev arg is introduced called '
busy_budget' whose default value is 64.busy_budgetis the value supplied to the kernel with theSO_BUSY_POLL_BUDGETsocket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee
/sys/class/net/eth0/napi_defer_hard_irqsecho 200000 | sudo tee/sys/class/net/eth0/gro_flush_timeout.. where eth0 is the interface being used by the PMD.
Signed-off-by Ciara Loftus <[email protected]>
<...>
doc/guides/rel_notes/release_21_05.rst New Features · line 77
Quoted 11 lines
doc/guides/rel_notes/release_21_05.rst +4
-0@@ -70,6 +70,10 @@ New Features * Added command to display Rx queue used descriptor count. ``show port (port_id) rxq (queue_id) desc used count`` +* **Updated the AF_XDP driver.** + + * Added support for preferred busy polling. +
Can you please move the update after above the testpmd updates? For more details the expected order is in the section comment.
Quoted 9 lines
doc/guides/rel_notes/release_21_05.rst +9
-0+static int +configure_preferred_busy_poll(struct pkt_rx_queue *rxq) +{ + int sock_opt = 1; + int fd = xsk_socket__fd(rxq->xsk); + int ret = 0; + + ret = setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL, + (void *)&sock_opt, sizeof(sock_opt));
doc/guides/rel_notes/release_21_05.rst New Features
Quoted 10 lines
doc/guides/rel_notes/release_21_05.rst +10
-0+ if (ret < 0) { + AF_XDP_LOG(DEBUG, "Failed to set SO_PREFER_BUSY_POLL\n"); + goto err_prefer; + } + + sock_opt = ETH_AF_XDP_DFLT_BUSY_TIMEOUT; + ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void *)&sock_opt, + sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(DEBUG, "Failed to set SO_BUSY_POLL\n");
[1]
doc/guides/rel_notes/release_21_05.rst
Quoted 8 lines
doc/guides/rel_notes/release_21_05.rst +8
-0+ goto err_timeout; + } + + sock_opt = rxq->busy_budget; + ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL_BUDGET, + (void *)&sock_opt, sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(DEBUG, "Failed to set SO_BUSY_POLL_BUDGET\n");
In above [1] and here, shouldn't the function return error, even the rollback is successful. I am thinking a case an invalid 'busy_budget' provided, like a very big number or negative value.
Quoted 31 lines
doc/guides/rel_notes/release_21_05.rst +31
-0+ } else { + AF_XDP_LOG(INFO, "Busy polling budget set to: %u\n", + rxq->busy_budget); + return 0; + } + + /* setsockopt failure - attempt to restore xsk to default state and + * proceed without busy polling support. + */ + sock_opt = 0; + ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void *)&sock_opt, + sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(ERR, "Failed to unset SO_BUSY_POLL\n"); + return -1; + } + +err_timeout: + sock_opt = 0; + ret = setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL, + (void *)&sock_opt, sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(ERR, "Failed to unset SO_PREFER_BUSY_POLL\n"); + return -1; + } + +err_prefer: + rxq->busy_budget = 0; + return 0; +} +
<...>
Re: [dpdk-dev] [PATCH v2 3/3] net/af_xdp: preferred busy polling
Quoted 77 lines · Ciara Loftus
Quoted 24 lines
This commit introduces support for preferred busy polling to the
AF_XDPPMD. This feature aims to improve single-core performance forAF_XDPsockets under heavy load.A new vdev arg is introduced called '
busy_budget' whose default value is 64.busy_budgetis the value supplied to the kernel with theSO_BUSY_POLL_BUDGETsocket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee
/sys/class/net/eth0/napi_defer_hard_irqsecho 200000 | sudo tee/sys/class/net/eth0/gro_flush_timeout.. where eth0 is the interface being used by the PMD.
Signed-off-by Ciara Loftus <[email protected]><...>
doc/guides/rel_notes/release_21_05.rst New Features · line 77
Quoted 11 lines
doc/guides/rel_notes/release_21_05.rst +4
-0@@ -70,6 +70,10 @@ New Features * Added command to display Rx queue used descriptor count. ``show port (port_id) rxq (queue_id) desc used count`` +* **Updated the AF_XDP driver.** + + * Added support for preferred busy polling. +Can you please move the update after above the testpmd updates? For more details the expected order is in the section comment.
doc/guides/rel_notes/release_21_05.rst New Features
Quoted 11 lines
doc/guides/rel_notes/release_21_05.rst +11
-0+static int +configure_preferred_busy_poll(struct pkt_rx_queue *rxq) +{ + int sock_opt = 1; + int fd = xsk_socket__fd(rxq->xsk); + int ret = 0; + + ret = setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL, + (void *)&sock_opt, sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(DEBUG, "Failed to setSO_PREFER_BUSY_POLL\n");
doc/guides/rel_notes/release_21_05.rst
Quoted 5 lines
doc/guides/rel_notes/release_21_05.rst +5
-0+ goto err_prefer; + } + + sock_opt = ETH_AF_XDP_DFLT_BUSY_TIMEOUT; + ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void*)&sock_opt,
doc/guides/rel_notes/release_21_05.rst
Quoted 3 lines
doc/guides/rel_notes/release_21_05.rst +3
-0+ sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(DEBUG, "Failed to set SO_BUSY_POLL\n");[1]
doc/guides/rel_notes/release_21_05.rst
Quoted 8 lines
doc/guides/rel_notes/release_21_05.rst +8
-0+ goto err_timeout; + } + + sock_opt = rxq->busy_budget; + ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL_BUDGET, + (void *)&sock_opt, sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(DEBUG, "Failed to setSO_BUSY_POLL_BUDGET\n");
Quoted 5 lines
In above [1] and here, shouldn't the function return error, even the rollback is
successful.
I am thinking a case an invalid 'busy_budget' provided, like a very big number or negative value.
How about introducing a check when parsing the argument at init and failing then, instead of here?
In that case if we fail here it should not be due to invalid value. It would be due to insufficient permissions.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/core/sock.c?h=v5.11#n1150
In that case I think issuing a log, rolling back and continuing with setup would be best, instead of returning an error and aborting and forcing the user to explicitly disable busy polling via busy_budget=0 in order to get the PMD to initialize.
Quoted 36 lines
doc/guides/rel_notes/release_21_05.rst
Quoted 12 lines
doc/guides/rel_notes/release_21_05.rst +11
-0+ } else { + AF_XDP_LOG(INFO, "Busy polling budget set to: %u\n", + rxq->busy_budget); + return 0; + } + + /* setsockopt failure - attempt to restore xsk to default state and + * proceed without busy polling support. + */ + sock_opt = 0; + ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void*)&sock_opt,
doc/guides/rel_notes/release_21_05.rst
Quoted 12 lines
doc/guides/rel_notes/release_21_05.rst +12
-0+ sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(ERR, "Failed to unset SO_BUSY_POLL\n"); + return -1; + } + +err_timeout: + sock_opt = 0; + ret = setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL, + (void *)&sock_opt, sizeof(sock_opt)); + if (ret < 0) { + AF_XDP_LOG(ERR, "Failed to unsetSO_PREFER_BUSY_POLL\n");
Quoted 8 lines
doc/guides/rel_notes/release_21_05.rst +8
-0+ return -1; + } + +err_prefer: + rxq->busy_budget = 0; + return 0; +} +<...>
v3 cover AF_XDP Preferred Busy Polling
In reply to Ciara LoftusSingle-core performance of AF_XDP at high loads can be poor because a heavily loaded NAPI context will never enter or allow for busy-polling.
1C testpmd rxonly (both IRQs and PMD on core 0):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=1 -- \
--forward-mode=rxonly
0.088Mpps
In order to achieve decent performance at high loads, it is currently recommended ensure the IRQs for the netdev queue and the core running the PMD are different.
2C testpmd rxonly (IRQs on core 0, PMD on core 1):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=0 -- \
--forward-mode=rxonly
19.26Mpps
However using an extra core is of course not ideal. The SO_PREFER_BUSY_POLL socket option was introduced in kernel v5.11 to help improve 1C performance. See [1].
This series sets this socket option on xsks created with DPDK (ie. instances of the AF_XDP PMD) unless explicitly disabled or not supported by the kernel. It was chosen to be enabled by default in order to bring the AF_XDP PMD in line with most other PMDs which execute on a single core.
The following system and netdev settings are recommended in conjunction with busy polling:
echo 2 | sudo tee /sys/class/net/eth0/napi_defer_hard_irqs
echo 200000 | sudo tee /sys/class/net/eth0/gro_flush_timeout
Re-running the 1C test with busy polling support and the above settings:
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=1 -- \
--forward-mode=rxonly
10.45Mpps
A new vdev arg is introduced called 'busy_budget' whose default value is 64. busy_budget is the value supplied to the kernel with the SO_BUSY_POLL_BUDGET socket option and represents the busy-polling NAPI budget ie. the number of packets the kernel will attempt to process in the netdev's NAPI context.
To set the busy budget to 256:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=256 14.06Mpps
If you still wish to run using 2 cores (one for PMD once for IRQs) it is recommended to disable busy polling to achieve optimal 2C performance:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=0 19.09Mpps
v2->v3:
* Moved release notes update to correct location
* Changed busy_budget from uint32_t to int since this is the type expected by setsockopt
* Validate busy_budget arg is <= UINT16_MAX during parse
v1->v2:
* Set batch size to default size of ring (2048)
* Split batches > 2048 into multiples of 2048 or less and process all packets in the same manner that is done for other drivers eg. ixgbe:
http://code.dpdk.org/dpdk/v21.02/source/drivers/net/ixgbe/ixgbe_rxtx.c#L318
* Update commit log with reasoning behing batching changes
* Update release notes with note on busy polling support
* Fix return type for sycall_needed function when the wakeup flag is not present
* Apprpriate log leveling
* Set default_*xportconf burst sizes to the default busy budget size (64)
* Detect support for busy polling via setsockopt instead of using the presence of the flag
RFC->v1:
* Fixed behaviour of busy_budget=0
* Ensure we bail out any of the new setsockopts fail
[1] https://lwn.net/Articles/837010/
Ciara Loftus (3):
net/af_xdp: allow bigger batch sizes
net/af_xdp: Use recvfrom() instead of poll()
net/af_xdp: preferred busy polling
doc/guides/nics/af_xdp.rst | 38 ++++- doc/guides/rel_notes/release_21_05.rst | 4 + drivers/net/af_xdp/compat.h | 14 ++ drivers/net/af_xdp/rte_eth_af_xdp.c | 208 ++++++++++++++++++++++--- 4 files changed, 240 insertions(+), 24 deletions(-)
Signature · 1 line
2.17.1
PATCH v3 1/3 net/af_xdp: allow bigger batch sizes
Prior to this commit, the maximum batch sizes for zero-copy and copy-mode rx and copy-mode tx were set to 32. Apart from zero-copy tx, the user could never rx/tx any more than 32 packets at a time and without inspecting the code the user wouldn't be aware of this.
This commit removes these upper limits placed on the user and instead sets an internal batch size equal to the default ring size (2048). Batches larger than this are still processed, however they are split into smaller batches similar to how it's done in other drivers. This is necessary because some arrays used during rx/tx need to be sized at compile-time.
Allowing a larger batch size allows for fewer batches and thus larger bulk operations, fewer ring accesses and fewer syscalls which should yield improved performance.
--- drivers/net/af_xdp/rte_eth_af_xdp.c | 67 ++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 10 deletions(-)
drivers/net/af_xdp/rte_eth_af_xdp.c +57 -10
@@ -66,8 +66,8 @@ RTE_LOG_REGISTER(af_xdp_logtype, pmd.net.af_xdp, NOTICE);#define ETH_AF_XDP_DFLT_START_QUEUE_IDX 0#define ETH_AF_XDP_DFLT_QUEUE_COUNT 1 -#define ETH_AF_XDP_RX_BATCH_SIZE 32 -#define ETH_AF_XDP_TX_BATCH_SIZE 32 +#define ETH_AF_XDP_RX_BATCH_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCS +#define ETH_AF_XDP_TX_BATCH_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCSstruct xsk_umem_info {
@@ -329,8 +329,7 @@ af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)struct rte_mbuf *mbufs[ETH_AF_XDP_RX_BATCH_SIZE ];if (xsk_prod_nb_free (fq, free_thresh) >= free_thresh) - (void )reserve_fill_queue (umem,ETH_AF_XDP_RX_BATCH_SIZE , -NULL , fq); + (void )reserve_fill_queue (umem, nb_pkts,NULL , fq); nb_pkts =xsk_ring_cons__peek (rx, nb_pkts, &idx_rx);if (nb_pkts ==0 ) {
@@ -379,10 +378,8 @@ af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)#endif static uint16_t -eth_af_xdp_rx (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) +af_xdp_rx (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) { - nb_pkts =RTE_MIN (nb_pkts,ETH_AF_XDP_RX_BATCH_SIZE ); -#if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG )return af_xdp_rx_zc (queue, bufs, nb_pkts);#else
@@ -390,6 +387,32 @@ eth_af_xdp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)#endif } +static uint16_t +eth_af_xdp_rx (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) +{ +uint16_t nb_rx; + +if (likely (nb_pkts <=ETH_AF_XDP_RX_BATCH_SIZE )) +return af_xdp_rx (queue, bufs, nb_pkts); + +/* Split larger batch into smaller batches of size +* ETH_AF_XDP_RX_BATCH_SIZE or less. +*/ + nb_rx =0 ; +while (nb_pkts) { +uint16_t ret, n; + + n = (uint16_t )RTE_MIN (nb_pkts,ETH_AF_XDP_RX_BATCH_SIZE ); + ret =af_xdp_rx (queue, &bufs[nb_rx], n); + nb_rx = (uint16_t )(nb_rx + ret); + nb_pkts = (uint16_t )(nb_pkts - ret); +if (ret < n) +break ; + } + +return nb_rx; +} +static void pull_umem_cq (struct xsk_umem_info *umem,int size,struct xsk_ring_cons *cq) {
@@ -535,8 +558,6 @@ af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)uint32_t idx_tx;struct xsk_ring_cons *cq = &txq->pair->cq; - nb_pkts =RTE_MIN (nb_pkts,ETH_AF_XDP_TX_BATCH_SIZE ); -pull_umem_cq (umem, nb_pkts, cq); nb_pkts = rte_ring_dequeue_bulk(umem->buf_ring, addrs,
@@ -575,6 +596,32 @@ af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)return nb_pkts; } + +static uint16_t +af_xdp_tx_cp_batch (void *queue,struct rte_mbuf **bufs,uint16_t nb_pkts) +{ +uint16_t nb_tx; + +if (likely (nb_pkts <=ETH_AF_XDP_TX_BATCH_SIZE )) +return af_xdp_tx_cp (queue, bufs, nb_pkts); + + nb_tx =0 ; +while (nb_pkts) { +uint16_t ret, n; + +/* Split larger batch into smaller batches of size +* ETH_AF_XDP_TX_BATCH_SIZE or less. +*/ + n = (uint16_t )RTE_MIN (nb_pkts,ETH_AF_XDP_TX_BATCH_SIZE ); + ret =af_xdp_tx_cp (queue, &bufs[nb_tx], n); + nb_tx = (uint16_t )(nb_tx + ret); + nb_pkts = (uint16_t )(nb_pkts - ret); +if (ret < n) +break ; + } + +return nb_tx; +}#endif static uint16_t
@@ -583,7 +630,7 @@ eth_af_xdp_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)#if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG )return af_xdp_tx_zc (queue, bufs, nb_pkts);#else -return af_xdp_tx_cp (queue, bufs, nb_pkts); +return af_xdp_tx_cp_batch (queue, bufs, nb_pkts);#endif }
Signature · 1 line
2.17.1
PATCH v3 2/3 net/af_xdp: Use recvfrom() instead of poll()
In reply to Ciara Loftuspoll() is more expensive and requires more tuning when used with the upcoming busy polling functionality.
--- drivers/net/af_xdp/rte_eth_af_xdp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/af_xdp/rte_eth_af_xdp.c +4 -2
@@ -263,7 +263,8 @@ af_xdp_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)if (nb_pkts ==0 ) {#if defined(XDP_USE_NEED_WAKEUP )if (xsk_ring_prod__needs_wakeup (fq)) - (void )poll (rxq->fds,1 ,1000 ); +recvfrom (xsk_socket__fd (rxq->xsk),NULL ,0 , +MSG_DONTWAIT ,NULL ,NULL );#endif return 0 ;
@@ -335,7 +336,8 @@ af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)if (nb_pkts ==0 ) {#if defined(XDP_USE_NEED_WAKEUP )if (xsk_ring_prod__needs_wakeup (fq)) - (void )poll (rxq->fds,1 ,1000 ); +recvfrom (xsk_socket__fd (rxq->xsk),NULL ,0 , +MSG_DONTWAIT ,NULL ,NULL );#endif return 0 ; }
Signature · 1 line
2.17.1
PATCH v3 3/3 net/af_xdp: preferred busy polling
In reply to Ciara LoftusThis commit introduces support for preferred busy polling to the AF_XDP PMD. This feature aims to improve single-core performance for AF_XDP sockets under heavy load.
A new vdev arg is introduced called 'busy_budget' whose default value is 64. busy_budget is the value supplied to the kernel with the SO_BUSY_POLL_BUDGET socket option and represents the busy-polling NAPI budget. To set the budget to a different value eg. 256:
--vdev=net_af_xdp0,iface=eth0,busy_budget=256
Preferred busy polling is enabled by default provided a kernel with version >= v5.11 is in use. To disable it, set the budget to zero.
The following settings are also strongly recommended to be used in conjunction with this feature:
echo 2 | sudo tee /sys/class/net/eth0/napi_defer_hard_irqs echo 200000 | sudo tee /sys/class/net/eth0/gro_flush_timeout
.. where eth0 is the interface being used by the PMD.
--- doc/guides/nics/af_xdp.rst | 38 ++++++- doc/guides/rel_notes/release_21_05.rst | 4 + drivers/net/af_xdp/compat.h | 14 +++ drivers/net/af_xdp/rte_eth_af_xdp.c | 135 +++++++++++++++++++++++-- 4 files changed, 179 insertions(+), 12 deletions(-)
doc/guides/nics/af_xdp.rst +37 -1
@@ -35,6 +35,7 @@ The following options can be provided to set up an af_xdp port in DPDK. * ``shared_umem`` - PMD will attempt to share UMEM with others (optional, default 0); * ``xdp_prog`` - path to custom xdp program (optional, default none); +* ``busy_budget`` - busy polling budget (optional, default 64); Prerequisites -------------
@@ -51,6 +52,7 @@ This is a Linux-specific PMD, thus the following prerequisites apply: * For shared_umem, it requires kernel version v5.10 or later and libbpf version v0.2.0 or later. * For 32-bit OS, a kernel with version 5.4 or later is required. +* For busy polling, kernel version v5.11 or later is required. Set up an af_xdp interface -----------------------------
@@ -107,4 +109,38 @@ Limitations .. code-block:: console --vdev net_af_xdp0,iface=ens786f1,shared_umem=1 \ - --vdev net_af_xdp1,iface=ens786f2,shared_umem=1 \ + --vdev net_af_xdp1,iface=ens786f2,shared_umem=1 \ + +- **Preferred Busy Polling** + + The SO_PREFER_BUSY_POLL socket option was introduced in kernel v5.11. It can + deliver a performance improvement for sockets with heavy traffic loads and + can significantly improve single-core performance in this context. + + The feature is enabled by default in the AF_XDP PMD. To disable it, set the + 'busy_budget' vdevarg to zero: + + .. code-block:: console + + --vdev net_af_xdp0,iface=ens786f1,busy_budget=0 + + The default 'busy_budget' is 64 and it represents the number of packets the + kernel will attempt to process in the netdev's NAPI context. You can change + the value for example to 256 like so: + + .. code-block:: console + + --vdev net_af_xdp0,iface=ens786f1,busy_budget=256 + + It is also strongly recommended to set the following for optimal performance: + + .. code-block:: console + + echo 2 | sudo tee /sys/class/net/ens786f1/napi_defer_hard_irqs + echo 200000 | sudo tee /sys/class/net/ens786f1/gro_flush_timeout + + The above defers interrupts for interface ens786f1 and instead schedules its + NAPI context from a watchdog timer instead of from softirqs. More information + on this feature can be found at [1]. + + [1] https://lwn.net/Articles/837010/
doc/guides/rel_notes/release_21_05.rst +4 -0
@@ -65,6 +65,10 @@ New Features * Added support for txgbevf PMD. +* **Updated the AF_XDP driver.** + + * Added support for preferred busy polling. + * **Updated testpmd.** * Added command to display Rx queue used descriptor count.
drivers/net/af_xdp/compat.h +14 -0
@@ -39,3 +39,17 @@ create_shared_socket(struct xsk_socket **xsk_ptr __rte_unused,return -1 ; }#endif + +#ifdef XDP_USE_NEED_WAKEUP +static int +syscall_needed (struct xsk_ring_prod *q,uint32_t busy_budget) +{ +return xsk_ring_prod__needs_wakeup (q) | busy_budget; +} +#else +static int +syscall_needed(struct xsk_ring_prod *q __rte_unused, uint32_t busy_budget) +{ +return busy_budget; +} +#endif
drivers/net/af_xdp/rte_eth_af_xdp.c +124 -11
255 lines not on this page · raw message
Signature · 1 line
2.17.1
Quoted 74 lines · Ciara Loftus
Single-core performance of
AF_XDPat high loads can be poor because a heavily loaded NAPI context will never enter or allow for busy-polling.1C testpmd rxonly (both IRQs and PMD on core 0):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=1 -- \
--forward-mode=rxonly
0.088MppsIn order to achieve decent performance at high loads, it is currently recommended ensure the IRQs for the netdev queue and the core running the PMD are different.
2C testpmd rxonly (IRQs on core 0, PMD on core 1):
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=0 -- \
--forward-mode=rxonly
19.26MppsHowever using an extra core is of course not ideal. The
SO_PREFER_BUSY_POLLsocket option was introduced in kernel v5.11 to help improve 1C performance. See [1].This series sets this socket option on xsks created with DPDK (ie. instances of the
AF_XDPPMD) unless explicitly disabled or not supported by the kernel. It was chosen to be enabled by default in order to bring theAF_XDPPMD in line with most other PMDs which execute on a single core.The following system and netdev settings are recommended in conjunction with busy polling:
echo 2 | sudo tee/sys/class/net/eth0/napi_defer_hard_irqs
echo 200000 | sudo tee/sys/class/net/eth0/gro_flush_timeoutRe-running the 1C test with busy polling support and the above settings:
./dpdk-testpmd -l 0-1 --vdev=net_af_xdp0,iface=eth0 --main-lcore=1 -- \
--forward-mode=rxonly
10.45MppsA new vdev arg is introduced called '
busy_budget' whose default value is 64.busy_budgetis the value supplied to the kernel with theSO_BUSY_POLL_BUDGETsocket option and represents the busy-polling NAPI budget ie. the number of packets the kernel will attempt to process in the netdev's NAPI context.To set the busy budget to 256:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=256 14.06MppsIf you still wish to run using 2 cores (one for PMD once for IRQs) it is recommended to disable busy polling to achieve optimal 2C performance:
./dpdk-testpmd --vdev=net_af_xdp0,iface=eth0,busy_budget=0 19.09Mpps
v2->v3:
* Moved release notes update to correct location
* Changedbusy_budgetfromuint32_tto int since this is the type expected by setsockopt
* Validatebusy_budgetarg is <=UINT16_MAXduring parse
v1->v2:
* Set batch size to default size of ring (2048)
* Split batches > 2048 into multiples of 2048 or less and process all packets in the same manner that is done for other drivers eg. ixgbe:
http://code.dpdk.org/dpdk/v21.02/source/drivers/net/ixgbe/ixgbe_rxtx.c#L318
* Update commit log with reasoning behing batching changes
* Update release notes with note on busy polling support
* Fix return type forsycall_neededfunction when the wakeup flag is not present
* Apprpriate log leveling
* Set default_*xportconf burst sizes to the default busy budget size (64)
* Detect support for busy polling via setsockopt instead of using the presence of the flag
RFC->v1:
* Fixed behaviour of busy_budget=0
* Ensure we bail out any of the new setsockopts fail
Quoted 8 lines
[1] https://lwn.net/Articles/837010/
Ciara Loftus (3):
net/af_xdp: allow bigger batch sizes
net/af_xdp: Userecvfrom()instead ofpoll()
net/af_xdp: preferred busy polling
for series,
Series applied to dpdk-next-net/main, thanks.