From: Jesper Dangaard Brouer <brouer@redhat.com>
To: netdev@vger.kernel.org, "David S. Miller" <davem@davemloft.net>
Cc: eugenia@mellanox.com, Alexander Duyck <alexander.duyck@gmail.com>,
alexei.starovoitov@gmail.com, saeedm@mellanox.com,
Jesper Dangaard Brouer <brouer@redhat.com>,
gerlitz.or@gmail.com
Subject: [net-next PATCH 3/7] net: bulk alloc and reuse of SKBs in NAPI context
Date: Fri, 04 Mar 2016 14:01:43 +0100 [thread overview]
Message-ID: <20160304130143.32651.33813.stgit@firesoul> (raw)
In-Reply-To: <20160304130054.32651.51776.stgit@firesoul>
This patch introduce bulk alloc of SKBs and allow reuse of SKBs
free'ed in same softirq cycle. SKBs are normally free'ed during TX
completion, but most high speed drivers also cleanup TX ring during
NAPI RX poll cycle. Thus, if using napi_consume_skb/__kfree_skb_defer,
SKBs will be avail in the napi_alloc_cache->skb_cache.
If no SKBs are avail for reuse, then only bulk alloc 8 SKBs, to limit
the potential overshooting unused SKBs needed to free'ed when NAPI
cycle ends (flushed in net_rx_action via __kfree_skb_flush()).
Generalize ___build_skb() to allow passing it a preallocated SKB.
I've previously demonstrated a 1% speedup for IPv4 forwarding, when
used on the ixgbe driver. If SKB alloc and free happens on different
CPUs (like in RPS use-case) the performance benefit is expected to
increase.
All drivers using the napi_alloc_skb() call will benefit from
this change automatically.
Joint work with Alexander Duyck.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
---
net/core/skbuff.c | 71 ++++++++++++++++++++++++++++++++++-------------------
1 file changed, 45 insertions(+), 26 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 7af7ec635d90..96fb7933b614 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -281,32 +281,14 @@ nodata:
}
EXPORT_SYMBOL(__alloc_skb);
-/**
- * __build_skb - build a network buffer
- * @data: data buffer provided by caller
- * @frag_size: size of data, or 0 if head was kmalloced
- *
- * Allocate a new &sk_buff. Caller provides space holding head and
- * skb_shared_info. @data must have been allocated by kmalloc() only if
- * @frag_size is 0, otherwise data should come from the page allocator
- * or vmalloc()
- * The return is the new skb buffer.
- * On a failure the return is %NULL, and @data is not freed.
- * Notes :
- * Before IO, driver allocates only data buffer where NIC put incoming frame
- * Driver should add room at head (NET_SKB_PAD) and
- * MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
- * After IO, driver calls build_skb(), to allocate sk_buff and populate it
- * before giving packet to stack.
- * RX rings only contains data buffers, not full skbs.
- */
-struct sk_buff *__build_skb(void *data, unsigned int frag_size)
+/* Allows skb being (pre)allocated by caller */
+static inline
+struct sk_buff *___build_skb(void *data, unsigned int frag_size,
+ struct sk_buff *skb)
{
struct skb_shared_info *shinfo;
- struct sk_buff *skb;
unsigned int size = frag_size ? : ksize(data);
- skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
if (!skb)
return NULL;
@@ -331,6 +313,34 @@ struct sk_buff *__build_skb(void *data, unsigned int frag_size)
return skb;
}
+/**
+ * __build_skb - build a network buffer
+ * @data: data buffer provided by caller
+ * @frag_size: size of data, or 0 if head was kmalloced
+ *
+ * Allocate a new &sk_buff. Caller provides space holding head and
+ * skb_shared_info. @data must have been allocated by kmalloc() only if
+ * @frag_size is 0, otherwise data should come from the page allocator
+ * or vmalloc()
+ * The return is the new skb buffer.
+ * On a failure the return is %NULL, and @data is not freed.
+ * Notes :
+ * Before IO, driver allocates only data buffer where NIC put incoming frame
+ * Driver should add room at head (NET_SKB_PAD) and
+ * MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
+ * After IO, driver calls build_skb(), to allocate sk_buff and populate it
+ * before giving packet to stack.
+ * RX rings only contains data buffers, not full skbs.
+ */
+struct sk_buff *__build_skb(void *data, unsigned int frag_size)
+{
+ struct sk_buff *skb;
+ unsigned int size = frag_size ? : ksize(data);
+
+ skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
+ return ___build_skb(data, size, skb);
+}
+
/* build_skb() is wrapper over __build_skb(), that specifically
* takes care of skb->head and skb->pfmemalloc
* This means that if @frag_size is not zero, then @data must be backed
@@ -490,8 +500,8 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
len += NET_SKB_PAD + NET_IP_ALIGN;
- if ((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) ||
- (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
+ if (unlikely((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) ||
+ (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA)))) {
skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
if (!skb)
goto skb_fail;
@@ -508,11 +518,20 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
if (unlikely(!data))
return NULL;
- skb = __build_skb(data, len);
- if (unlikely(!skb)) {
+#define BULK_ALLOC_SIZE 8
+ if (!nc->skb_count) {
+ nc->skb_count = kmem_cache_alloc_bulk(skbuff_head_cache,
+ gfp_mask, BULK_ALLOC_SIZE,
+ nc->skb_cache);
+ }
+ if (likely(nc->skb_count)) {
+ skb = (struct sk_buff *)nc->skb_cache[--nc->skb_count];
+ } else {
+ /* alloc bulk failed */
skb_free_frag(data);
return NULL;
}
+ skb = ___build_skb(data, len, skb);
/* use OR instead of assignment to avoid clearing of bits in mask */
if (nc->page.pfmemalloc)
next prev parent reply other threads:[~2016-03-04 13:01 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-04 13:01 [net-next PATCH 0/7] net: bulk alloc side and more bulk free drivers Jesper Dangaard Brouer
2016-03-04 13:01 ` [net-next PATCH 1/7] mlx5: use napi_consume_skb API to get bulk free operations Jesper Dangaard Brouer
2016-03-04 13:01 ` [net-next PATCH 2/7] mlx4: " Jesper Dangaard Brouer
2016-03-08 19:24 ` David Miller
2016-03-09 11:00 ` Jesper Dangaard Brouer
2016-03-09 16:47 ` Alexander Duyck
2016-03-09 21:03 ` David Miller
2016-03-09 21:36 ` Jesper Dangaard Brouer
2016-03-09 21:43 ` Alexander Duyck
2016-03-09 21:47 ` Jesper Dangaard Brouer
2016-03-09 22:07 ` Alexander Duyck
2016-03-10 12:15 ` [net-next PATCH V2 0/3] net: bulk free adjustment and two driver use-cases Jesper Dangaard Brouer
2016-03-10 12:15 ` [net-next PATCH V2 1/3] net: adjust napi_consume_skb to handle none-NAPI callers Jesper Dangaard Brouer
2016-03-10 12:15 ` [net-next PATCH V2 2/3] mlx4: use napi_consume_skb API to get bulk free operations Jesper Dangaard Brouer
2016-03-10 13:59 ` Sergei Shtylyov
2016-03-10 14:59 ` [net-next PATCH V3 0/3] net: bulk free adjustment and two driver use-cases Jesper Dangaard Brouer
2016-03-10 14:59 ` [net-next PATCH V3 1/3] net: adjust napi_consume_skb to handle none-NAPI callers Jesper Dangaard Brouer
2016-03-10 17:21 ` Sergei Shtylyov
2016-03-11 7:45 ` Jesper Dangaard Brouer
2016-03-11 8:43 ` [net-next PATCH V4 0/3] net: bulk free adjustment and two driver use-cases Jesper Dangaard Brouer
2016-03-11 8:43 ` [net-next PATCH V4 1/3] net: adjust napi_consume_skb to handle non-NAPI callers Jesper Dangaard Brouer
2016-03-11 8:44 ` [net-next PATCH V4 2/3] mlx4: use napi_consume_skb API to get bulk free operations Jesper Dangaard Brouer
2016-03-11 8:44 ` [net-next PATCH V4 3/3] mlx5: " Jesper Dangaard Brouer
2016-03-14 2:35 ` [net-next PATCH V4 0/3] net: bulk free adjustment and two driver use-cases David Miller
2016-03-10 14:59 ` [net-next PATCH V3 2/3] mlx4: use napi_consume_skb API to get bulk free operations Jesper Dangaard Brouer
2016-03-10 14:59 ` [net-next PATCH V3 3/3] mlx5: " Jesper Dangaard Brouer
2016-03-10 12:15 ` [net-next PATCH V2 " Jesper Dangaard Brouer
2016-03-04 13:01 ` Jesper Dangaard Brouer [this message]
2016-03-13 14:06 ` [net-next PATCH 3/7] net: bulk alloc and reuse of SKBs in NAPI context Rana Shahout
2016-03-14 6:55 ` Jesper Dangaard Brouer
2016-03-04 13:01 ` [net-next PATCH 4/7] mlx5: use napi_alloc_skb API to get SKB bulk allocations Jesper Dangaard Brouer
2016-03-04 13:02 ` [net-next PATCH 5/7] mlx4: " Jesper Dangaard Brouer
2016-03-04 13:02 ` [net-next PATCH 6/7] net: introduce napi_alloc_skb_hint() for more use-cases Jesper Dangaard Brouer
2016-03-04 13:02 ` [net-next PATCH 7/7] mlx5: hint the NAPI alloc skb API about the expected bulk size Jesper Dangaard Brouer
2016-03-04 16:36 ` [net-next PATCH 0/7] net: bulk alloc side and more bulk free drivers Alexei Starovoitov
2016-03-04 19:15 ` Jesper Dangaard Brouer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160304130143.32651.33813.stgit@firesoul \
--to=brouer@redhat.com \
--cc=alexander.duyck@gmail.com \
--cc=alexei.starovoitov@gmail.com \
--cc=davem@davemloft.net \
--cc=eugenia@mellanox.com \
--cc=gerlitz.or@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=saeedm@mellanox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).