mempool: rename functions with confusing names
[dpdk.git] / app / test / test_mempool_perf.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 performance
64  * =======
65  *
66  *    Each core get *n_keep* objects per bulk of *n_get_bulk*. Then,
67  *    objects are put back in the pool per bulk of *n_put_bulk*.
68  *
69  *    This sequence is done during TIME_S seconds.
70  *
71  *    This test is done on the following configurations:
72  *
73  *    - Cores configuration (*cores*)
74  *
75  *      - One core with cache
76  *      - Two cores with cache
77  *      - Max. cores with cache
78  *      - One core without cache
79  *      - Two cores without cache
80  *      - Max. cores without cache
81  *      - One core with user-owned cache
82  *      - Two cores with user-owned cache
83  *      - Max. cores with user-owned cache
84  *
85  *    - Bulk size (*n_get_bulk*, *n_put_bulk*)
86  *
87  *      - Bulk get from 1 to 32
88  *      - Bulk put from 1 to 32
89  *
90  *    - Number of kept objects (*n_keep*)
91  *
92  *      - 32
93  *      - 128
94  */
95
96 #define N 65536
97 #define TIME_S 5
98 #define MEMPOOL_ELT_SIZE 2048
99 #define MAX_KEEP 128
100 #define MEMPOOL_SIZE ((rte_lcore_count()*(MAX_KEEP+RTE_MEMPOOL_CACHE_MAX_SIZE))-1)
101
102 #define LOG_ERR() printf("test failed at %s():%d\n", __func__, __LINE__)
103 #define RET_ERR() do {                                                  \
104                 LOG_ERR();                                              \
105                 return -1;                                              \
106         } while (0)
107 #define GOTO_ERR(var, label) do {                                       \
108                 LOG_ERR();                                              \
109                 var = -1;                                               \
110                 goto label;                                             \
111         } while (0)
112
113 static struct rte_mempool *mp;
114 static struct rte_mempool *mp_cache, *mp_nocache;
115 static int use_external_cache;
116 static unsigned external_cache_size = RTE_MEMPOOL_CACHE_MAX_SIZE;
117
118 static rte_atomic32_t synchro;
119
120 /* number of objects in one bulk operation (get or put) */
121 static unsigned n_get_bulk;
122 static unsigned n_put_bulk;
123
124 /* number of objects retrived from mempool before putting them back */
125 static unsigned n_keep;
126
127 /* number of enqueues / dequeues */
128 struct mempool_test_stats {
129         uint64_t enq_count;
130 } __rte_cache_aligned;
131
132 static struct mempool_test_stats stats[RTE_MAX_LCORE];
133
134 /*
135  * save the object number in the first 4 bytes of object data. All
136  * other bytes are set to 0.
137  */
138 static void
139 my_obj_init(struct rte_mempool *mp, __attribute__((unused)) void *arg,
140             void *obj, unsigned i)
141 {
142         uint32_t *objnum = obj;
143         memset(obj, 0, mp->elt_size);
144         *objnum = i;
145 }
146
147 static int
148 per_lcore_mempool_test(__attribute__((unused)) void *arg)
149 {
150         void *obj_table[MAX_KEEP];
151         unsigned i, idx;
152         unsigned lcore_id = rte_lcore_id();
153         int ret = 0;
154         uint64_t start_cycles, end_cycles;
155         uint64_t time_diff = 0, hz = rte_get_timer_hz();
156         struct rte_mempool_cache *cache;
157
158         if (use_external_cache) {
159                 /* Create a user-owned mempool cache. */
160                 cache = rte_mempool_cache_create(external_cache_size,
161                                                  SOCKET_ID_ANY);
162                 if (cache == NULL)
163                         RET_ERR();
164         } else {
165                 /* May be NULL if cache is disabled. */
166                 cache = rte_mempool_default_cache(mp, lcore_id);
167         }
168
169         /* n_get_bulk and n_put_bulk must be divisors of n_keep */
170         if (((n_keep / n_get_bulk) * n_get_bulk) != n_keep)
171                 GOTO_ERR(ret, out);
172         if (((n_keep / n_put_bulk) * n_put_bulk) != n_keep)
173                 GOTO_ERR(ret, out);
174
175         stats[lcore_id].enq_count = 0;
176
177         /* wait synchro for slaves */
178         if (lcore_id != rte_get_master_lcore())
179                 while (rte_atomic32_read(&synchro) == 0);
180
181         start_cycles = rte_get_timer_cycles();
182
183         while (time_diff/hz < TIME_S) {
184                 for (i = 0; likely(i < (N/n_keep)); i++) {
185                         /* get n_keep objects by bulk of n_bulk */
186                         idx = 0;
187                         while (idx < n_keep) {
188                                 ret = rte_mempool_generic_get(mp,
189                                                               &obj_table[idx],
190                                                               n_get_bulk,
191                                                               cache, 0);
192                                 if (unlikely(ret < 0)) {
193                                         rte_mempool_dump(stdout, mp);
194                                         /* in this case, objects are lost... */
195                                         GOTO_ERR(ret, out);
196                                 }
197                                 idx += n_get_bulk;
198                         }
199
200                         /* put the objects back */
201                         idx = 0;
202                         while (idx < n_keep) {
203                                 rte_mempool_generic_put(mp, &obj_table[idx],
204                                                         n_put_bulk,
205                                                         cache, 0);
206                                 idx += n_put_bulk;
207                         }
208                 }
209                 end_cycles = rte_get_timer_cycles();
210                 time_diff = end_cycles - start_cycles;
211                 stats[lcore_id].enq_count += N;
212         }
213
214 out:
215         if (use_external_cache) {
216                 rte_mempool_cache_flush(cache, mp);
217                 rte_mempool_cache_free(cache);
218         }
219
220         return ret;
221 }
222
223 /* launch all the per-lcore test, and display the result */
224 static int
225 launch_cores(unsigned cores)
226 {
227         unsigned lcore_id;
228         uint64_t rate;
229         int ret;
230         unsigned cores_save = cores;
231
232         rte_atomic32_set(&synchro, 0);
233
234         /* reset stats */
235         memset(stats, 0, sizeof(stats));
236
237         printf("mempool_autotest cache=%u cores=%u n_get_bulk=%u "
238                "n_put_bulk=%u n_keep=%u ",
239                use_external_cache ?
240                    external_cache_size : (unsigned) mp->cache_size,
241                cores, n_get_bulk, n_put_bulk, n_keep);
242
243         if (rte_mempool_avail_count(mp) != MEMPOOL_SIZE) {
244                 printf("mempool is not full\n");
245                 return -1;
246         }
247
248         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
249                 if (cores == 1)
250                         break;
251                 cores--;
252                 rte_eal_remote_launch(per_lcore_mempool_test,
253                                       NULL, lcore_id);
254         }
255
256         /* start synchro and launch test on master */
257         rte_atomic32_set(&synchro, 1);
258
259         ret = per_lcore_mempool_test(NULL);
260
261         cores = cores_save;
262         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
263                 if (cores == 1)
264                         break;
265                 cores--;
266                 if (rte_eal_wait_lcore(lcore_id) < 0)
267                         ret = -1;
268         }
269
270         if (ret < 0) {
271                 printf("per-lcore test returned -1\n");
272                 return -1;
273         }
274
275         rate = 0;
276         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
277                 rate += (stats[lcore_id].enq_count / TIME_S);
278
279         printf("rate_persec=%" PRIu64 "\n", rate);
280
281         return 0;
282 }
283
284 /* for a given number of core, launch all test cases */
285 static int
286 do_one_mempool_test(unsigned cores)
287 {
288         unsigned bulk_tab_get[] = { 1, 4, 32, 0 };
289         unsigned bulk_tab_put[] = { 1, 4, 32, 0 };
290         unsigned keep_tab[] = { 32, 128, 0 };
291         unsigned *get_bulk_ptr;
292         unsigned *put_bulk_ptr;
293         unsigned *keep_ptr;
294         int ret;
295
296         for (get_bulk_ptr = bulk_tab_get; *get_bulk_ptr; get_bulk_ptr++) {
297                 for (put_bulk_ptr = bulk_tab_put; *put_bulk_ptr; put_bulk_ptr++) {
298                         for (keep_ptr = keep_tab; *keep_ptr; keep_ptr++) {
299
300                                 n_get_bulk = *get_bulk_ptr;
301                                 n_put_bulk = *put_bulk_ptr;
302                                 n_keep = *keep_ptr;
303                                 ret = launch_cores(cores);
304
305                                 if (ret < 0)
306                                         return -1;
307                         }
308                 }
309         }
310         return 0;
311 }
312
313 static int
314 test_mempool_perf(void)
315 {
316         rte_atomic32_init(&synchro);
317
318         /* create a mempool (without cache) */
319         if (mp_nocache == NULL)
320                 mp_nocache = rte_mempool_create("perf_test_nocache", MEMPOOL_SIZE,
321                                                 MEMPOOL_ELT_SIZE, 0, 0,
322                                                 NULL, NULL,
323                                                 my_obj_init, NULL,
324                                                 SOCKET_ID_ANY, 0);
325         if (mp_nocache == NULL)
326                 return -1;
327
328         /* create a mempool (with cache) */
329         if (mp_cache == NULL)
330                 mp_cache = rte_mempool_create("perf_test_cache", MEMPOOL_SIZE,
331                                               MEMPOOL_ELT_SIZE,
332                                               RTE_MEMPOOL_CACHE_MAX_SIZE, 0,
333                                               NULL, NULL,
334                                               my_obj_init, NULL,
335                                               SOCKET_ID_ANY, 0);
336         if (mp_cache == NULL)
337                 return -1;
338
339         /* performance test with 1, 2 and max cores */
340         printf("start performance test (without cache)\n");
341         mp = mp_nocache;
342
343         if (do_one_mempool_test(1) < 0)
344                 return -1;
345
346         if (do_one_mempool_test(2) < 0)
347                 return -1;
348
349         if (do_one_mempool_test(rte_lcore_count()) < 0)
350                 return -1;
351
352         /* performance test with 1, 2 and max cores */
353         printf("start performance test (with cache)\n");
354         mp = mp_cache;
355
356         if (do_one_mempool_test(1) < 0)
357                 return -1;
358
359         if (do_one_mempool_test(2) < 0)
360                 return -1;
361
362         if (do_one_mempool_test(rte_lcore_count()) < 0)
363                 return -1;
364
365         /* performance test with 1, 2 and max cores */
366         printf("start performance test (with user-owned cache)\n");
367         mp = mp_nocache;
368         use_external_cache = 1;
369
370         if (do_one_mempool_test(1) < 0)
371                 return -1;
372
373         if (do_one_mempool_test(2) < 0)
374                 return -1;
375
376         if (do_one_mempool_test(rte_lcore_count()) < 0)
377                 return -1;
378
379         rte_mempool_list_dump(stdout);
380
381         return 0;
382 }
383
384 static struct test_command mempool_perf_cmd = {
385         .command = "mempool_perf_autotest",
386         .callback = test_mempool_perf,
387 };
388 REGISTER_TEST_COMMAND(mempool_perf_cmd);