cc47232c9ee11bae2751945467c30f43cd20ba05
[dpdk.git] / app / test / test_mempool.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 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
35 #include <string.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdint.h>
39 #include <inttypes.h>
40 #include <stdarg.h>
41 #include <errno.h>
42 #include <sys/queue.h>
43
44 #include <rte_common.h>
45 #include <rte_log.h>
46 #include <rte_debug.h>
47 #include <rte_memory.h>
48 #include <rte_memzone.h>
49 #include <rte_launch.h>
50 #include <rte_cycles.h>
51 #include <rte_tailq.h>
52 #include <rte_eal.h>
53 #include <rte_per_lcore.h>
54 #include <rte_lcore.h>
55 #include <rte_atomic.h>
56 #include <rte_branch_prediction.h>
57 #include <rte_ring.h>
58 #include <rte_mempool.h>
59 #include <rte_spinlock.h>
60 #include <rte_malloc.h>
61
62 #include <cmdline_parse.h>
63
64 #include "test.h"
65
66 /*
67  * Mempool
68  * =======
69  *
70  * Basic tests: done on one core with and without cache:
71  *
72  *    - Get one object, put one object
73  *    - Get two objects, put two objects
74  *    - Get all objects, test that their content is not modified and
75  *      put them back in the pool.
76  */
77
78 #define N 65536
79 #define TIME_S 5
80 #define MEMPOOL_ELT_SIZE 2048
81 #define MAX_KEEP 128
82 #define MEMPOOL_SIZE ((RTE_MAX_LCORE*(MAX_KEEP+RTE_MEMPOOL_CACHE_MAX_SIZE))-1)
83
84 static struct rte_mempool *mp;
85 static struct rte_mempool *mp_cache, *mp_nocache;
86
87 static rte_atomic32_t synchro;
88
89
90
91 /*
92  * save the object number in the first 4 bytes of object data. All
93  * other bytes are set to 0.
94  */
95 static void
96 my_obj_init(struct rte_mempool *mp, __attribute__((unused)) void *arg,
97             void *obj, unsigned i)
98 {
99         uint32_t *objnum = obj;
100         memset(obj, 0, mp->elt_size);
101         *objnum = i;
102 }
103
104 /* basic tests (done on one core) */
105 static int
106 test_mempool_basic(void)
107 {
108         uint32_t *objnum;
109         void **objtable;
110         void *obj, *obj2;
111         char *obj_data;
112         int ret = 0;
113         unsigned i, j;
114
115         /* dump the mempool status */
116         rte_mempool_dump(mp);
117
118         printf("get an object\n");
119         if (rte_mempool_get(mp, &obj) < 0)
120                 return -1;
121         rte_mempool_dump(mp);
122
123         /* tests that improve coverage */
124         printf("get object count\n");
125         if (rte_mempool_count(mp) != MEMPOOL_SIZE - 1)
126                 return -1;
127
128         printf("get private data\n");
129         if (rte_mempool_get_priv(mp) !=
130                         (char*) mp + sizeof(struct rte_mempool))
131                 return -1;
132
133         printf("get physical address of an object\n");
134         if (rte_mempool_virt2phy(mp, obj) !=
135                         (phys_addr_t) (mp->phys_addr + (phys_addr_t) ((char*) obj - (char*) mp)))
136                 return -1;
137
138         printf("put the object back\n");
139         rte_mempool_put(mp, obj);
140         rte_mempool_dump(mp);
141
142         printf("get 2 objects\n");
143         if (rte_mempool_get(mp, &obj) < 0)
144                 return -1;
145         if (rte_mempool_get(mp, &obj2) < 0) {
146                 rte_mempool_put(mp, obj);
147                 return -1;
148         }
149         rte_mempool_dump(mp);
150
151         printf("put the objects back\n");
152         rte_mempool_put(mp, obj);
153         rte_mempool_put(mp, obj2);
154         rte_mempool_dump(mp);
155
156         /*
157          * get many objects: we cannot get them all because the cache
158          * on other cores may not be empty.
159          */
160         objtable = malloc(MEMPOOL_SIZE * sizeof(void *));
161         if (objtable == NULL) {
162                 return -1;
163         }
164
165         for (i=0; i<MEMPOOL_SIZE; i++) {
166                 if (rte_mempool_get(mp, &objtable[i]) < 0)
167                         break;
168         }
169
170         /*
171          * for each object, check that its content was not modified,
172          * and put objects back in pool
173          */
174         while (i--) {
175                 obj = objtable[i];
176                 obj_data = obj;
177                 objnum = obj;
178                 if (*objnum > MEMPOOL_SIZE) {
179                         printf("bad object number\n");
180                         ret = -1;
181                         break;
182                 }
183                 for (j=sizeof(*objnum); j<mp->elt_size; j++) {
184                         if (obj_data[j] != 0)
185                                 ret = -1;
186                 }
187
188                 rte_mempool_put(mp, objtable[i]);
189         }
190
191         free(objtable);
192         if (ret == -1)
193                 printf("objects were modified!\n");
194
195         return ret;
196 }
197
198 static int test_mempool_creation_with_exceeded_cache_size(void)
199 {
200         struct rte_mempool *mp_cov;
201
202         mp_cov = rte_mempool_create("test_mempool_creation_with_exceeded_cache_size", MEMPOOL_SIZE,
203                                               MEMPOOL_ELT_SIZE,
204                                               RTE_MEMPOOL_CACHE_MAX_SIZE + 32, 0,
205                                               NULL, NULL,
206                                               my_obj_init, NULL,
207                                               SOCKET_ID_ANY, 0);
208         if(NULL != mp_cov) {
209                 return -1;
210         }
211
212         return 0;
213 }
214
215 static struct rte_mempool *mp_spsc;
216 static rte_spinlock_t scsp_spinlock;
217 static void *scsp_obj_table[MAX_KEEP];
218
219 /*
220  * single producer function
221  */
222 static int test_mempool_single_producer(void)
223 {
224         unsigned int i;
225         void *obj = NULL;
226         uint64_t start_cycles, end_cycles;
227         uint64_t duration = rte_get_hpet_hz() * 8;
228
229         start_cycles = rte_get_hpet_cycles();
230         while (1) {
231                 end_cycles = rte_get_hpet_cycles();
232                 /* duration uses up, stop producing */
233                 if (start_cycles + duration < end_cycles)
234                         break;
235                 rte_spinlock_lock(&scsp_spinlock);
236                 for (i = 0; i < MAX_KEEP; i ++) {
237                         if (NULL != scsp_obj_table[i]) {
238                                 obj = scsp_obj_table[i];
239                                 break;
240                         }
241                 }
242                 rte_spinlock_unlock(&scsp_spinlock);
243                 if (i >= MAX_KEEP) {
244                         continue;
245                 }
246                 if (rte_mempool_from_obj(obj) != mp_spsc) {
247                         printf("test_mempool_single_producer there is an obj not owned by this mempool\n");
248                         return -1;
249                 }
250                 rte_mempool_sp_put(mp_spsc, obj);
251                 rte_spinlock_lock(&scsp_spinlock);
252                 scsp_obj_table[i] = NULL;
253                 rte_spinlock_unlock(&scsp_spinlock);
254         }
255
256         return 0;
257 }
258
259 /*
260  * single consumer function
261  */
262 static int test_mempool_single_consumer(void)
263 {
264         unsigned int i;
265         void * obj;
266         uint64_t start_cycles, end_cycles;
267         uint64_t duration = rte_get_hpet_hz() * 5;
268
269         start_cycles = rte_get_hpet_cycles();
270         while (1) {
271                 end_cycles = rte_get_hpet_cycles();
272                 /* duration uses up, stop consuming */
273                 if (start_cycles + duration < end_cycles)
274                         break;
275                 rte_spinlock_lock(&scsp_spinlock);
276                 for (i = 0; i < MAX_KEEP; i ++) {
277                         if (NULL == scsp_obj_table[i])
278                                 break;
279                 }
280                 rte_spinlock_unlock(&scsp_spinlock);
281                 if (i >= MAX_KEEP)
282                         continue;
283                 if (rte_mempool_sc_get(mp_spsc, &obj) < 0)
284                         break;
285                 rte_spinlock_lock(&scsp_spinlock);
286                 scsp_obj_table[i] = obj;
287                 rte_spinlock_unlock(&scsp_spinlock);
288         }
289
290         return 0;
291 }
292
293 /*
294  * test function for mempool test based on singple consumer and single producer, can run on one lcore only
295  */
296 static int test_mempool_launch_single_consumer(__attribute__((unused)) void *arg)
297 {
298         return test_mempool_single_consumer();
299 }
300
301 static void my_mp_init(struct rte_mempool * mp, __attribute__((unused)) void * arg)
302 {
303         printf("mempool name is %s\n", mp->name);
304         /* nothing to be implemented here*/
305         return ;
306 }
307
308 /*
309  * it tests the mempool operations based on singple producer and single consumer
310  */
311 static int
312 test_mempool_sp_sc(void)
313 {
314         int ret = 0;
315         unsigned lcore_id = rte_lcore_id();
316         unsigned lcore_next;
317
318         /* create a mempool with single producer/consumer ring */
319         if (NULL == mp_spsc) {
320                 mp_spsc = rte_mempool_create("test_mempool_sp_sc", MEMPOOL_SIZE,
321                                                 MEMPOOL_ELT_SIZE, 0, 0,
322                                                 my_mp_init, NULL,
323                                                 my_obj_init, NULL,
324                                                 SOCKET_ID_ANY, MEMPOOL_F_NO_CACHE_ALIGN | MEMPOOL_F_SP_PUT | MEMPOOL_F_SC_GET);
325                 if (NULL == mp_spsc) {
326                         return -1;
327                 }
328         }
329         if (rte_mempool_lookup("test_mempool_sp_sc") != mp_spsc) {
330                 printf("Cannot lookup mempool from its name\n");
331                 return -1;
332         }
333         lcore_next = rte_get_next_lcore(lcore_id, 0, 1);
334         if (RTE_MAX_LCORE <= lcore_next)
335                 return -1;
336         if (rte_eal_lcore_role(lcore_next) != ROLE_RTE)
337                 return -1;
338         rte_spinlock_init(&scsp_spinlock);
339         memset(scsp_obj_table, 0, sizeof(scsp_obj_table));
340         rte_eal_remote_launch(test_mempool_launch_single_consumer, NULL, lcore_next);
341         if(test_mempool_single_producer() < 0)
342                 ret = -1;
343
344         if(rte_eal_wait_lcore(lcore_next) < 0)
345                 ret = -1;
346
347         return ret;
348 }
349
350 /*
351  * it tests some more basic of mempool
352  */
353 static int
354 test_mempool_basic_ex(struct rte_mempool * mp)
355 {
356         unsigned i;
357         void **obj;
358         void *err_obj;
359         int ret = -1;
360
361         if (mp == NULL)
362                 return ret;
363
364         obj = (void **)rte_zmalloc("test_mempool_basic_ex", (MEMPOOL_SIZE * sizeof(void *)), 0);
365         if (obj == NULL) {
366                 printf("test_mempool_basic_ex fail to rte_malloc\n");
367                 return ret;
368         }
369         printf("test_mempool_basic_ex now mempool (%s) has %u free entries\n", mp->name, rte_mempool_free_count(mp));
370         if (rte_mempool_full(mp) != 1) {
371                 printf("test_mempool_basic_ex the mempool is not full but it should be\n");
372                 goto fail_mp_basic_ex;
373         }
374
375         for (i = 0; i < MEMPOOL_SIZE; i ++) {
376                 if (rte_mempool_mc_get(mp, &obj[i]) < 0) {
377                         printf("fail_mp_basic_ex fail to get mempool object for [%u]\n", i);
378                         goto fail_mp_basic_ex;
379                 }
380         }
381         if (rte_mempool_mc_get(mp, &err_obj) == 0) {
382                 printf("test_mempool_basic_ex get an impossible obj from mempool\n");
383                 goto fail_mp_basic_ex;
384         }
385         printf("number: %u\n", i);
386         if (rte_mempool_empty(mp) != 1) {
387                 printf("test_mempool_basic_ex the mempool is not empty but it should be\n");
388                 goto fail_mp_basic_ex;
389         }
390
391         for (i = 0; i < MEMPOOL_SIZE; i ++) {
392                 rte_mempool_mp_put(mp, obj[i]);
393         }
394         if (rte_mempool_full(mp) != 1) {
395                 printf("test_mempool_basic_ex the mempool is not full but it should be\n");
396                 goto fail_mp_basic_ex;
397         }
398
399         ret = 0;
400
401 fail_mp_basic_ex:
402         if (obj != NULL)
403                 rte_free((void *)obj);
404
405         return ret;
406 }
407
408 static int
409 test_mempool_same_name_twice_creation(void)
410 {
411         struct rte_mempool *mp_tc;
412
413         mp_tc = rte_mempool_create("test_mempool_same_name_twice_creation", MEMPOOL_SIZE,
414                                                 MEMPOOL_ELT_SIZE, 0, 0,
415                                                 NULL, NULL,
416                                                 NULL, NULL,
417                                                 SOCKET_ID_ANY, 0);
418         if (NULL == mp_tc)
419                 return -1;
420
421         mp_tc = rte_mempool_create("test_mempool_same_name_twice_creation", MEMPOOL_SIZE,
422                                                 MEMPOOL_ELT_SIZE, 0, 0,
423                                                 NULL, NULL,
424                                                 NULL, NULL,
425                                                 SOCKET_ID_ANY, 0);
426         if (NULL != mp_tc)
427                 return -1;
428
429         return 0;
430 }
431
432 int
433 test_mempool(void)
434 {
435         rte_atomic32_init(&synchro);
436
437         /* create a mempool (without cache) */
438         if (mp_nocache == NULL)
439                 mp_nocache = rte_mempool_create("test_nocache", MEMPOOL_SIZE,
440                                                 MEMPOOL_ELT_SIZE, 0, 0,
441                                                 NULL, NULL,
442                                                 my_obj_init, NULL,
443                                                 SOCKET_ID_ANY, 0);
444         if (mp_nocache == NULL)
445                 return -1;
446
447         /* create a mempool (with cache) */
448         if (mp_cache == NULL)
449                 mp_cache = rte_mempool_create("test_cache", MEMPOOL_SIZE,
450                                               MEMPOOL_ELT_SIZE,
451                                               RTE_MEMPOOL_CACHE_MAX_SIZE, 0,
452                                               NULL, NULL,
453                                               my_obj_init, NULL,
454                                               SOCKET_ID_ANY, 0);
455         if (mp_cache == NULL)
456                 return -1;
457
458
459         /* retrieve the mempool from its name */
460         if (rte_mempool_lookup("test_nocache") != mp_nocache) {
461                 printf("Cannot lookup mempool from its name\n");
462                 return -1;
463         }
464
465         rte_mempool_list_dump();
466
467         /* basic tests without cache */
468         mp = mp_nocache;
469         if (test_mempool_basic() < 0)
470                 return -1;
471
472         /* basic tests with cache */
473         mp = mp_cache;
474         if (test_mempool_basic() < 0)
475                 return -1;
476
477         /* more basic tests without cache */
478         if (test_mempool_basic_ex(mp_nocache) < 0)
479                 return -1;
480
481         /* mempool operation test based on single producer and single comsumer */
482         if (test_mempool_sp_sc() < 0)
483                 return -1;
484
485         if (test_mempool_creation_with_exceeded_cache_size() < 0)
486                 return -1;
487
488         if (test_mempool_same_name_twice_creation() < 0)
489                 return -1;
490
491         rte_mempool_list_dump();
492
493         return 0;
494 }