mempool: deprecate specific get and put functions
[dpdk.git] / app / test / test_mempool.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <string.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <inttypes.h>
39 #include <stdarg.h>
40 #include <errno.h>
41 #include <sys/queue.h>
42
43 #include <rte_common.h>
44 #include <rte_log.h>
45 #include <rte_debug.h>
46 #include <rte_memory.h>
47 #include <rte_memzone.h>
48 #include <rte_launch.h>
49 #include <rte_cycles.h>
50 #include <rte_eal.h>
51 #include <rte_per_lcore.h>
52 #include <rte_lcore.h>
53 #include <rte_atomic.h>
54 #include <rte_branch_prediction.h>
55 #include <rte_ring.h>
56 #include <rte_mempool.h>
57 #include <rte_spinlock.h>
58 #include <rte_malloc.h>
59
60 #include "test.h"
61
62 /*
63  * Mempool
64  * =======
65  *
66  * Basic tests: done on one core with and without cache:
67  *
68  *    - Get one object, put one object
69  *    - Get two objects, put two objects
70  *    - Get all objects, test that their content is not modified and
71  *      put them back in the pool.
72  */
73
74 #define MEMPOOL_ELT_SIZE 2048
75 #define MAX_KEEP 16
76 #define MEMPOOL_SIZE ((rte_lcore_count()*(MAX_KEEP+RTE_MEMPOOL_CACHE_MAX_SIZE))-1)
77
78 #define RET_ERR() do {                                                  \
79                 printf("test failed at %s():%d\n", __func__, __LINE__); \
80                 return -1;                                              \
81         } while (0)
82
83 static rte_atomic32_t synchro;
84
85 /*
86  * Simple example of custom mempool structure. Holds pointers to all the
87  * elements which are simply malloc'd in this example.
88  */
89 struct custom_mempool {
90         rte_spinlock_t lock;
91         unsigned count;
92         unsigned size;
93         void *elts[];
94 };
95
96 /*
97  * Loop through all the element pointers and allocate a chunk of memory, then
98  * insert that memory into the ring.
99  */
100 static int
101 custom_mempool_alloc(struct rte_mempool *mp)
102 {
103         struct custom_mempool *cm;
104
105         cm = rte_zmalloc("custom_mempool",
106                 sizeof(struct custom_mempool) + mp->size * sizeof(void *), 0);
107         if (cm == NULL)
108                 return -ENOMEM;
109
110         rte_spinlock_init(&cm->lock);
111         cm->count = 0;
112         cm->size = mp->size;
113         mp->pool_data = cm;
114         return 0;
115 }
116
117 static void
118 custom_mempool_free(struct rte_mempool *mp)
119 {
120         rte_free((void *)(mp->pool_data));
121 }
122
123 static int
124 custom_mempool_enqueue(struct rte_mempool *mp, void * const *obj_table,
125                 unsigned n)
126 {
127         struct custom_mempool *cm = (struct custom_mempool *)(mp->pool_data);
128         int ret = 0;
129
130         rte_spinlock_lock(&cm->lock);
131         if (cm->count + n > cm->size) {
132                 ret = -ENOBUFS;
133         } else {
134                 memcpy(&cm->elts[cm->count], obj_table, sizeof(void *) * n);
135                 cm->count += n;
136         }
137         rte_spinlock_unlock(&cm->lock);
138         return ret;
139 }
140
141
142 static int
143 custom_mempool_dequeue(struct rte_mempool *mp, void **obj_table, unsigned n)
144 {
145         struct custom_mempool *cm = (struct custom_mempool *)(mp->pool_data);
146         int ret = 0;
147
148         rte_spinlock_lock(&cm->lock);
149         if (n > cm->count) {
150                 ret = -ENOENT;
151         } else {
152                 cm->count -= n;
153                 memcpy(obj_table, &cm->elts[cm->count], sizeof(void *) * n);
154         }
155         rte_spinlock_unlock(&cm->lock);
156         return ret;
157 }
158
159 static unsigned
160 custom_mempool_get_count(const struct rte_mempool *mp)
161 {
162         struct custom_mempool *cm = (struct custom_mempool *)(mp->pool_data);
163
164         return cm->count;
165 }
166
167 static struct rte_mempool_ops mempool_ops_custom = {
168         .name = "custom_handler",
169         .alloc = custom_mempool_alloc,
170         .free = custom_mempool_free,
171         .enqueue = custom_mempool_enqueue,
172         .dequeue = custom_mempool_dequeue,
173         .get_count = custom_mempool_get_count,
174 };
175
176 MEMPOOL_REGISTER_OPS(mempool_ops_custom);
177
178 /*
179  * save the object number in the first 4 bytes of object data. All
180  * other bytes are set to 0.
181  */
182 static void
183 my_obj_init(struct rte_mempool *mp, __attribute__((unused)) void *arg,
184             void *obj, unsigned i)
185 {
186         uint32_t *objnum = obj;
187
188         memset(obj, 0, mp->elt_size);
189         *objnum = i;
190 }
191
192 /* basic tests (done on one core) */
193 static int
194 test_mempool_basic(struct rte_mempool *mp)
195 {
196         uint32_t *objnum;
197         void **objtable;
198         void *obj, *obj2;
199         char *obj_data;
200         int ret = 0;
201         unsigned i, j;
202
203         /* dump the mempool status */
204         rte_mempool_dump(stdout, mp);
205
206         printf("get an object\n");
207         if (rte_mempool_get(mp, &obj) < 0)
208                 RET_ERR();
209         rte_mempool_dump(stdout, mp);
210
211         /* tests that improve coverage */
212         printf("get object count\n");
213         if (rte_mempool_count(mp) != MEMPOOL_SIZE - 1)
214                 RET_ERR();
215
216         printf("get private data\n");
217         if (rte_mempool_get_priv(mp) != (char *)mp +
218                         MEMPOOL_HEADER_SIZE(mp, mp->cache_size))
219                 RET_ERR();
220
221 #ifndef RTE_EXEC_ENV_BSDAPP /* rte_mem_virt2phy() not supported on bsd */
222         printf("get physical address of an object\n");
223         if (rte_mempool_virt2phy(mp, obj) != rte_mem_virt2phy(obj))
224                 RET_ERR();
225 #endif
226
227         printf("put the object back\n");
228         rte_mempool_put(mp, obj);
229         rte_mempool_dump(stdout, mp);
230
231         printf("get 2 objects\n");
232         if (rte_mempool_get(mp, &obj) < 0)
233                 RET_ERR();
234         if (rte_mempool_get(mp, &obj2) < 0) {
235                 rte_mempool_put(mp, obj);
236                 RET_ERR();
237         }
238         rte_mempool_dump(stdout, mp);
239
240         printf("put the objects back\n");
241         rte_mempool_put(mp, obj);
242         rte_mempool_put(mp, obj2);
243         rte_mempool_dump(stdout, mp);
244
245         /*
246          * get many objects: we cannot get them all because the cache
247          * on other cores may not be empty.
248          */
249         objtable = malloc(MEMPOOL_SIZE * sizeof(void *));
250         if (objtable == NULL)
251                 RET_ERR();
252
253         for (i = 0; i < MEMPOOL_SIZE; i++) {
254                 if (rte_mempool_get(mp, &objtable[i]) < 0)
255                         break;
256         }
257
258         /*
259          * for each object, check that its content was not modified,
260          * and put objects back in pool
261          */
262         while (i--) {
263                 obj = objtable[i];
264                 obj_data = obj;
265                 objnum = obj;
266                 if (*objnum > MEMPOOL_SIZE) {
267                         printf("bad object number(%d)\n", *objnum);
268                         ret = -1;
269                         break;
270                 }
271                 for (j = sizeof(*objnum); j < mp->elt_size; j++) {
272                         if (obj_data[j] != 0)
273                                 ret = -1;
274                 }
275
276                 rte_mempool_put(mp, objtable[i]);
277         }
278
279         free(objtable);
280         if (ret == -1)
281                 printf("objects were modified!\n");
282
283         return ret;
284 }
285
286 static int test_mempool_creation_with_exceeded_cache_size(void)
287 {
288         struct rte_mempool *mp_cov;
289
290         mp_cov = rte_mempool_create("test_mempool_cache_too_big",
291                 MEMPOOL_SIZE,
292                 MEMPOOL_ELT_SIZE,
293                 RTE_MEMPOOL_CACHE_MAX_SIZE + 32, 0,
294                 NULL, NULL,
295                 my_obj_init, NULL,
296                 SOCKET_ID_ANY, 0);
297
298         if (mp_cov != NULL) {
299                 rte_mempool_free(mp_cov);
300                 RET_ERR();
301         }
302
303         return 0;
304 }
305
306 static struct rte_mempool *mp_spsc;
307 static rte_spinlock_t scsp_spinlock;
308 static void *scsp_obj_table[MAX_KEEP];
309
310 /*
311  * single producer function
312  */
313 static int test_mempool_single_producer(void)
314 {
315         unsigned int i;
316         void *obj = NULL;
317         uint64_t start_cycles, end_cycles;
318         uint64_t duration = rte_get_timer_hz() / 4;
319
320         start_cycles = rte_get_timer_cycles();
321         while (1) {
322                 end_cycles = rte_get_timer_cycles();
323                 /* duration uses up, stop producing */
324                 if (start_cycles + duration < end_cycles)
325                         break;
326                 rte_spinlock_lock(&scsp_spinlock);
327                 for (i = 0; i < MAX_KEEP; i ++) {
328                         if (NULL != scsp_obj_table[i]) {
329                                 obj = scsp_obj_table[i];
330                                 break;
331                         }
332                 }
333                 rte_spinlock_unlock(&scsp_spinlock);
334                 if (i >= MAX_KEEP) {
335                         continue;
336                 }
337                 if (rte_mempool_from_obj(obj) != mp_spsc) {
338                         printf("obj not owned by this mempool\n");
339                         RET_ERR();
340                 }
341                 rte_mempool_put(mp_spsc, obj);
342                 rte_spinlock_lock(&scsp_spinlock);
343                 scsp_obj_table[i] = NULL;
344                 rte_spinlock_unlock(&scsp_spinlock);
345         }
346
347         return 0;
348 }
349
350 /*
351  * single consumer function
352  */
353 static int test_mempool_single_consumer(void)
354 {
355         unsigned int i;
356         void * obj;
357         uint64_t start_cycles, end_cycles;
358         uint64_t duration = rte_get_timer_hz() / 8;
359
360         start_cycles = rte_get_timer_cycles();
361         while (1) {
362                 end_cycles = rte_get_timer_cycles();
363                 /* duration uses up, stop consuming */
364                 if (start_cycles + duration < end_cycles)
365                         break;
366                 rte_spinlock_lock(&scsp_spinlock);
367                 for (i = 0; i < MAX_KEEP; i ++) {
368                         if (NULL == scsp_obj_table[i])
369                                 break;
370                 }
371                 rte_spinlock_unlock(&scsp_spinlock);
372                 if (i >= MAX_KEEP)
373                         continue;
374                 if (rte_mempool_get(mp_spsc, &obj) < 0)
375                         break;
376                 rte_spinlock_lock(&scsp_spinlock);
377                 scsp_obj_table[i] = obj;
378                 rte_spinlock_unlock(&scsp_spinlock);
379         }
380
381         return 0;
382 }
383
384 /*
385  * test function for mempool test based on singple consumer and single producer,
386  * can run on one lcore only
387  */
388 static int
389 test_mempool_launch_single_consumer(__attribute__((unused)) void *arg)
390 {
391         return test_mempool_single_consumer();
392 }
393
394 static void
395 my_mp_init(struct rte_mempool *mp, __attribute__((unused)) void *arg)
396 {
397         printf("mempool name is %s\n", mp->name);
398         /* nothing to be implemented here*/
399         return ;
400 }
401
402 /*
403  * it tests the mempool operations based on singple producer and single consumer
404  */
405 static int
406 test_mempool_sp_sc(void)
407 {
408         int ret = 0;
409         unsigned lcore_id = rte_lcore_id();
410         unsigned lcore_next;
411
412         /* create a mempool with single producer/consumer ring */
413         if (mp_spsc == NULL) {
414                 mp_spsc = rte_mempool_create("test_mempool_sp_sc", MEMPOOL_SIZE,
415                         MEMPOOL_ELT_SIZE, 0, 0,
416                         my_mp_init, NULL,
417                         my_obj_init, NULL,
418                         SOCKET_ID_ANY,
419                         MEMPOOL_F_NO_CACHE_ALIGN | MEMPOOL_F_SP_PUT |
420                         MEMPOOL_F_SC_GET);
421                 if (mp_spsc == NULL)
422                         RET_ERR();
423         }
424         if (rte_mempool_lookup("test_mempool_sp_sc") != mp_spsc) {
425                 printf("Cannot lookup mempool from its name\n");
426                 rte_mempool_free(mp_spsc);
427                 RET_ERR();
428         }
429         lcore_next = rte_get_next_lcore(lcore_id, 0, 1);
430         if (lcore_next >= RTE_MAX_LCORE) {
431                 rte_mempool_free(mp_spsc);
432                 RET_ERR();
433         }
434         if (rte_eal_lcore_role(lcore_next) != ROLE_RTE) {
435                 rte_mempool_free(mp_spsc);
436                 RET_ERR();
437         }
438         rte_spinlock_init(&scsp_spinlock);
439         memset(scsp_obj_table, 0, sizeof(scsp_obj_table));
440         rte_eal_remote_launch(test_mempool_launch_single_consumer, NULL,
441                 lcore_next);
442         if (test_mempool_single_producer() < 0)
443                 ret = -1;
444
445         if (rte_eal_wait_lcore(lcore_next) < 0)
446                 ret = -1;
447         rte_mempool_free(mp_spsc);
448
449         return ret;
450 }
451
452 /*
453  * it tests some more basic of mempool
454  */
455 static int
456 test_mempool_basic_ex(struct rte_mempool *mp)
457 {
458         unsigned i;
459         void **obj;
460         void *err_obj;
461         int ret = -1;
462
463         if (mp == NULL)
464                 return ret;
465
466         obj = rte_calloc("test_mempool_basic_ex", MEMPOOL_SIZE,
467                 sizeof(void *), 0);
468         if (obj == NULL) {
469                 printf("test_mempool_basic_ex fail to rte_malloc\n");
470                 return ret;
471         }
472         printf("test_mempool_basic_ex now mempool (%s) has %u free entries\n",
473                 mp->name, rte_mempool_free_count(mp));
474         if (rte_mempool_full(mp) != 1) {
475                 printf("test_mempool_basic_ex the mempool should be full\n");
476                 goto fail_mp_basic_ex;
477         }
478
479         for (i = 0; i < MEMPOOL_SIZE; i ++) {
480                 if (rte_mempool_get(mp, &obj[i]) < 0) {
481                         printf("test_mp_basic_ex fail to get object for [%u]\n",
482                                 i);
483                         goto fail_mp_basic_ex;
484                 }
485         }
486         if (rte_mempool_get(mp, &err_obj) == 0) {
487                 printf("test_mempool_basic_ex get an impossible obj\n");
488                 goto fail_mp_basic_ex;
489         }
490         printf("number: %u\n", i);
491         if (rte_mempool_empty(mp) != 1) {
492                 printf("test_mempool_basic_ex the mempool should be empty\n");
493                 goto fail_mp_basic_ex;
494         }
495
496         for (i = 0; i < MEMPOOL_SIZE; i++)
497                 rte_mempool_put(mp, obj[i]);
498
499         if (rte_mempool_full(mp) != 1) {
500                 printf("test_mempool_basic_ex the mempool should be full\n");
501                 goto fail_mp_basic_ex;
502         }
503
504         ret = 0;
505
506 fail_mp_basic_ex:
507         if (obj != NULL)
508                 rte_free((void *)obj);
509
510         return ret;
511 }
512
513 static int
514 test_mempool_same_name_twice_creation(void)
515 {
516         struct rte_mempool *mp_tc, *mp_tc2;
517
518         mp_tc = rte_mempool_create("test_mempool_same_name", MEMPOOL_SIZE,
519                 MEMPOOL_ELT_SIZE, 0, 0,
520                 NULL, NULL,
521                 NULL, NULL,
522                 SOCKET_ID_ANY, 0);
523
524         if (mp_tc == NULL)
525                 RET_ERR();
526
527         mp_tc2 = rte_mempool_create("test_mempool_same_name", MEMPOOL_SIZE,
528                 MEMPOOL_ELT_SIZE, 0, 0,
529                 NULL, NULL,
530                 NULL, NULL,
531                 SOCKET_ID_ANY, 0);
532
533         if (mp_tc2 != NULL) {
534                 rte_mempool_free(mp_tc);
535                 rte_mempool_free(mp_tc2);
536                 RET_ERR();
537         }
538
539         rte_mempool_free(mp_tc);
540         return 0;
541 }
542
543 /*
544  * BAsic test for mempool_xmem functions.
545  */
546 static int
547 test_mempool_xmem_misc(void)
548 {
549         uint32_t elt_num, total_size;
550         size_t sz;
551         ssize_t usz;
552
553         elt_num = MAX_KEEP;
554         total_size = rte_mempool_calc_obj_size(MEMPOOL_ELT_SIZE, 0, NULL);
555         sz = rte_mempool_xmem_size(elt_num, total_size, MEMPOOL_PG_SHIFT_MAX);
556
557         usz = rte_mempool_xmem_usage(NULL, elt_num, total_size, 0, 1,
558                 MEMPOOL_PG_SHIFT_MAX);
559
560         if (sz != (size_t)usz)  {
561                 printf("failure @ %s: rte_mempool_xmem_usage(%u, %u) "
562                         "returns: %#zx, while expected: %#zx;\n",
563                         __func__, elt_num, total_size, sz, (size_t)usz);
564                 return -1;
565         }
566
567         return 0;
568 }
569
570 static int
571 test_mempool(void)
572 {
573         struct rte_mempool *mp_cache = NULL;
574         struct rte_mempool *mp_nocache = NULL;
575         struct rte_mempool *mp_ext = NULL;
576
577         rte_atomic32_init(&synchro);
578
579         /* create a mempool (without cache) */
580         mp_nocache = rte_mempool_create("test_nocache", MEMPOOL_SIZE,
581                 MEMPOOL_ELT_SIZE, 0, 0,
582                 NULL, NULL,
583                 my_obj_init, NULL,
584                 SOCKET_ID_ANY, 0);
585
586         if (mp_nocache == NULL) {
587                 printf("cannot allocate mp_nocache mempool\n");
588                 goto err;
589         }
590
591         /* create a mempool (with cache) */
592         mp_cache = rte_mempool_create("test_cache", MEMPOOL_SIZE,
593                 MEMPOOL_ELT_SIZE,
594                 RTE_MEMPOOL_CACHE_MAX_SIZE, 0,
595                 NULL, NULL,
596                 my_obj_init, NULL,
597                 SOCKET_ID_ANY, 0);
598
599         if (mp_cache == NULL) {
600                 printf("cannot allocate mp_cache mempool\n");
601                 goto err;
602         }
603
604         /* create a mempool with an external handler */
605         mp_ext = rte_mempool_create_empty("test_ext",
606                 MEMPOOL_SIZE,
607                 MEMPOOL_ELT_SIZE,
608                 RTE_MEMPOOL_CACHE_MAX_SIZE, 0,
609                 SOCKET_ID_ANY, 0);
610
611         if (mp_ext == NULL) {
612                 printf("cannot allocate mp_ext mempool\n");
613                 goto err;
614         }
615         if (rte_mempool_set_ops_byname(mp_ext, "custom_handler", NULL) < 0) {
616                 printf("cannot set custom handler\n");
617                 goto err;
618         }
619         if (rte_mempool_populate_default(mp_ext) < 0) {
620                 printf("cannot populate mp_ext mempool\n");
621                 goto err;
622         }
623         rte_mempool_obj_iter(mp_ext, my_obj_init, NULL);
624
625         /* retrieve the mempool from its name */
626         if (rte_mempool_lookup("test_nocache") != mp_nocache) {
627                 printf("Cannot lookup mempool from its name\n");
628                 goto err;
629         }
630
631         rte_mempool_list_dump(stdout);
632
633         /* basic tests without cache */
634         if (test_mempool_basic(mp_nocache) < 0)
635                 goto err;
636
637         /* basic tests with cache */
638         if (test_mempool_basic(mp_cache) < 0)
639                 goto err;
640
641         /* more basic tests without cache */
642         if (test_mempool_basic_ex(mp_nocache) < 0)
643                 goto err;
644
645         /* mempool operation test based on single producer and single comsumer */
646         if (test_mempool_sp_sc() < 0)
647                 goto err;
648
649         if (test_mempool_creation_with_exceeded_cache_size() < 0)
650                 goto err;
651
652         if (test_mempool_same_name_twice_creation() < 0)
653                 goto err;
654
655         if (test_mempool_xmem_misc() < 0)
656                 goto err;
657
658         rte_mempool_list_dump(stdout);
659
660         return 0;
661
662 err:
663         rte_mempool_free(mp_nocache);
664         rte_mempool_free(mp_cache);
665         rte_mempool_free(mp_ext);
666         return -1;
667 }
668
669 static struct test_command mempool_cmd = {
670         .command = "mempool_autotest",
671         .callback = test_mempool,
672 };
673 REGISTER_TEST_COMMAND(mempool_cmd);