net: stmmac: RX performance improvement
Subsystems (5)
v2 cover net: stmmac: RX performance improvement
This series improves RX performance a lot, ~34% TCP RX throughput boost has been observed with DWXGMAC CORE 3.20a running on Cortex-A65 CPUs:
from 2.18 Gbits/sec increased to 2.92 Gbits/sec.
---
Changes in v2:
1. No cache prefetch for frags (Alexander Lobakin)
2. Fix code style warning reported by netdev CI on Patchwork
v1: https://patchwork.kernel.org/project/netdevbpf/list/?series=924103&state=%2A&archive=both
---
Furong Xu (3):
net: stmmac: Switch to zero-copy in non-XDP RX path
net: stmmac: Set page_pool_params.max_len to a precise size
net: stmmac: Optimize cache prefetch in RX path
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 33 +++++++++++-------- .../net/ethernet/stmicro/stmmac/stmmac_xdp.h | 1 - 3 files changed, 20 insertions(+), 15 deletions(-)
Signature · 1 line
2.34.1
PATCH v2 1/3 net: stmmac: Switch to zero-copy in non-XDP RX path
Avoid memcpy in non-XDP RX path by marking all allocated SKBs to be recycled in the upper network stack.
This patch brings ~11.5% driver performance improvement in a TCP RX throughput test with iPerf tool on a single isolated Cortex-A65 CPU core, from 2.18 Gbits/sec increased to 2.43 Gbits/sec.
--- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 26 ++++++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac.h +1 -0
@@ -126,6 +126,7 @@ struct stmmac_rx_queue {unsigned int cur_rx;unsigned int dirty_rx;unsigned int buf_alloc_num; +unsigned int napi_skb_frag_size;dma_addr_t dma_rx_phy;u32 rx_tail_addr;unsigned int state_saved;
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +17 -9
@@ -1330,7 +1330,7 @@ static unsigned int stmmac_rx_offset(struct stmmac_priv *priv)if (stmmac_xdp_is_enabled (priv))return XDP_PACKET_HEADROOM ; -return 0 ; +return NET_SKB_PAD ; }static int stmmac_set_bfsize (int mtu,int bufsize)
@@ -2029,17 +2029,21 @@ static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv,struct stmmac_channel *ch = &priv->channel[queue];bool xdp_prog =stmmac_xdp_is_enabled (priv);struct page_pool_params pp_params = {0 }; -unsigned int num_pages; +unsigned int dma_buf_sz_pad, num_pages;unsigned int napi_id;int ret; + dma_buf_sz_pad =stmmac_rx_offset (priv) + dma_conf->dma_buf_sz + +SKB_DATA_ALIGN (sizeof (struct skb_shared_info )); + num_pages =DIV_ROUND_UP (dma_buf_sz_pad,PAGE_SIZE ); + rx_q->queue_index = queue; rx_q->priv_data = priv; + rx_q->napi_skb_frag_size = num_pages *PAGE_SIZE ; pp_params.flags =PP_FLAG_DMA_MAP |PP_FLAG_DMA_SYNC_DEV ; pp_params.pool_size = dma_conf->dma_rx_size; - num_pages =DIV_ROUND_UP (dma_conf->dma_buf_sz,PAGE_SIZE ); - pp_params.order =ilog2 (num_pages); + pp_params.order =order_base_2 (num_pages); pp_params.nid =dev_to_node (priv->device); pp_params.dev = priv->device; pp_params.dma_dir = xdp_prog ?DMA_BIDIRECTIONAL :DMA_FROM_DEVICE ;
@@ -5574,22 +5578,26 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) }if (!skb) { +unsigned int head_pad_len; +/* XDP program may expand or reduce tail */ buf1_len = ctx.xdp.data_end - ctx.xdp.data; - skb =napi_alloc_skb (&ch->rx_napi, buf1_len); + skb =napi_build_skb (page_address (buf->page), + rx_q->napi_skb_frag_size);if (!skb) { +page_pool_recycle_direct (rx_q->page_pool, + buf->page); rx_dropped++; count++; goto drain_data; }/* XDP program may adjust header */ -skb_copy_to_linear_data (skb, ctx.xdp.data, buf1_len); + head_pad_len = ctx.xdp.data - ctx.xdp.data_hard_start; +skb_reserve (skb, head_pad_len);skb_put (skb, buf1_len); - -/* Data payload copied into SKB, page ready for recycle */ -page_pool_recycle_direct (rx_q->page_pool, buf->page); +skb_mark_for_recycle (skb); buf->page =NULL ; }else if (buf1_len) { dma_sync_single_for_cpu(priv->device, buf->addr,
Signature · 1 line
2.34.1
PATCH v2 2/3 net: stmmac: Set page_pool_params.max_len to a precise size
In reply to Furong XuDMA engine will always write no more than dma_buf_sz bytes of a received frame into a page buffer, the remaining spaces are unused or used by CPU exclusively.
Setting page_pool_params.max_len to almost the full size of page(s) helps nothing more, but wastes more CPU cycles on cache maintenance.
For a standard MTU of 1500, then dma_buf_sz is assigned to 1536, and this patch brings ~16.9% driver performance improvement in a TCP RX throughput test with iPerf tool on a single isolated Cortex-A65 CPU core, from 2.43 Gbits/sec increased to 2.84 Gbits/sec.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1 -1
@@ -2048,7 +2048,7 @@ static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, pp_params.dev = priv->device; pp_params.dma_dir = xdp_prog ?DMA_BIDIRECTIONAL :DMA_FROM_DEVICE ; pp_params.offset =stmmac_rx_offset (priv); - pp_params.max_len =STMMAC_MAX_RX_BUF_SIZE (num_pages); + pp_params.max_len = dma_conf->dma_buf_sz; rx_q->page_pool =page_pool_create (&pp_params);if (IS_ERR (rx_q->page_pool)) {
drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.h +0 -1
@@ -4,7 +4,6 @@#ifndef _STMMAC_XDP_H_#define _STMMAC_XDP_H_ -#define STMMAC_MAX_RX_BUF_SIZE (num) (((num) * PAGE_SIZE) - XDP_PACKET_HEADROOM)#define STMMAC_RX_DMA_ATTR (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING) int stmmac_xdp_setup_pool(struct stmmac_priv *priv, struct xsk_buff_pool *pool,
Signature · 1 line
2.34.1
PATCH v2 3/3 net: stmmac: Optimize cache prefetch in RX path
In reply to Furong XuCurrent code prefetches cache lines for the received frame first, and then dma_sync_single_for_cpu() against this frame, this is wrong. Cache prefetch should be triggered after dma_sync_single_for_cpu().
This patch brings ~2.8% driver performance improvement in a TCP RX throughput test with iPerf tool on a single isolated Cortex-A65 CPU core, 2.84 Gbits/sec increased to 2.92 Gbits/sec.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1 -4
@@ -5500,10 +5500,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)/* Buffer is good. Go on. */ -prefetch (page_address (buf->page) + buf->page_offset); -if (buf->sec_page) -prefetch (page_address (buf->sec_page)); - buf1_len =stmmac_rx_buf1_len (priv, p, status, len); len += buf1_len; buf2_len =stmmac_rx_buf2_len (priv, p, status, len);
@@ -5525,6 +5521,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)dma_sync_single_for_cpu (priv->device, buf->addr, buf1_len, dma_dir); +prefetch (page_address (buf->page) + buf->page_offset);xdp_init_buff (&ctx.xdp, buf_sz, &rx_q->xdp_rxq); xdp_prepare_buff(&ctx.xdp, page_address(buf->page),
Signature · 1 line
2.34.1
Re: [PATCH net-next v2 3/3] net: stmmac: Optimize cache prefetch in RX path
Quoted 29 lines · Furong Xu
Current code prefetches cache lines for the received frame first, and then
dma_sync_single_for_cpu()against this frame, this is wrong. Cache prefetch should be triggered afterdma_sync_single_for_cpu().This patch brings ~2.8% driver performance improvement in a TCP RX throughput test with iPerf tool on a single isolated Cortex-A65 CPU core, 2.84 Gbits/sec increased to 2.92 Gbits/sec.
Signed-off-by Furong Xu <[email protected]>--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +0
-4@@ -5500,10 +5500,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)/* Buffer is good. Go on. */ -prefetch (page_address (buf->page) + buf->page_offset); -if (buf->sec_page) -prefetch (page_address (buf->sec_page)); - buf1_len =stmmac_rx_buf1_len (priv, p, status, len); len += buf1_len; buf2_len =stmmac_rx_buf2_len (priv, p, status, len);
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) · line 5524
Quoted 4 lines
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1
-0@@ -5525,6 +5521,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)dma_sync_single_for_cpu (priv->device, buf->addr, buf1_len, dma_dir); +prefetch (page_address (buf->page) + buf->page_offset);
Minor nit: I've seen in other drivers authors using net_prefetch. Probably not worth a re-roll just for something this minor.
Jakub Kicinski
maintainerRe: [PATCH net-next v2 3/3] net: stmmac: Optimize cache prefetch in RX path
Quoted 8 lines · On Tue, 14 Jan 2025 15:31:05 -0800 Joe Damato wrote:
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) · line 5524
Quoted 5 lines
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1
-0@@ -5525,6 +5521,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)dma_sync_single_for_cpu (priv->device, buf->addr, buf1_len, dma_dir); +prefetch (page_address (buf->page) + buf->page_offset);Minor nit: I've seen in other drivers authors using
net_prefetch. Probably not worth a re-roll just for something this minor.
Let's respin. I don't know how likely stmmac is to be integrated into an SoC with 64B cachelines these days, but since you caught this - why not potentially save someone from investigating this later..
Signature · 1 line
pw-bot: cr
Re: [PATCH net-next v2 3/3] net: stmmac: Optimize cache prefetch in RX path
In reply to Joe DamatoQuoted 31 lines · Joe Damato
Quoted 30 lines · Furong Xu
Current code prefetches cache lines for the received frame first, and then
dma_sync_single_for_cpu()against this frame, this is wrong. Cache prefetch should be triggered afterdma_sync_single_for_cpu().This patch brings ~2.8% driver performance improvement in a TCP RX throughput test with iPerf tool on a single isolated Cortex-A65 CPU core, 2.84 Gbits/sec increased to 2.92 Gbits/sec.
Signed-off-by Furong Xu <[email protected]>--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +0
-4@@ -5500,10 +5500,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)/* Buffer is good. Go on. */ -prefetch (page_address (buf->page) + buf->page_offset); -if (buf->sec_page) -prefetch (page_address (buf->sec_page)); - buf1_len =stmmac_rx_buf1_len (priv, p, status, len); len += buf1_len; buf2_len =stmmac_rx_buf2_len (priv, p, status, len);@@ -5525,6 +5521,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
Quoted 6 lines
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) · line 5524
Quoted 3 lines
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1
-0dma_sync_single_for_cpu (priv->device, buf->addr, buf1_len, dma_dir); +prefetch (page_address (buf->page) + buf->page_offset);Minor nit: I've seen in other drivers authors using
net_prefetch. Probably not worth a re-roll just for something this minor.
After switch to net_prefetch(), I get another 4.5% throughput improvement :) Thanks! This definitely worth a v3 of this series.
pw-bot: changes-requested
Re: [PATCH net-next v2 3/3] net: stmmac: Optimize cache prefetch in RX path
Quoted 40 lines · Furong Xu
Quoted 31 lines · Joe Damato
Quoted 30 lines · Furong Xu
Current code prefetches cache lines for the received frame first, and then
dma_sync_single_for_cpu()against this frame, this is wrong. Cache prefetch should be triggered afterdma_sync_single_for_cpu().This patch brings ~2.8% driver performance improvement in a TCP RX throughput test with iPerf tool on a single isolated Cortex-A65 CPU core, 2.84 Gbits/sec increased to 2.92 Gbits/sec.
Signed-off-by Furong Xu <[email protected]>--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +0
-4@@ -5500,10 +5500,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)/* Buffer is good. Go on. */ -prefetch (page_address (buf->page) + buf->page_offset); -if (buf->sec_page) -prefetch (page_address (buf->sec_page)); - buf1_len =stmmac_rx_buf1_len (priv, p, status, len); len += buf1_len; buf2_len =stmmac_rx_buf2_len (priv, p, status, len);@@ -5525,6 +5521,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)Quoted 6 lines
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) · line 5524
Quoted 3 lines
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1
-0dma_sync_single_for_cpu (priv->device, buf->addr, buf1_len, dma_dir); +prefetch (page_address (buf->page) + buf->page_offset);Minor nit: I've seen in other drivers authors using
net_prefetch. Probably not worth a re-roll just for something this minor.
Quoted 2 lines
After switch to
net_prefetch(), I get another 4.5% throughput improvement :) Thanks! This definitely worth a v3 of this series.q
No worries. For what it's worth, it looks like there are a few other instances in this driver where net_prefetch or net_prefetchw can be used instead. That might be better as a followup / cleanup and separate from this series though.
Just thought I'd mention it as you have a way to test the improvements and I, unfortunately, do not have one of these devices.
From: Furong Xu <[email protected]>
Date: Mon, 13 Jan 2025 22:20:28 +0800
Quoted 3 lines
This series improves RX performance a lot, ~34% TCP RX throughput boost has been observed with DWXGMAC CORE 3.20a running on Cortex-A65 CPUs:
from 2.18 Gbits/sec increased to 2.92 Gbits/sec.
Series:
Thanks,
Olek