[dpdk-dev,v5,2/3] app/test: test external mempool handler

Message ID 1463665501-18325-3-git-send-email-david.hunt@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers

Commit Message

Hunt, David May 19, 2016, 1:45 p.m. UTC
  Use a minimal custom mempool external handler and check that it also
passes basic mempool autotests.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
Signed-off-by: David Hunt <david.hunt@intel.com>
---
 app/test/test_mempool.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)
  

Comments

Jan Viktorin May 23, 2016, 12:45 p.m. UTC | #1
On Thu, 19 May 2016 14:45:00 +0100
David Hunt <david.hunt@intel.com> wrote:

> Use a minimal custom mempool external handler and check that it also
> passes basic mempool autotests.
> 
> Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
> Signed-off-by: David Hunt <david.hunt@intel.com>
> 
> ---
> app/test/test_mempool.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 113 insertions(+)
> 
> diff --git a/app/test/test_mempool.c b/app/test/test_mempool.c
> index 9f02758..f55d126 100644
> --- a/app/test/test_mempool.c
> +++ b/app/test/test_mempool.c
> @@ -85,6 +85,96 @@
>  static rte_atomic32_t synchro;
>  
>  /*
> + * Simple example of custom mempool structure. Holds pointers to all the
> + * elements which are simply malloc'd in this example.
> + */
> +struct custom_mempool {
> +	rte_spinlock_t lock;
> +	unsigned count;
> +	unsigned size;
> +	void *elts[];
> +};
> +
> +/*
> + * Loop though all the element pointers and allocate a chunk of memory, then

s/though/through/

> + * insert that memory into the ring.
> + */
> +static void *
> +custom_mempool_alloc(struct rte_mempool *mp)
> +{
> +	struct custom_mempool *cm;
> +
> +	cm = rte_zmalloc("custom_mempool",
> +		sizeof(struct custom_mempool) + mp->size * sizeof(void *), 0);
> +	if (cm == NULL)
> +		return NULL;
> +
> +	rte_spinlock_init(&cm->lock);
> +	cm->count = 0;
> +	cm->size = mp->size;
> +	return cm;
> +}
> +
> +static void
> +custom_mempool_free(void *p)
> +{
> +	rte_free(p);
> +}
> +
> +static int
> +custom_mempool_put(void *p, void * const *obj_table, unsigned n)
> +{
> +	struct custom_mempool *cm = (struct custom_mempool *)p;
> +	int ret = 0;
> +
> +	rte_spinlock_lock(&cm->lock);
> +	if (cm->count + n > cm->size) {
> +		ret = -ENOBUFS;
> +	} else {
> +		memcpy(&cm->elts[cm->count], obj_table, sizeof(void *) * n);
> +		cm->count += n;
> +	}
> +	rte_spinlock_unlock(&cm->lock);
> +	return ret;
> +}
> +
> +
> +static int
> +custom_mempool_get(void *p, void **obj_table, unsigned n)
> +{
> +	struct custom_mempool *cm = (struct custom_mempool *)p;
> +	int ret = 0;
> +
> +	rte_spinlock_lock(&cm->lock);
> +	if (n > cm->count) {
> +		ret = -ENOENT;
> +	} else {
> +		cm->count -= n;
> +		memcpy(obj_table, &cm->elts[cm->count], sizeof(void *) * n);
> +	}
> +	rte_spinlock_unlock(&cm->lock);
> +	return ret;
> +}
> +
> +static unsigned
> +custom_mempool_get_count(void *p)
> +{
> +	struct custom_mempool *cm = (struct custom_mempool *)p;
> +	return cm->count;
> +}
> +
> +static struct rte_mempool_handler mempool_handler_custom = {
> +	.name = "custom_handler",
> +	.alloc = custom_mempool_alloc,
> +	.free = custom_mempool_free,
> +	.put = custom_mempool_put,
> +	.get = custom_mempool_get,
> +	.get_count = custom_mempool_get_count,
> +};
> +
> +MEMPOOL_REGISTER_HANDLER(mempool_handler_custom);

What about to drop the rte_mempool_handler.name field and derive the
name from the variable name given to the MEMPOOL_REGISTER_HANDLER.
The MEMPOOL_REGISTER_HANDLER sould do some macro magic inside and call

  rte_mempool_handler_register(name, handler);

Just an idea...

> +
> +/*
>   * save the object number in the first 4 bytes of object data. All
>   * other bytes are set to 0.
>   */
> @@ -479,6 +569,7 @@ test_mempool(void)
>  {
>  	struct rte_mempool *mp_cache = NULL;
>  	struct rte_mempool *mp_nocache = NULL;
> +	struct rte_mempool *mp_ext = NULL;
>  
>  	rte_atomic32_init(&synchro);
>  
> @@ -507,6 +598,27 @@ test_mempool(void)
>  		goto err;
>  	}
>  
> +	/* create a mempool with an external handler */
> +	mp_ext = rte_mempool_create_empty("test_ext",
> +		MEMPOOL_SIZE,
> +		MEMPOOL_ELT_SIZE,
> +		RTE_MEMPOOL_CACHE_MAX_SIZE, 0,
> +		SOCKET_ID_ANY, 0);
> +
> +	if (mp_ext == NULL) {
> +		printf("cannot allocate mp_ext mempool\n");
> +		goto err;
> +	}
> +	if (rte_mempool_set_handler(mp_ext, "custom_handler") < 0) {
> +		printf("cannot set custom handler\n");
> +		goto err;
> +	}
> +	if (rte_mempool_populate_default(mp_ext) < 0) {
> +		printf("cannot populate mp_ext mempool\n");
> +		goto err;
> +	}
> +	rte_mempool_obj_iter(mp_ext, my_obj_init, NULL);
> +

The test becomes quite complex. What about having several smaller
tests with a clear setup and cleanup steps?

>  	/* retrieve the mempool from its name */
>  	if (rte_mempool_lookup("test_nocache") != mp_nocache) {
>  		printf("Cannot lookup mempool from its name\n");
> @@ -547,6 +659,7 @@ test_mempool(void)
>  err:
>  	rte_mempool_free(mp_nocache);
>  	rte_mempool_free(mp_cache);
> +	rte_mempool_free(mp_ext);
>  	return -1;
>  }
>
  
Hunt, David May 31, 2016, 9:17 a.m. UTC | #2
Hi Jan,

On 5/23/2016 1:45 PM, Jan Viktorin wrote:
> On Thu, 19 May 2016 14:45:00 +0100
> David Hunt <david.hunt@intel.com> wrote:

--snip--

>> + * Loop though all the element pointers and allocate a chunk of memory, then
> s/though/through/

Fixed.

>> +static struct rte_mempool_handler mempool_handler_custom = {
>> +	.name = "custom_handler",
>> +	.alloc = custom_mempool_alloc,
>> +	.free = custom_mempool_free,
>> +	.put = custom_mempool_put,
>> +	.get = custom_mempool_get,
>> +	.get_count = custom_mempool_get_count,
>> +};
>> +
>> +MEMPOOL_REGISTER_HANDLER(mempool_handler_custom);
> What about to drop the rte_mempool_handler.name field and derive the
> name from the variable name given to the MEMPOOL_REGISTER_HANDLER.
> The MEMPOOL_REGISTER_HANDLER sould do some macro magic inside and call
>
>    rte_mempool_handler_register(name, handler);
>
> Just an idea...

Lets see if anyone else has any strong opinions on this :)


>> +
>> +/*
>>    * save the object number in the first 4 bytes of object data. All
>>    * other bytes are set to 0.
>>    */
>> @@ -479,6 +569,7 @@ test_mempool(void)
>>   {
>>   	struct rte_mempool *mp_cache = NULL;
>>   	struct rte_mempool *mp_nocache = NULL;
>> +	struct rte_mempool *mp_ext = NULL;
>>   
>>   	rte_atomic32_init(&synchro);
>>   
>> @@ -507,6 +598,27 @@ test_mempool(void)
>>   		goto err;
>>   	}
>>   
>> +	/* create a mempool with an external handler */
>> +	mp_ext = rte_mempool_create_empty("test_ext",
>> +		MEMPOOL_SIZE,
>> +		MEMPOOL_ELT_SIZE,
>> +		RTE_MEMPOOL_CACHE_MAX_SIZE, 0,
>> +		SOCKET_ID_ANY, 0);
>> +
>> +	if (mp_ext == NULL) {
>> +		printf("cannot allocate mp_ext mempool\n");
>> +		goto err;
>> +	}
>> +	if (rte_mempool_set_handler(mp_ext, "custom_handler") < 0) {
>> +		printf("cannot set custom handler\n");
>> +		goto err;
>> +	}
>> +	if (rte_mempool_populate_default(mp_ext) < 0) {
>> +		printf("cannot populate mp_ext mempool\n");
>> +		goto err;
>> +	}
>> +	rte_mempool_obj_iter(mp_ext, my_obj_init, NULL);
>> +
> The test becomes quite complex. What about having several smaller
> tests with a clear setup and cleanup steps?

I guess that's something we can look at in the future. For the moment 
can we leave it?

Thanks,
Dave.
  
Jan Viktorin May 31, 2016, 12:14 p.m. UTC | #3
On Tue, 31 May 2016 10:17:41 +0100
"Hunt, David" <david.hunt@intel.com> wrote:

> Hi Jan,
> 
> On 5/23/2016 1:45 PM, Jan Viktorin wrote:
> > On Thu, 19 May 2016 14:45:00 +0100
> > David Hunt <david.hunt@intel.com> wrote:  
> 
> --snip--
> 

[...]

> >> +  
> > The test becomes quite complex. What about having several smaller
> > tests with a clear setup and cleanup steps?  
> 
> I guess that's something we can look at in the future. For the moment 
> can we leave it?

Yes, just a suggestion. I think, Olivier (maintainer) should request this if needed.

> 
> Thanks,
> Dave.
> 
> 
>
  
Olivier Matz May 31, 2016, 8:40 p.m. UTC | #4
Hi,

On 05/31/2016 02:14 PM, Jan Viktorin wrote:
> On Tue, 31 May 2016 10:17:41 +0100
> "Hunt, David" <david.hunt@intel.com> wrote:
>> On 5/23/2016 1:45 PM, Jan Viktorin wrote:
>>> The test becomes quite complex. What about having several smaller
>>> tests with a clear setup and cleanup steps?  
>>
>> I guess that's something we can look at in the future. For the moment 
>> can we leave it?
> 
> Yes, just a suggestion. I think, Olivier (maintainer) should request this if needed.

Yes, I think we can let it as is for now. But I agree this is something
we could enhance.

Thanks
Olivier
  

Patch

diff --git a/app/test/test_mempool.c b/app/test/test_mempool.c
index 9f02758..f55d126 100644
--- a/app/test/test_mempool.c
+++ b/app/test/test_mempool.c
@@ -85,6 +85,96 @@ 
 static rte_atomic32_t synchro;
 
 /*
+ * Simple example of custom mempool structure. Holds pointers to all the
+ * elements which are simply malloc'd in this example.
+ */
+struct custom_mempool {
+	rte_spinlock_t lock;
+	unsigned count;
+	unsigned size;
+	void *elts[];
+};
+
+/*
+ * Loop though all the element pointers and allocate a chunk of memory, then
+ * insert that memory into the ring.
+ */
+static void *
+custom_mempool_alloc(struct rte_mempool *mp)
+{
+	struct custom_mempool *cm;
+
+	cm = rte_zmalloc("custom_mempool",
+		sizeof(struct custom_mempool) + mp->size * sizeof(void *), 0);
+	if (cm == NULL)
+		return NULL;
+
+	rte_spinlock_init(&cm->lock);
+	cm->count = 0;
+	cm->size = mp->size;
+	return cm;
+}
+
+static void
+custom_mempool_free(void *p)
+{
+	rte_free(p);
+}
+
+static int
+custom_mempool_put(void *p, void * const *obj_table, unsigned n)
+{
+	struct custom_mempool *cm = (struct custom_mempool *)p;
+	int ret = 0;
+
+	rte_spinlock_lock(&cm->lock);
+	if (cm->count + n > cm->size) {
+		ret = -ENOBUFS;
+	} else {
+		memcpy(&cm->elts[cm->count], obj_table, sizeof(void *) * n);
+		cm->count += n;
+	}
+	rte_spinlock_unlock(&cm->lock);
+	return ret;
+}
+
+
+static int
+custom_mempool_get(void *p, void **obj_table, unsigned n)
+{
+	struct custom_mempool *cm = (struct custom_mempool *)p;
+	int ret = 0;
+
+	rte_spinlock_lock(&cm->lock);
+	if (n > cm->count) {
+		ret = -ENOENT;
+	} else {
+		cm->count -= n;
+		memcpy(obj_table, &cm->elts[cm->count], sizeof(void *) * n);
+	}
+	rte_spinlock_unlock(&cm->lock);
+	return ret;
+}
+
+static unsigned
+custom_mempool_get_count(void *p)
+{
+	struct custom_mempool *cm = (struct custom_mempool *)p;
+	return cm->count;
+}
+
+static struct rte_mempool_handler mempool_handler_custom = {
+	.name = "custom_handler",
+	.alloc = custom_mempool_alloc,
+	.free = custom_mempool_free,
+	.put = custom_mempool_put,
+	.get = custom_mempool_get,
+	.get_count = custom_mempool_get_count,
+};
+
+MEMPOOL_REGISTER_HANDLER(mempool_handler_custom);
+
+/*
  * save the object number in the first 4 bytes of object data. All
  * other bytes are set to 0.
  */
@@ -479,6 +569,7 @@  test_mempool(void)
 {
 	struct rte_mempool *mp_cache = NULL;
 	struct rte_mempool *mp_nocache = NULL;
+	struct rte_mempool *mp_ext = NULL;
 
 	rte_atomic32_init(&synchro);
 
@@ -507,6 +598,27 @@  test_mempool(void)
 		goto err;
 	}
 
+	/* create a mempool with an external handler */
+	mp_ext = rte_mempool_create_empty("test_ext",
+		MEMPOOL_SIZE,
+		MEMPOOL_ELT_SIZE,
+		RTE_MEMPOOL_CACHE_MAX_SIZE, 0,
+		SOCKET_ID_ANY, 0);
+
+	if (mp_ext == NULL) {
+		printf("cannot allocate mp_ext mempool\n");
+		goto err;
+	}
+	if (rte_mempool_set_handler(mp_ext, "custom_handler") < 0) {
+		printf("cannot set custom handler\n");
+		goto err;
+	}
+	if (rte_mempool_populate_default(mp_ext) < 0) {
+		printf("cannot populate mp_ext mempool\n");
+		goto err;
+	}
+	rte_mempool_obj_iter(mp_ext, my_obj_init, NULL);
+
 	/* retrieve the mempool from its name */
 	if (rte_mempool_lookup("test_nocache") != mp_nocache) {
 		printf("Cannot lookup mempool from its name\n");
@@ -547,6 +659,7 @@  test_mempool(void)
 err:
 	rte_mempool_free(mp_nocache);
 	rte_mempool_free(mp_cache);
+	rte_mempool_free(mp_ext);
 	return -1;
 }