Message ID | 1426710078-11230-1-git-send-email-vadim.suraev@gmail.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers |
Return-Path: <dev-bounces@dpdk.org> X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id A39AC592B; Wed, 18 Mar 2015 21:21:34 +0100 (CET) Received: from mail-wi0-f175.google.com (mail-wi0-f175.google.com [209.85.212.175]) by dpdk.org (Postfix) with ESMTP id C1783590C for <dev@dpdk.org>; Wed, 18 Mar 2015 21:21:33 +0100 (CET) Received: by wixw10 with SMTP id w10so69842243wix.0 for <dev@dpdk.org>; Wed, 18 Mar 2015 13:21:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=MLiNLVEEkU69h5dWOm9zGqHP6m9POqKsRO3WzDuLcXI=; b=GvC/xVEnZVJTgVWvmOLmdyUdH0bNaNRZV2tMHwhJAs3FeeVV+GOKk8ucKc4AndewYA KJOip0CcHIcSlE0dkJzwkv529kJUKNZDC1GHMsVa5+L8/2lhSrzhm1M3AkycAwFcd1eo lzX1gZ/IjqkBm4reKqIk4lQQfQiGprUQ5M8gaPH3yVtTS66H9/2qxCZIsaBxsKhrLnJ8 wGML58rWuoTc2kJLCH4czkwz6ui4szDtAJDbDbRsOmYLB5pJrPL3EyXKMHTv1wgxiA4x KM6li4q9ZZ8ufacz8j+mtAXe8xDGlUFEgWWGsOkeeC/9PwTx1Ow170/laHITHbfUvfyn w8eg== X-Received: by 10.194.61.161 with SMTP id q1mr148863631wjr.132.1426710093639; Wed, 18 Mar 2015 13:21:33 -0700 (PDT) Received: from ubuntu.ubuntu-domain (bzq-79-176-41-72.red.bezeqint.net. [79.176.41.72]) by mx.google.com with ESMTPSA id n1sm4601172wib.11.2015.03.18.13.21.31 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 18 Mar 2015 13:21:32 -0700 (PDT) From: "vadim.suraev@gmail.com" <vadim.suraev@gmail.com> To: dev@dpdk.org Date: Wed, 18 Mar 2015 22:21:18 +0200 Message-Id: <1426710078-11230-1-git-send-email-vadim.suraev@gmail.com> X-Mailer: git-send-email 1.7.9.5 Subject: [dpdk-dev] [PATCH v2] rte_mbuf: mbuf bulk alloc/free functions added + unittest X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK <dev.dpdk.org> List-Unsubscribe: <http://dpdk.org/ml/options/dev>, <mailto:dev-request@dpdk.org?subject=unsubscribe> List-Archive: <http://dpdk.org/ml/archives/dev/> List-Post: <mailto:dev@dpdk.org> List-Help: <mailto:dev-request@dpdk.org?subject=help> List-Subscribe: <http://dpdk.org/ml/listinfo/dev>, <mailto:dev-request@dpdk.org?subject=subscribe> Errors-To: dev-bounces@dpdk.org Sender: "dev" <dev-bounces@dpdk.org> |
Commit Message
vadim.suraev@gmail.com
March 18, 2015, 8:21 p.m. UTC
From: "vadim.suraev@gmail.com" <vadim.suraev@gmail.com> This patch adds mbuf bulk allocation/freeing functions and unittest Signed-off-by: Vadim Suraev <vadim.suraev@gmail.com> --- New in v2: - function rte_pktmbuf_alloc_bulk added - function rte_pktmbuf_bulk_free added - function rte_pktmbuf_free_chain added - applied reviewers' comments app/test/test_mbuf.c | 94 +++++++++++++++++++++++++++++++++++++++++++- lib/librte_mbuf/rte_mbuf.h | 91 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 1 deletion(-)
Comments
On Wed, Mar 18, 2015 at 10:21:18PM +0200, vadim.suraev@gmail.com wrote: > From: "vadim.suraev@gmail.com" <vadim.suraev@gmail.com> > > This patch adds mbuf bulk allocation/freeing functions and unittest > > Signed-off-by: Vadim Suraev > <vadim.suraev@gmail.com> > --- > New in v2: > - function rte_pktmbuf_alloc_bulk added > - function rte_pktmbuf_bulk_free added > - function rte_pktmbuf_free_chain added > - applied reviewers' comments > > app/test/test_mbuf.c | 94 +++++++++++++++++++++++++++++++++++++++++++- > lib/librte_mbuf/rte_mbuf.h | 91 ++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 184 insertions(+), 1 deletion(-) > > diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c > index 1ff66cb..b20c6a4 100644 > --- a/app/test/test_mbuf.c > +++ b/app/test/test_mbuf.c > @@ -77,6 +77,7 @@ > #define REFCNT_RING_SIZE (REFCNT_MBUF_NUM * REFCNT_MAX_REF) > > #define MAKE_STRING(x) # x > +#define MBUF_POOL_LOCAL_CACHE_SIZE 32 > > static struct rte_mempool *pktmbuf_pool = NULL; > > @@ -405,6 +406,84 @@ test_pktmbuf_pool(void) > return ret; > } > ><snip> > diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h > index 17ba791..fabeae2 100644 > --- a/lib/librte_mbuf/rte_mbuf.h > +++ b/lib/librte_mbuf/rte_mbuf.h > @@ -825,6 +825,97 @@ static inline void rte_pktmbuf_free(struct rte_mbuf *m) > } > > /** > + * Allocate a bulk of mbufs, initiate refcnt and resets > + * > + * @param pool > + * memory pool to allocate from > + * @param mbufs > + * Array of pointers to mbuf > + * @param count > + * Array size > + */ > +static inline int rte_pktmbuf_alloc_bulk(struct rte_mempool *pool, > + struct rte_mbuf **mbufs, > + unsigned count) > +{ > + unsigned idx; > + int rc = 0; > + > + rc = rte_mempool_get_bulk(pool, (void **)mbufs, count); > + if (unlikely(rc)) > + return rc; > + > + for (idx = 0; idx < count; idx++) { > + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 0); > + rte_mbuf_refcnt_set(mbufs[idx], 1); > + rte_pktmbuf_reset(mbufs[idx]); > + } > + return rc; > +} > + > +/** > + * Free a bulk of mbufs into its original mempool. > + * This function assumes: > + * - refcnt equals 1 > + * - mbufs are direct > + * - all mbufs must belong to the same mempool > + * > + * @param mbufs > + * Array of pointers to mbuf > + * @param count > + * Array size > + */ > +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > + unsigned count) > +{ > + unsigned idx; > + > + RTE_MBUF_ASSERT(count > 0); > + > + for (idx = 0; idx < count; idx++) { > + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > + rte_mbuf_refcnt_set(mbufs[idx], 0); This is really a misuse of the API. The entire point of reference counting is to know when an mbuf has no more references and can be freed. By forcing all the reference counts to zero here, you allow the refcnt infrastructure to be circumvented, causing memory leaks. I think what you need to do here is enhance the underlying pktmbuf interface such that an rte_mbuf structure has a destructor method association with it which is called when its refcnt reaches zero. That way the rte_pktmbuf_bulk_free function can just decrement the refcnt on each mbuf_structure, and the pool as a whole can be returned when the destructor function discovers that all mbufs in that bulk pool are freed. Neil
Hi Neil, On 03/18/2015 09:58 PM, Neil Horman wrote: >> +/** >> + * Free a bulk of mbufs into its original mempool. >> + * This function assumes: >> + * - refcnt equals 1 >> + * - mbufs are direct >> + * - all mbufs must belong to the same mempool >> + * >> + * @param mbufs >> + * Array of pointers to mbuf >> + * @param count >> + * Array size >> + */ >> +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, >> + unsigned count) >> +{ >> + unsigned idx; >> + >> + RTE_MBUF_ASSERT(count > 0); >> + >> + for (idx = 0; idx < count; idx++) { >> + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); >> + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); >> + rte_mbuf_refcnt_set(mbufs[idx], 0); > This is really a misuse of the API. The entire point of reference counting is > to know when an mbuf has no more references and can be freed. By forcing all > the reference counts to zero here, you allow the refcnt infrastructure to be > circumvented, causing memory leaks. > > I think what you need to do here is enhance the underlying pktmbuf interface > such that an rte_mbuf structure has a destructor method association with it > which is called when its refcnt reaches zero. That way the > rte_pktmbuf_bulk_free function can just decrement the refcnt on each > mbuf_structure, and the pool as a whole can be returned when the destructor > function discovers that all mbufs in that bulk pool are freed. I don't really understand what's the problem here. The API explicitly describes the conditions for calling this functions: the segments are directs, they belong to the same mempool, and their refcnt is 1. This function could be useful in a driver which knows that the mbuf it allocated matches this conditions. I think an application that only uses direct mbufs and one mempool could also use this function. Regards, Olivier
> -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Olivier MATZ > Sent: Thursday, March 19, 2015 8:41 AM > To: Neil Horman; vadim.suraev@gmail.com > Cc: dev@dpdk.org > Subject: Re: [dpdk-dev] [PATCH v2] rte_mbuf: mbuf bulk alloc/free functions added + unittest > > Hi Neil, > > On 03/18/2015 09:58 PM, Neil Horman wrote: > >> +/** > >> + * Free a bulk of mbufs into its original mempool. > >> + * This function assumes: > >> + * - refcnt equals 1 > >> + * - mbufs are direct > >> + * - all mbufs must belong to the same mempool > >> + * > >> + * @param mbufs > >> + * Array of pointers to mbuf > >> + * @param count > >> + * Array size > >> + */ > >> +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > >> + unsigned count) > >> +{ > >> + unsigned idx; > >> + > >> + RTE_MBUF_ASSERT(count > 0); > >> + > >> + for (idx = 0; idx < count; idx++) { > >> + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > >> + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > >> + rte_mbuf_refcnt_set(mbufs[idx], 0); > > This is really a misuse of the API. The entire point of reference counting is > > to know when an mbuf has no more references and can be freed. By forcing all > > the reference counts to zero here, you allow the refcnt infrastructure to be > > circumvented, causing memory leaks. > > > > I think what you need to do here is enhance the underlying pktmbuf interface > > such that an rte_mbuf structure has a destructor method association with it > > which is called when its refcnt reaches zero. That way the > > rte_pktmbuf_bulk_free function can just decrement the refcnt on each > > mbuf_structure, and the pool as a whole can be returned when the destructor > > function discovers that all mbufs in that bulk pool are freed. > > I don't really understand what's the problem here. The API explicitly > describes the conditions for calling this functions: the segments are > directs, they belong to the same mempool, and their refcnt is 1. > > This function could be useful in a driver which knows that the mbuf > it allocated matches this conditions. I think an application that > only uses direct mbufs and one mempool could also use this function. I also don't see anything wrong with that function. As long, as user makes sure that all mbufs in the bulk satisfy the required conditions it should be ok, I think. Of course, it's usage is limited, but I suppose the author has some scenario in mind, when introduced it. Konstantin > > Regards, > Olivier
On Thu, Mar 19, 2015 at 09:41:25AM +0100, Olivier MATZ wrote: > Hi Neil, > > On 03/18/2015 09:58 PM, Neil Horman wrote: > >>+/** > >>+ * Free a bulk of mbufs into its original mempool. > >>+ * This function assumes: > >>+ * - refcnt equals 1 > >>+ * - mbufs are direct > >>+ * - all mbufs must belong to the same mempool > >>+ * > >>+ * @param mbufs > >>+ * Array of pointers to mbuf > >>+ * @param count > >>+ * Array size > >>+ */ > >>+static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > >>+ unsigned count) > >>+{ > >>+ unsigned idx; > >>+ > >>+ RTE_MBUF_ASSERT(count > 0); > >>+ > >>+ for (idx = 0; idx < count; idx++) { > >>+ RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > >>+ RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > >>+ rte_mbuf_refcnt_set(mbufs[idx], 0); > >This is really a misuse of the API. The entire point of reference counting is > >to know when an mbuf has no more references and can be freed. By forcing all > >the reference counts to zero here, you allow the refcnt infrastructure to be > >circumvented, causing memory leaks. > > > >I think what you need to do here is enhance the underlying pktmbuf interface > >such that an rte_mbuf structure has a destructor method association with it > >which is called when its refcnt reaches zero. That way the > >rte_pktmbuf_bulk_free function can just decrement the refcnt on each > >mbuf_structure, and the pool as a whole can be returned when the destructor > >function discovers that all mbufs in that bulk pool are freed. > > I don't really understand what's the problem here. The API explicitly > describes the conditions for calling this functions: the segments are > directs, they belong to the same mempool, and their refcnt is 1. > > This function could be useful in a driver which knows that the mbuf > it allocated matches this conditions. I think an application that > only uses direct mbufs and one mempool could also use this function. > That last condition is my issue with this patch, that the user has to know what refcnts are. It makes this api useful for little more than the test case that is provided with it. Its irritating enough that for singly allocated mbufs the user has to know what the refcount of a buffer is before freeing, but at least they can macrotize a {rte_pktmbuf_refcnt_update; if(rte_pktmbuf_refct_read) then free} operation. With this, you've placed the user in charge of not only doing that, but also of managing the relationship between pktmbufs and the pool they came from. while that makes sense for the test case, it really doesn't in any general use case in which packet processing is ever deferred or queued, because it means that the application is now responsible for holding a pointer to every packet it allocates and checking its refcount periodically until it completes. There is never any reason that an application won't need to do this management, so making it the purview of the application to handle rather than properly integrating that functionality in the library is really a false savings. Regards Neil > Regards, > Olivier > >
Hi Neil, On 03/19/2015 02:16 PM, Neil Horman wrote: >> On 03/18/2015 09:58 PM, Neil Horman wrote: >>>> +/** >>>> + * Free a bulk of mbufs into its original mempool. >>>> + * This function assumes: >>>> + * - refcnt equals 1 >>>> + * - mbufs are direct >>>> + * - all mbufs must belong to the same mempool >>>> + * >>>> + * @param mbufs >>>> + * Array of pointers to mbuf >>>> + * @param count >>>> + * Array size >>>> + */ >>>> +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, >>>> + unsigned count) >>>> +{ >>>> + unsigned idx; >>>> + >>>> + RTE_MBUF_ASSERT(count > 0); >>>> + >>>> + for (idx = 0; idx < count; idx++) { >>>> + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); >>>> + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); >>>> + rte_mbuf_refcnt_set(mbufs[idx], 0); >>> This is really a misuse of the API. The entire point of reference counting is >>> to know when an mbuf has no more references and can be freed. By forcing all >>> the reference counts to zero here, you allow the refcnt infrastructure to be >>> circumvented, causing memory leaks. >>> >>> I think what you need to do here is enhance the underlying pktmbuf interface >>> such that an rte_mbuf structure has a destructor method association with it >>> which is called when its refcnt reaches zero. That way the >>> rte_pktmbuf_bulk_free function can just decrement the refcnt on each >>> mbuf_structure, and the pool as a whole can be returned when the destructor >>> function discovers that all mbufs in that bulk pool are freed. >> >> I don't really understand what's the problem here. The API explicitly >> describes the conditions for calling this functions: the segments are >> directs, they belong to the same mempool, and their refcnt is 1. >> >> This function could be useful in a driver which knows that the mbuf >> it allocated matches this conditions. I think an application that >> only uses direct mbufs and one mempool could also use this function. > > > That last condition is my issue with this patch, that the user has to know what > refcnts are. It makes this api useful for little more than the test case that > is provided with it. Its irritating enough that for singly allocated mbufs the > user has to know what the refcount of a buffer is before freeing, but at least > they can macrotize a {rte_pktmbuf_refcnt_update; if(rte_pktmbuf_refct_read) then > free} operation. > > With this, you've placed the user in charge of not only doing that, but also of > managing the relationship between pktmbufs and the pool they came from. while > that makes sense for the test case, it really doesn't in any general use case in > which packet processing is ever deferred or queued, because it means that the > application is now responsible for holding a pointer to every packet it > allocates and checking its refcount periodically until it completes. > > There is never any reason that an application won't need to do this management, > so making it the purview of the application to handle rather than properly > integrating that functionality in the library is really a false savings. There are some places where you know that the prerequisites are met, so you can save cycles by using this function. From what I imagine, if in a driver you allocate mbufs, chain them and for some reason you realize you have to free them, you can use this function instead of freeing them one by one. Also, as it's up to the application to decide how many mbuf pools are created, and whether indirect mbufs are used or not, the application can take the short path of using this function in some conditions. Vadim, maybe you have another reason or use case for adding this function? Could you detail why you need it and how it improves your use case? Regards, Olivier
Hi, Olivier, No, I personally need to free a chain using mempool bulk. If I'm not mistaken, it has been proposed by one of reviewers to have lower level function, so it was done (I'm sorry if misunderstood) Regards, Vadim. On Mar 23, 2015 8:44 PM, "Olivier MATZ" <olivier.matz@6wind.com> wrote: > Hi Neil, > > On 03/19/2015 02:16 PM, Neil Horman wrote: > >> On 03/18/2015 09:58 PM, Neil Horman wrote: > >>>> +/** > >>>> + * Free a bulk of mbufs into its original mempool. > >>>> + * This function assumes: > >>>> + * - refcnt equals 1 > >>>> + * - mbufs are direct > >>>> + * - all mbufs must belong to the same mempool > >>>> + * > >>>> + * @param mbufs > >>>> + * Array of pointers to mbuf > >>>> + * @param count > >>>> + * Array size > >>>> + */ > >>>> +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > >>>> + unsigned count) > >>>> +{ > >>>> + unsigned idx; > >>>> + > >>>> + RTE_MBUF_ASSERT(count > 0); > >>>> + > >>>> + for (idx = 0; idx < count; idx++) { > >>>> + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > >>>> + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > >>>> + rte_mbuf_refcnt_set(mbufs[idx], 0); > >>> This is really a misuse of the API. The entire point of reference > counting is > >>> to know when an mbuf has no more references and can be freed. By > forcing all > >>> the reference counts to zero here, you allow the refcnt infrastructure > to be > >>> circumvented, causing memory leaks. > >>> > >>> I think what you need to do here is enhance the underlying pktmbuf > interface > >>> such that an rte_mbuf structure has a destructor method association > with it > >>> which is called when its refcnt reaches zero. That way the > >>> rte_pktmbuf_bulk_free function can just decrement the refcnt on each > >>> mbuf_structure, and the pool as a whole can be returned when the > destructor > >>> function discovers that all mbufs in that bulk pool are freed. > >> > >> I don't really understand what's the problem here. The API explicitly > >> describes the conditions for calling this functions: the segments are > >> directs, they belong to the same mempool, and their refcnt is 1. > >> > >> This function could be useful in a driver which knows that the mbuf > >> it allocated matches this conditions. I think an application that > >> only uses direct mbufs and one mempool could also use this function. > > > > > > That last condition is my issue with this patch, that the user has to > know what > > refcnts are. It makes this api useful for little more than the test > case that > > is provided with it. Its irritating enough that for singly allocated > mbufs the > > user has to know what the refcount of a buffer is before freeing, but at > least > > they can macrotize a {rte_pktmbuf_refcnt_update; > if(rte_pktmbuf_refct_read) then > > free} operation. > > > > With this, you've placed the user in charge of not only doing that, but > also of > > managing the relationship between pktmbufs and the pool they came from. > while > > that makes sense for the test case, it really doesn't in any general use > case in > > which packet processing is ever deferred or queued, because it means > that the > > application is now responsible for holding a pointer to every packet it > > allocates and checking its refcount periodically until it completes. > > > > There is never any reason that an application won't need to do this > management, > > so making it the purview of the application to handle rather than > properly > > integrating that functionality in the library is really a false savings. > > There are some places where you know that the prerequisites are met, > so you can save cycles by using this function. > > From what I imagine, if in a driver you allocate mbufs, chain them and > for some reason you realize you have to free them, you can use this > function instead of freeing them one by one. > > Also, as it's up to the application to decide how many mbuf pools are > created, and whether indirect mbufs are used or not, the application > can take the short path of using this function in some conditions. > > Vadim, maybe you have another reason or use case for adding this > function? Could you detail why you need it and how it improves your > use case? > > Regards, > Olivier >
On Mon, Mar 23, 2015 at 05:44:02PM +0100, Olivier MATZ wrote: > Hi Neil, > > On 03/19/2015 02:16 PM, Neil Horman wrote: > >> On 03/18/2015 09:58 PM, Neil Horman wrote: > >>>> +/** > >>>> + * Free a bulk of mbufs into its original mempool. > >>>> + * This function assumes: > >>>> + * - refcnt equals 1 > >>>> + * - mbufs are direct > >>>> + * - all mbufs must belong to the same mempool > >>>> + * > >>>> + * @param mbufs > >>>> + * Array of pointers to mbuf > >>>> + * @param count > >>>> + * Array size > >>>> + */ > >>>> +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > >>>> + unsigned count) > >>>> +{ > >>>> + unsigned idx; > >>>> + > >>>> + RTE_MBUF_ASSERT(count > 0); > >>>> + > >>>> + for (idx = 0; idx < count; idx++) { > >>>> + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > >>>> + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > >>>> + rte_mbuf_refcnt_set(mbufs[idx], 0); > >>> This is really a misuse of the API. The entire point of reference counting is > >>> to know when an mbuf has no more references and can be freed. By forcing all > >>> the reference counts to zero here, you allow the refcnt infrastructure to be > >>> circumvented, causing memory leaks. > >>> > >>> I think what you need to do here is enhance the underlying pktmbuf interface > >>> such that an rte_mbuf structure has a destructor method association with it > >>> which is called when its refcnt reaches zero. That way the > >>> rte_pktmbuf_bulk_free function can just decrement the refcnt on each > >>> mbuf_structure, and the pool as a whole can be returned when the destructor > >>> function discovers that all mbufs in that bulk pool are freed. > >> > >> I don't really understand what's the problem here. The API explicitly > >> describes the conditions for calling this functions: the segments are > >> directs, they belong to the same mempool, and their refcnt is 1. > >> > >> This function could be useful in a driver which knows that the mbuf > >> it allocated matches this conditions. I think an application that > >> only uses direct mbufs and one mempool could also use this function. > > > > > > That last condition is my issue with this patch, that the user has to know what > > refcnts are. It makes this api useful for little more than the test case that > > is provided with it. Its irritating enough that for singly allocated mbufs the > > user has to know what the refcount of a buffer is before freeing, but at least > > they can macrotize a {rte_pktmbuf_refcnt_update; if(rte_pktmbuf_refct_read) then > > free} operation. > > > > With this, you've placed the user in charge of not only doing that, but also of > > managing the relationship between pktmbufs and the pool they came from. while > > that makes sense for the test case, it really doesn't in any general use case in > > which packet processing is ever deferred or queued, because it means that the > > application is now responsible for holding a pointer to every packet it > > allocates and checking its refcount periodically until it completes. > > > > There is never any reason that an application won't need to do this management, > > so making it the purview of the application to handle rather than properly > > integrating that functionality in the library is really a false savings. > > There are some places where you know that the prerequisites are met, > so you can save cycles by using this function. > > From what I imagine, if in a driver you allocate mbufs, chain them and > for some reason you realize you have to free them, you can use this > function instead of freeing them one by one. > > Also, as it's up to the application to decide how many mbuf pools are > created, and whether indirect mbufs are used or not, the application > can take the short path of using this function in some conditions. > > Vadim, maybe you have another reason or use case for adding this > function? Could you detail why you need it and how it improves your > use case? > > Regards, > Olivier > So, I think we're making different points here. You seem to be justifying the API as it exists by finding use cases that fit into its documented restrictions (direct buffers, refcounts at 1, etc), which severely limit that use case set. My assertion is that those restrictions were created because it was inconvienient to code using the reference count as intended. I'm saying lets augment the reference counting mechanism so that we can use these specially allocated mbufs in a wider variety of use cases beyond the limited set they are currently good for Neil
Hi Vadim, > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Vadim Suraev > Sent: Monday, March 23, 2015 5:31 PM > To: Olivier MATZ > Cc: dev@dpdk.org > Subject: Re: [dpdk-dev] [PATCH v2] rte_mbuf: mbuf bulk alloc/free functions added + unittest > > Hi, Olivier, > No, I personally need to free a chain using mempool bulk. If I'm not > mistaken, it has been proposed by one of reviewers to have lower level > function, so it was done (I'm sorry if misunderstood) Was it me? As I remember, I said it would be good to create rte_pktmbuf_bulk_free() or rte_pktmbuf_seg_bulk_free() - that would free a bulk of mbufs segments in the same manner as rte_pktmbuf_free_chain() does: count number of consecutive mbufs from the same mempool to be freed and then put them back into the pool at one go. Such function would be useful inside PMD code. In fact we already using analogy of such function inside vPMD TX code. Though from my point, such function should be generic as rte_pktmbuf_free_chain() - no special limitations like all mbufs from one pool, refcnt==1, etc. So if it was me who confused you - I am sorry. Konstantin > Regards, > Vadim. > On Mar 23, 2015 8:44 PM, "Olivier MATZ" <olivier.matz@6wind.com> wrote: > > > Hi Neil, > > > > On 03/19/2015 02:16 PM, Neil Horman wrote: > > >> On 03/18/2015 09:58 PM, Neil Horman wrote: > > >>>> +/** > > >>>> + * Free a bulk of mbufs into its original mempool. > > >>>> + * This function assumes: > > >>>> + * - refcnt equals 1 > > >>>> + * - mbufs are direct > > >>>> + * - all mbufs must belong to the same mempool > > >>>> + * > > >>>> + * @param mbufs > > >>>> + * Array of pointers to mbuf > > >>>> + * @param count > > >>>> + * Array size > > >>>> + */ > > >>>> +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > > >>>> + unsigned count) > > >>>> +{ > > >>>> + unsigned idx; > > >>>> + > > >>>> + RTE_MBUF_ASSERT(count > 0); > > >>>> + > > >>>> + for (idx = 0; idx < count; idx++) { > > >>>> + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > > >>>> + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > > >>>> + rte_mbuf_refcnt_set(mbufs[idx], 0); > > >>> This is really a misuse of the API. The entire point of reference > > counting is > > >>> to know when an mbuf has no more references and can be freed. By > > forcing all > > >>> the reference counts to zero here, you allow the refcnt infrastructure > > to be > > >>> circumvented, causing memory leaks. > > >>> > > >>> I think what you need to do here is enhance the underlying pktmbuf > > interface > > >>> such that an rte_mbuf structure has a destructor method association > > with it > > >>> which is called when its refcnt reaches zero. That way the > > >>> rte_pktmbuf_bulk_free function can just decrement the refcnt on each > > >>> mbuf_structure, and the pool as a whole can be returned when the > > destructor > > >>> function discovers that all mbufs in that bulk pool are freed. > > >> > > >> I don't really understand what's the problem here. The API explicitly > > >> describes the conditions for calling this functions: the segments are > > >> directs, they belong to the same mempool, and their refcnt is 1. > > >> > > >> This function could be useful in a driver which knows that the mbuf > > >> it allocated matches this conditions. I think an application that > > >> only uses direct mbufs and one mempool could also use this function. > > > > > > > > > That last condition is my issue with this patch, that the user has to > > know what > > > refcnts are. It makes this api useful for little more than the test > > case that > > > is provided with it. Its irritating enough that for singly allocated > > mbufs the > > > user has to know what the refcount of a buffer is before freeing, but at > > least > > > they can macrotize a {rte_pktmbuf_refcnt_update; > > if(rte_pktmbuf_refct_read) then > > > free} operation. > > > > > > With this, you've placed the user in charge of not only doing that, but > > also of > > > managing the relationship between pktmbufs and the pool they came from. > > while > > > that makes sense for the test case, it really doesn't in any general use > > case in > > > which packet processing is ever deferred or queued, because it means > > that the > > > application is now responsible for holding a pointer to every packet it > > > allocates and checking its refcount periodically until it completes. > > > > > > There is never any reason that an application won't need to do this > > management, > > > so making it the purview of the application to handle rather than > > properly > > > integrating that functionality in the library is really a false savings. > > > > There are some places where you know that the prerequisites are met, > > so you can save cycles by using this function. > > > > From what I imagine, if in a driver you allocate mbufs, chain them and > > for some reason you realize you have to free them, you can use this > > function instead of freeing them one by one. > > > > Also, as it's up to the application to decide how many mbuf pools are > > created, and whether indirect mbufs are used or not, the application > > can take the short path of using this function in some conditions. > > > > Vadim, maybe you have another reason or use case for adding this > > function? Could you detail why you need it and how it improves your > > use case? > > > > Regards, > > Olivier > >
Hi, Konstantin, >Though from my point, such function should be generic as rte_pktmbuf_free_chain() - >no special limitations like all mbufs from one pool, refcnt==1, etc. I misunderstood, I'll rework. Regards, Vadim. On Tue, Mar 24, 2015 at 1:48 AM, Ananyev, Konstantin < konstantin.ananyev@intel.com> wrote: > Hi Vadim, > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Vadim Suraev > > Sent: Monday, March 23, 2015 5:31 PM > > To: Olivier MATZ > > Cc: dev@dpdk.org > > Subject: Re: [dpdk-dev] [PATCH v2] rte_mbuf: mbuf bulk alloc/free > functions added + unittest > > > > Hi, Olivier, > > No, I personally need to free a chain using mempool bulk. If I'm not > > mistaken, it has been proposed by one of reviewers to have lower level > > function, so it was done (I'm sorry if misunderstood) > > Was it me? > As I remember, I said it would be good to create rte_pktmbuf_bulk_free() > or rte_pktmbuf_seg_bulk_free() - > that would free a bulk of mbufs segments in the same manner as > rte_pktmbuf_free_chain() does: > count number of consecutive mbufs from the same mempool to be freed and > then put them back into the pool at one go. > Such function would be useful inside PMD code. > In fact we already using analogy of such function inside vPMD TX code. > Though from my point, such function should be generic as > rte_pktmbuf_free_chain() - > no special limitations like all mbufs from one pool, refcnt==1, etc. > So if it was me who confused you - I am sorry. > Konstantin > > > Regards, > > Vadim. > > On Mar 23, 2015 8:44 PM, "Olivier MATZ" <olivier.matz@6wind.com> wrote: > > > > > Hi Neil, > > > > > > On 03/19/2015 02:16 PM, Neil Horman wrote: > > > >> On 03/18/2015 09:58 PM, Neil Horman wrote: > > > >>>> +/** > > > >>>> + * Free a bulk of mbufs into its original mempool. > > > >>>> + * This function assumes: > > > >>>> + * - refcnt equals 1 > > > >>>> + * - mbufs are direct > > > >>>> + * - all mbufs must belong to the same mempool > > > >>>> + * > > > >>>> + * @param mbufs > > > >>>> + * Array of pointers to mbuf > > > >>>> + * @param count > > > >>>> + * Array size > > > >>>> + */ > > > >>>> +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > > > >>>> + unsigned count) > > > >>>> +{ > > > >>>> + unsigned idx; > > > >>>> + > > > >>>> + RTE_MBUF_ASSERT(count > 0); > > > >>>> + > > > >>>> + for (idx = 0; idx < count; idx++) { > > > >>>> + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > > > >>>> + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > > > >>>> + rte_mbuf_refcnt_set(mbufs[idx], 0); > > > >>> This is really a misuse of the API. The entire point of reference > > > counting is > > > >>> to know when an mbuf has no more references and can be freed. By > > > forcing all > > > >>> the reference counts to zero here, you allow the refcnt > infrastructure > > > to be > > > >>> circumvented, causing memory leaks. > > > >>> > > > >>> I think what you need to do here is enhance the underlying pktmbuf > > > interface > > > >>> such that an rte_mbuf structure has a destructor method association > > > with it > > > >>> which is called when its refcnt reaches zero. That way the > > > >>> rte_pktmbuf_bulk_free function can just decrement the refcnt on > each > > > >>> mbuf_structure, and the pool as a whole can be returned when the > > > destructor > > > >>> function discovers that all mbufs in that bulk pool are freed. > > > >> > > > >> I don't really understand what's the problem here. The API > explicitly > > > >> describes the conditions for calling this functions: the segments > are > > > >> directs, they belong to the same mempool, and their refcnt is 1. > > > >> > > > >> This function could be useful in a driver which knows that the mbuf > > > >> it allocated matches this conditions. I think an application that > > > >> only uses direct mbufs and one mempool could also use this function. > > > > > > > > > > > > That last condition is my issue with this patch, that the user has to > > > know what > > > > refcnts are. It makes this api useful for little more than the test > > > case that > > > > is provided with it. Its irritating enough that for singly allocated > > > mbufs the > > > > user has to know what the refcount of a buffer is before freeing, > but at > > > least > > > > they can macrotize a {rte_pktmbuf_refcnt_update; > > > if(rte_pktmbuf_refct_read) then > > > > free} operation. > > > > > > > > With this, you've placed the user in charge of not only doing that, > but > > > also of > > > > managing the relationship between pktmbufs and the pool they came > from. > > > while > > > > that makes sense for the test case, it really doesn't in any general > use > > > case in > > > > which packet processing is ever deferred or queued, because it means > > > that the > > > > application is now responsible for holding a pointer to every packet > it > > > > allocates and checking its refcount periodically until it completes. > > > > > > > > There is never any reason that an application won't need to do this > > > management, > > > > so making it the purview of the application to handle rather than > > > properly > > > > integrating that functionality in the library is really a false > savings. > > > > > > There are some places where you know that the prerequisites are met, > > > so you can save cycles by using this function. > > > > > > From what I imagine, if in a driver you allocate mbufs, chain them and > > > for some reason you realize you have to free them, you can use this > > > function instead of freeing them one by one. > > > > > > Also, as it's up to the application to decide how many mbuf pools are > > > created, and whether indirect mbufs are used or not, the application > > > can take the short path of using this function in some conditions. > > > > > > Vadim, maybe you have another reason or use case for adding this > > > function? Could you detail why you need it and how it improves your > > > use case? > > > > > > Regards, > > > Olivier > > > >
Hi Vadim, > From: Vadim Suraev [mailto:vadim.suraev@gmail.com] > Sent: Tuesday, March 24, 2015 7:53 AM > To: Ananyev, Konstantin > Cc: Olivier MATZ; dev@dpdk.org > Subject: Re: [dpdk-dev] [PATCH v2] rte_mbuf: mbuf bulk alloc/free functions added + unittest > > Hi, Konstantin, > > >Though from my point, such function should be generic as rte_pktmbuf_free_chain() - > >no special limitations like all mbufs from one pool, refcnt==1, etc. > I misunderstood, I'll rework. Ok, thanks. Konstantin > Regards, > Vadim. > > On Tue, Mar 24, 2015 at 1:48 AM, Ananyev, Konstantin <konstantin.ananyev@intel.com> wrote: > Hi Vadim, > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Vadim Suraev > > Sent: Monday, March 23, 2015 5:31 PM > > To: Olivier MATZ > > Cc: dev@dpdk.org > > Subject: Re: [dpdk-dev] [PATCH v2] rte_mbuf: mbuf bulk alloc/free functions added + unittest > > > > Hi, Olivier, > > No, I personally need to free a chain using mempool bulk. If I'm not > > mistaken, it has been proposed by one of reviewers to have lower level > > function, so it was done (I'm sorry if misunderstood) > > Was it me? > As I remember, I said it would be good to create rte_pktmbuf_bulk_free() or rte_pktmbuf_seg_bulk_free() - > that would free a bulk of mbufs segments in the same manner as rte_pktmbuf_free_chain() does: > count number of consecutive mbufs from the same mempool to be freed and then put them back into the pool at one go. > Such function would be useful inside PMD code. > In fact we already using analogy of such function inside vPMD TX code. > Though from my point, such function should be generic as rte_pktmbuf_free_chain() - > no special limitations like all mbufs from one pool, refcnt==1, etc. > So if it was me who confused you - I am sorry. > Konstantin > > > Regards, > > Vadim. > > On Mar 23, 2015 8:44 PM, "Olivier MATZ" <olivier.matz@6wind.com> wrote: > > > > > Hi Neil, > > > > > > On 03/19/2015 02:16 PM, Neil Horman wrote: > > > >> On 03/18/2015 09:58 PM, Neil Horman wrote: > > > >>>> +/** > > > >>>> + * Free a bulk of mbufs into its original mempool. > > > >>>> + * This function assumes: > > > >>>> + * - refcnt equals 1 > > > >>>> + * - mbufs are direct > > > >>>> + * - all mbufs must belong to the same mempool > > > >>>> + * > > > >>>> + * @param mbufs > > > >>>> + * Array of pointers to mbuf > > > >>>> + * @param count > > > >>>> + * Array size > > > >>>> + */ > > > >>>> +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > > > >>>> + unsigned count) > > > >>>> +{ > > > >>>> + unsigned idx; > > > >>>> + > > > >>>> + RTE_MBUF_ASSERT(count > 0); > > > >>>> + > > > >>>> + for (idx = 0; idx < count; idx++) { > > > >>>> + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > > > >>>> + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > > > >>>> + rte_mbuf_refcnt_set(mbufs[idx], 0); > > > >>> This is really a misuse of the API. The entire point of reference > > > counting is > > > >>> to know when an mbuf has no more references and can be freed. By > > > forcing all > > > >>> the reference counts to zero here, you allow the refcnt infrastructure > > > to be > > > >>> circumvented, causing memory leaks. > > > >>> > > > >>> I think what you need to do here is enhance the underlying pktmbuf > > > interface > > > >>> such that an rte_mbuf structure has a destructor method association > > > with it > > > >>> which is called when its refcnt reaches zero. That way the > > > >>> rte_pktmbuf_bulk_free function can just decrement the refcnt on each > > > >>> mbuf_structure, and the pool as a whole can be returned when the > > > destructor > > > >>> function discovers that all mbufs in that bulk pool are freed. > > > >> > > > >> I don't really understand what's the problem here. The API explicitly > > > >> describes the conditions for calling this functions: the segments are > > > >> directs, they belong to the same mempool, and their refcnt is 1. > > > >> > > > >> This function could be useful in a driver which knows that the mbuf > > > >> it allocated matches this conditions. I think an application that > > > >> only uses direct mbufs and one mempool could also use this function. > > > > > > > > > > > > That last condition is my issue with this patch, that the user has to > > > know what > > > > refcnts are. It makes this api useful for little more than the test > > > case that > > > > is provided with it. Its irritating enough that for singly allocated > > > mbufs the > > > > user has to know what the refcount of a buffer is before freeing, but at > > > least > > > > they can macrotize a {rte_pktmbuf_refcnt_update; > > > if(rte_pktmbuf_refct_read) then > > > > free} operation. > > > > > > > > With this, you've placed the user in charge of not only doing that, but > > > also of > > > > managing the relationship between pktmbufs and the pool they came from. > > > while > > > > that makes sense for the test case, it really doesn't in any general use > > > case in > > > > which packet processing is ever deferred or queued, because it means > > > that the > > > > application is now responsible for holding a pointer to every packet it > > > > allocates and checking its refcount periodically until it completes. > > > > > > > > There is never any reason that an application won't need to do this > > > management, > > > > so making it the purview of the application to handle rather than > > > properly > > > > integrating that functionality in the library is really a false savings. > > > > > > There are some places where you know that the prerequisites are met, > > > so you can save cycles by using this function. > > > > > > From what I imagine, if in a driver you allocate mbufs, chain them and > > > for some reason you realize you have to free them, you can use this > > > function instead of freeing them one by one. > > > > > > Also, as it's up to the application to decide how many mbuf pools are > > > created, and whether indirect mbufs are used or not, the application > > > can take the short path of using this function in some conditions. > > > > > > Vadim, maybe you have another reason or use case for adding this > > > function? Could you detail why you need it and how it improves your > > > use case? > > > > > > Regards, > > > Olivier > > >
Hi, Neil >I think what you need to do here is enhance the underlying pktmbuf interface >such that an rte_mbuf structure has a destructor method association with it >which is called when its refcnt reaches zero. That way the >rte_pktmbuf_bulk_free function can just decrement the refcnt on each >mbuf_structure, and the pool as a whole can be returned when the destructor >function discovers that all mbufs in that bulk pool are freed. I thought again and it looks to me that if mempool_cache is enabled, rte_pktmbuf_bulk_free and are redundant because the logic would be very similar to already implemented in rte_mempool. Probably the only rte_pktmbuf_alloc_bulk makes sense in this patch? Regards, Vadim. On Wed, Mar 18, 2015 at 10:58 PM, Neil Horman <nhorman@tuxdriver.com> wrote: > On Wed, Mar 18, 2015 at 10:21:18PM +0200, vadim.suraev@gmail.com wrote: > > From: "vadim.suraev@gmail.com" <vadim.suraev@gmail.com> > > > > This patch adds mbuf bulk allocation/freeing functions and unittest > > > > Signed-off-by: Vadim Suraev > > <vadim.suraev@gmail.com> > > --- > > New in v2: > > - function rte_pktmbuf_alloc_bulk added > > - function rte_pktmbuf_bulk_free added > > - function rte_pktmbuf_free_chain added > > - applied reviewers' comments > > > > app/test/test_mbuf.c | 94 > +++++++++++++++++++++++++++++++++++++++++++- > > lib/librte_mbuf/rte_mbuf.h | 91 > ++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 184 insertions(+), 1 deletion(-) > > > > diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c > > index 1ff66cb..b20c6a4 100644 > > --- a/app/test/test_mbuf.c > > +++ b/app/test/test_mbuf.c > > @@ -77,6 +77,7 @@ > > #define REFCNT_RING_SIZE (REFCNT_MBUF_NUM * REFCNT_MAX_REF) > > > > #define MAKE_STRING(x) # x > > +#define MBUF_POOL_LOCAL_CACHE_SIZE 32 > > > > static struct rte_mempool *pktmbuf_pool = NULL; > > > > @@ -405,6 +406,84 @@ test_pktmbuf_pool(void) > > return ret; > > } > > > ><snip> > > diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h > > index 17ba791..fabeae2 100644 > > --- a/lib/librte_mbuf/rte_mbuf.h > > +++ b/lib/librte_mbuf/rte_mbuf.h > > @@ -825,6 +825,97 @@ static inline void rte_pktmbuf_free(struct rte_mbuf > *m) > > } > > > > /** > > + * Allocate a bulk of mbufs, initiate refcnt and resets > > + * > > + * @param pool > > + * memory pool to allocate from > > + * @param mbufs > > + * Array of pointers to mbuf > > + * @param count > > + * Array size > > + */ > > +static inline int rte_pktmbuf_alloc_bulk(struct rte_mempool *pool, > > + struct rte_mbuf **mbufs, > > + unsigned count) > > +{ > > + unsigned idx; > > + int rc = 0; > > + > > + rc = rte_mempool_get_bulk(pool, (void **)mbufs, count); > > + if (unlikely(rc)) > > + return rc; > > + > > + for (idx = 0; idx < count; idx++) { > > + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 0); > > + rte_mbuf_refcnt_set(mbufs[idx], 1); > > + rte_pktmbuf_reset(mbufs[idx]); > > + } > > + return rc; > > +} > > + > > +/** > > + * Free a bulk of mbufs into its original mempool. > > + * This function assumes: > > + * - refcnt equals 1 > > + * - mbufs are direct > > + * - all mbufs must belong to the same mempool > > + * > > + * @param mbufs > > + * Array of pointers to mbuf > > + * @param count > > + * Array size > > + */ > > +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > > + unsigned count) > > +{ > > + unsigned idx; > > + > > + RTE_MBUF_ASSERT(count > 0); > > + > > + for (idx = 0; idx < count; idx++) { > > + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > > + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > > + rte_mbuf_refcnt_set(mbufs[idx], 0); > This is really a misuse of the API. The entire point of reference > counting is > to know when an mbuf has no more references and can be freed. By forcing > all > the reference counts to zero here, you allow the refcnt infrastructure to > be > circumvented, causing memory leaks. > > I think what you need to do here is enhance the underlying pktmbuf > interface > such that an rte_mbuf structure has a destructor method association with it > which is called when its refcnt reaches zero. That way the > rte_pktmbuf_bulk_free function can just decrement the refcnt on each > mbuf_structure, and the pool as a whole can be returned when the destructor > function discovers that all mbufs in that bulk pool are freed. > > Neil > >
On Mon, Mar 30, 2015 at 10:04:20PM +0300, Vadim Suraev wrote: > Hi, Neil > > >I think what you need to do here is enhance the underlying pktmbuf > interface > >such that an rte_mbuf structure has a destructor method association with it > >which is called when its refcnt reaches zero. That way the > >rte_pktmbuf_bulk_free function can just decrement the refcnt on each > >mbuf_structure, and the pool as a whole can be returned when the destructor > >function discovers that all mbufs in that bulk pool are freed. > > I thought again and it looks to me that if mempool_cache is enabled, > rte_pktmbuf_bulk_free and are redundant because the logic would be very > similar to already implemented in rte_mempool. Probably the only > rte_pktmbuf_alloc_bulk makes sense in this patch? > > Regards, > Vadim. > Looking at it, yes, I agree, using an externally allocated large contiguous block of memory, mapped with rte_mempool_xmem_create, then allocating with rte_pktmbuf_alloc would likely work in exactly the same way. I'd argue that even the bulk alloc function isn't really needed, as its implementation seems like it would just be a for loop with 2-3 lines in it. Neil > On Wed, Mar 18, 2015 at 10:58 PM, Neil Horman <nhorman@tuxdriver.com> wrote: > > > On Wed, Mar 18, 2015 at 10:21:18PM +0200, vadim.suraev@gmail.com wrote: > > > From: "vadim.suraev@gmail.com" <vadim.suraev@gmail.com> > > > > > > This patch adds mbuf bulk allocation/freeing functions and unittest > > > > > > Signed-off-by: Vadim Suraev > > > <vadim.suraev@gmail.com> > > > --- > > > New in v2: > > > - function rte_pktmbuf_alloc_bulk added > > > - function rte_pktmbuf_bulk_free added > > > - function rte_pktmbuf_free_chain added > > > - applied reviewers' comments > > > > > > app/test/test_mbuf.c | 94 > > +++++++++++++++++++++++++++++++++++++++++++- > > > lib/librte_mbuf/rte_mbuf.h | 91 > > ++++++++++++++++++++++++++++++++++++++++++ > > > 2 files changed, 184 insertions(+), 1 deletion(-) > > > > > > diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c > > > index 1ff66cb..b20c6a4 100644 > > > --- a/app/test/test_mbuf.c > > > +++ b/app/test/test_mbuf.c > > > @@ -77,6 +77,7 @@ > > > #define REFCNT_RING_SIZE (REFCNT_MBUF_NUM * REFCNT_MAX_REF) > > > > > > #define MAKE_STRING(x) # x > > > +#define MBUF_POOL_LOCAL_CACHE_SIZE 32 > > > > > > static struct rte_mempool *pktmbuf_pool = NULL; > > > > > > @@ -405,6 +406,84 @@ test_pktmbuf_pool(void) > > > return ret; > > > } > > > > > ><snip> > > > diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h > > > index 17ba791..fabeae2 100644 > > > --- a/lib/librte_mbuf/rte_mbuf.h > > > +++ b/lib/librte_mbuf/rte_mbuf.h > > > @@ -825,6 +825,97 @@ static inline void rte_pktmbuf_free(struct rte_mbuf > > *m) > > > } > > > > > > /** > > > + * Allocate a bulk of mbufs, initiate refcnt and resets > > > + * > > > + * @param pool > > > + * memory pool to allocate from > > > + * @param mbufs > > > + * Array of pointers to mbuf > > > + * @param count > > > + * Array size > > > + */ > > > +static inline int rte_pktmbuf_alloc_bulk(struct rte_mempool *pool, > > > + struct rte_mbuf **mbufs, > > > + unsigned count) > > > +{ > > > + unsigned idx; > > > + int rc = 0; > > > + > > > + rc = rte_mempool_get_bulk(pool, (void **)mbufs, count); > > > + if (unlikely(rc)) > > > + return rc; > > > + > > > + for (idx = 0; idx < count; idx++) { > > > + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 0); > > > + rte_mbuf_refcnt_set(mbufs[idx], 1); > > > + rte_pktmbuf_reset(mbufs[idx]); > > > + } > > > + return rc; > > > +} > > > + > > > +/** > > > + * Free a bulk of mbufs into its original mempool. > > > + * This function assumes: > > > + * - refcnt equals 1 > > > + * - mbufs are direct > > > + * - all mbufs must belong to the same mempool > > > + * > > > + * @param mbufs > > > + * Array of pointers to mbuf > > > + * @param count > > > + * Array size > > > + */ > > > +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, > > > + unsigned count) > > > +{ > > > + unsigned idx; > > > + > > > + RTE_MBUF_ASSERT(count > 0); > > > + > > > + for (idx = 0; idx < count; idx++) { > > > + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); > > > + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); > > > + rte_mbuf_refcnt_set(mbufs[idx], 0); > > This is really a misuse of the API. The entire point of reference > > counting is > > to know when an mbuf has no more references and can be freed. By forcing > > all > > the reference counts to zero here, you allow the refcnt infrastructure to > > be > > circumvented, causing memory leaks. > > > > I think what you need to do here is enhance the underlying pktmbuf > > interface > > such that an rte_mbuf structure has a destructor method association with it > > which is called when its refcnt reaches zero. That way the > > rte_pktmbuf_bulk_free function can just decrement the refcnt on each > > mbuf_structure, and the pool as a whole can be returned when the destructor > > function discovers that all mbufs in that bulk pool are freed. > > > > Neil > > > >
diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c index 1ff66cb..b20c6a4 100644 --- a/app/test/test_mbuf.c +++ b/app/test/test_mbuf.c @@ -77,6 +77,7 @@ #define REFCNT_RING_SIZE (REFCNT_MBUF_NUM * REFCNT_MAX_REF) #define MAKE_STRING(x) # x +#define MBUF_POOL_LOCAL_CACHE_SIZE 32 static struct rte_mempool *pktmbuf_pool = NULL; @@ -405,6 +406,84 @@ test_pktmbuf_pool(void) return ret; } +/* test pktmbuf bulk allocation and freeing +*/ +static int +test_pktmbuf_pool_bulk(void) +{ + unsigned i; + /* size of mempool - size of local cache, otherwise may fail */ + unsigned mbufs_to_allocate = NB_MBUF - MBUF_POOL_LOCAL_CACHE_SIZE; + struct rte_mbuf *m[mbufs_to_allocate]; + int ret = 0; + unsigned mbuf_count_before_allocation = rte_mempool_count(pktmbuf_pool); + + for (i = 0; i < mbufs_to_allocate; i++) + m[i] = NULL; + /* alloc NB_MBUF-MBUF_POOL_LOCAL_CACHE_SIZE mbufs */ + ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, m, mbufs_to_allocate); + if (ret) { + printf("cannot allocate %d mbufs bulk mempool_cnt=%d ret=%d\n", + mbufs_to_allocate, + rte_mempool_count(pktmbuf_pool), + ret); + return -1; + } + if ((rte_mempool_count(pktmbuf_pool) + mbufs_to_allocate) != + mbuf_count_before_allocation) { + printf("mempool count %d + allocated %d != initial %d\n", + rte_mempool_count(pktmbuf_pool), + mbufs_to_allocate, + mbuf_count_before_allocation); + return -1; + } + /* free them */ + rte_pktmbuf_bulk_free(m, mbufs_to_allocate); + + if (rte_mempool_count(pktmbuf_pool) != mbuf_count_before_allocation) { + printf("mempool count %d != initial %d\n", + rte_mempool_count(pktmbuf_pool), + mbuf_count_before_allocation); + return -1; + } + for (i = 0; i < mbufs_to_allocate; i++) + m[i] = NULL; + + /* alloc NB_MBUF-MBUF_POOL_LOCAL_CACHE_SIZE mbufs */ + ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, m, mbufs_to_allocate); + if (ret) { + printf("cannot allocate %d mbufs bulk mempool_cnt=%d ret=%d\n", + mbufs_to_allocate, + rte_mempool_count(pktmbuf_pool), + ret); + return -1; + } + if ((rte_mempool_count(pktmbuf_pool) + mbufs_to_allocate) != + mbuf_count_before_allocation) { + printf("mempool count %d + allocated %d != initial %d\n", + rte_mempool_count(pktmbuf_pool), + mbufs_to_allocate, + mbuf_count_before_allocation); + return -1; + } + + /* chain it */ + for (i = 0; i < mbufs_to_allocate - 1; i++) { + m[i]->next = m[i + 1]; + m[0]->nb_segs++; + } + /* free them */ + rte_pktmbuf_free_chain(m[0]); + + if (rte_mempool_count(pktmbuf_pool) != mbuf_count_before_allocation) { + printf("mempool count %d != initial %d\n", + rte_mempool_count(pktmbuf_pool), + mbuf_count_before_allocation); + return -1; + } + return ret; +} + /* * test that the pointer to the data on a packet mbuf is set properly */ @@ -766,7 +845,8 @@ test_mbuf(void) if (pktmbuf_pool == NULL) { pktmbuf_pool = rte_mempool_create("test_pktmbuf_pool", NB_MBUF, - MBUF_SIZE, 32, + MBUF_SIZE, + MBUF_POOL_LOCAL_CACHE_SIZE, sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL, @@ -790,6 +870,18 @@ test_mbuf(void) return -1; } + /* test bulk allocation and freeing */ + if (test_pktmbuf_pool_bulk() < 0) { + printf("test_pktmbuf_pool_bulk() failed\n"); + return -1; + } + + /* once again to ensure all mbufs were freed */ + if (test_pktmbuf_pool_bulk() < 0) { + printf("test_pktmbuf_pool_bulk() failed\n"); + return -1; + } + /* test that the pointer to the data on a packet mbuf is set properly */ if (test_pktmbuf_pool_ptr() < 0) { printf("test_pktmbuf_pool_ptr() failed\n"); diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h index 17ba791..fabeae2 100644 --- a/lib/librte_mbuf/rte_mbuf.h +++ b/lib/librte_mbuf/rte_mbuf.h @@ -825,6 +825,97 @@ static inline void rte_pktmbuf_free(struct rte_mbuf *m) } /** + * Allocate a bulk of mbufs, initiate refcnt and resets + * + * @param pool + * memory pool to allocate from + * @param mbufs + * Array of pointers to mbuf + * @param count + * Array size + */ +static inline int rte_pktmbuf_alloc_bulk(struct rte_mempool *pool, + struct rte_mbuf **mbufs, + unsigned count) +{ + unsigned idx; + int rc = 0; + + rc = rte_mempool_get_bulk(pool, (void **)mbufs, count); + if (unlikely(rc)) + return rc; + + for (idx = 0; idx < count; idx++) { + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 0); + rte_mbuf_refcnt_set(mbufs[idx], 1); + rte_pktmbuf_reset(mbufs[idx]); + } + return rc; +} + +/** + * Free a bulk of mbufs into its original mempool. + * This function assumes: + * - refcnt equals 1 + * - mbufs are direct + * - all mbufs must belong to the same mempool + * + * @param mbufs + * Array of pointers to mbuf + * @param count + * Array size + */ +static inline void rte_pktmbuf_bulk_free(struct rte_mbuf **mbufs, + unsigned count) +{ + unsigned idx; + + RTE_MBUF_ASSERT(count > 0); + + for (idx = 0; idx < count; idx++) { + RTE_MBUF_ASSERT(mbufs[idx]->pool == mbufs[0]->pool); + RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 1); + rte_mbuf_refcnt_set(mbufs[idx], 0); + } + rte_mempool_put_bulk(mbufs[0]->pool, (void **)mbufs, count); +} + +/** + * Free chained (scattered) mbufs into its original mempool(s). + * + * @param head + * The head of mbufs to be freed chain. Must not be NULL + */ +static inline void rte_pktmbuf_free_chain(struct rte_mbuf *head) +{ + struct rte_mbuf *mbufs[head->nb_segs]; + unsigned mbufs_count = 0; + struct rte_mbuf *next; + + while (head) { + next = head->next; + head = __rte_pktmbuf_prefree_seg(head); + if (likely(head != NULL)) { + head->next = NULL; + if (likely((!mbufs_count) || + (head->pool == mbufs[0]->pool))) + mbufs[mbufs_count++] = head; + else { + rte_mempool_put_bulk(mbufs[0]->pool, + (void **)mbufs, + mbufs_count); + mbufs_count = 0; + } + } + head = next; + } + if (mbufs_count > 0) + rte_mempool_put_bulk(mbufs[0]->pool, + (void **)mbufs, + mbufs_count); +} + +/** * Creates a "clone" of the given packet mbuf. * * Walks through all segments of the given packet mbuf, and for each of them: