77157801fb34b627183f5ed32fcd477256c9ad29
[dpdk.git] / lib / librte_mempool / rte_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 <stdio.h>
36 #include <string.h>
37 #include <stdint.h>
38 #include <stdarg.h>
39 #include <inttypes.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_atomic.h>
49 #include <rte_launch.h>
50 #include <rte_tailq.h>
51 #include <rte_eal.h>
52 #include <rte_eal_memconfig.h>
53 #include <rte_per_lcore.h>
54 #include <rte_lcore.h>
55 #include <rte_branch_prediction.h>
56 #include <rte_ring.h>
57 #include <rte_errno.h>
58 #include <rte_string_fns.h>
59
60 #include "rte_mempool.h"
61
62 TAILQ_HEAD(rte_mempool_list, rte_mempool);
63
64
65 /*
66  * return the greatest common divisor between a and b (fast algorithm)
67  *
68  */
69 static unsigned get_gcd(unsigned a, unsigned b)
70 {
71         unsigned c;
72
73         if (0 == a)
74                 return b;
75         if (0 == b)
76                 return a;
77
78         if (a < b) {
79                 c = a;
80                 a = b;
81                 b = c;
82         }
83
84         while (b != 0) {
85                 c = a % b;
86                 a = b;
87                 b = c;
88         }
89
90         return a;
91 }
92
93 /*
94  * Depending on memory configuration, objects addresses are spreaded
95  * between channels and ranks in RAM: the pool allocator will add
96  * padding between objects. This function return the new size of the
97  * object.
98  */
99 static unsigned optimize_object_size(unsigned obj_size)
100 {
101         unsigned nrank, nchan;
102         unsigned new_obj_size;
103
104         /* get number of channels */
105         nchan = rte_memory_get_nchannel();
106         if (nchan == 0)
107                 nchan = 1;
108
109         nrank = rte_memory_get_nrank();
110         if (nrank == 0)
111                 nrank = 1;
112
113         /* process new object size */
114         new_obj_size = (obj_size + CACHE_LINE_MASK) / CACHE_LINE_SIZE;
115         while (get_gcd(new_obj_size, nrank * nchan) != 1 ||
116                         get_gcd(nchan, new_obj_size) != 1)
117                 new_obj_size++;
118         return new_obj_size * CACHE_LINE_SIZE;
119 }
120
121 /* create the mempool */
122 struct rte_mempool *
123 rte_mempool_create(const char *name, unsigned n, unsigned elt_size,
124                    unsigned cache_size, unsigned private_data_size,
125                    rte_mempool_ctor_t *mp_init, void *mp_init_arg,
126                    rte_mempool_obj_ctor_t *obj_init, void *obj_init_arg,
127                    int socket_id, unsigned flags)
128 {
129         char mz_name[RTE_MEMZONE_NAMESIZE];
130         char rg_name[RTE_RING_NAMESIZE];
131         struct rte_mempool *mp = NULL;
132         struct rte_ring *r;
133         const struct rte_memzone *mz;
134         size_t mempool_size;
135         int mz_flags = RTE_MEMZONE_1GB|RTE_MEMZONE_SIZE_HINT_ONLY;
136         int rg_flags = 0;
137         uint32_t header_size, trailer_size;
138         uint32_t total_elt_size;
139         unsigned i;
140         void *obj;
141
142         /* compilation-time checks */
143         RTE_BUILD_BUG_ON((sizeof(struct rte_mempool) &
144                           CACHE_LINE_MASK) != 0);
145 #if RTE_MEMPOOL_CACHE_MAX_SIZE > 0
146         RTE_BUILD_BUG_ON((sizeof(struct rte_mempool_cache) &
147                           CACHE_LINE_MASK) != 0);
148         RTE_BUILD_BUG_ON((offsetof(struct rte_mempool, local_cache) &
149                           CACHE_LINE_MASK) != 0);
150 #endif
151 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG
152         RTE_BUILD_BUG_ON((sizeof(struct rte_mempool_debug_stats) &
153                           CACHE_LINE_MASK) != 0);
154         RTE_BUILD_BUG_ON((offsetof(struct rte_mempool, stats) &
155                           CACHE_LINE_MASK) != 0);
156 #endif
157
158         /* check that we have an initialised tail queue */
159         if (RTE_TAILQ_LOOKUP_BY_IDX(RTE_TAILQ_MEMPOOL, rte_mempool_list) == NULL) {
160                 rte_errno = E_RTE_NO_TAILQ;
161                 return NULL;    
162         }
163         
164         /* asked cache too big */
165         if (cache_size > RTE_MEMPOOL_CACHE_MAX_SIZE){
166                 rte_errno = EINVAL;
167                 return NULL;
168         }
169
170         /* "no cache align" imply "no spread" */
171         if (flags & MEMPOOL_F_NO_CACHE_ALIGN)
172                 flags |= MEMPOOL_F_NO_SPREAD;
173
174         /* ring flags */
175         if (flags & MEMPOOL_F_SP_PUT)
176                 rg_flags |= RING_F_SP_ENQ;
177         if (flags & MEMPOOL_F_SC_GET)
178                 rg_flags |= RING_F_SC_DEQ;
179
180         /* allocate the ring that will be used to store objects */
181         /* Ring functions will return appropriate errors if we are
182          * running as a secondary process etc., so no checks made
183          * in this function for that condition */
184         rte_snprintf(rg_name, sizeof(rg_name), "MP_%s", name);
185         r = rte_ring_create(rg_name, rte_align32pow2(n+1), socket_id, rg_flags);
186         if (r == NULL)
187                 return NULL;
188
189         /*
190          * In header, we have at least the pointer to the pool, and
191          * optionaly a 64 bits cookie.
192          */
193         header_size = 0;
194         header_size += sizeof(struct rte_mempool *); /* ptr to pool */
195 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG
196         header_size += sizeof(uint64_t); /* cookie */
197 #endif
198         if ((flags & MEMPOOL_F_NO_CACHE_ALIGN) == 0)
199                 header_size = (header_size + CACHE_LINE_MASK) & (~CACHE_LINE_MASK);
200
201         /* trailer contains the cookie in debug mode */
202         trailer_size = 0;
203 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG
204         trailer_size += sizeof(uint64_t); /* cookie */
205 #endif
206         /* element size is 8 bytes-aligned at least */
207         elt_size = (elt_size + 7) & (~7);
208
209         /* expand trailer to next cache line */
210         if ((flags & MEMPOOL_F_NO_CACHE_ALIGN) == 0) {
211                 total_elt_size = header_size + elt_size + trailer_size;
212                 trailer_size += ((CACHE_LINE_SIZE -
213                                   (total_elt_size & CACHE_LINE_MASK)) &
214                                  CACHE_LINE_MASK);
215         }
216
217         /*
218          * increase trailer to add padding between objects in order to
219          * spread them accross memory channels/ranks
220          */
221         if ((flags & MEMPOOL_F_NO_SPREAD) == 0) {
222                 unsigned new_size;
223                 new_size = optimize_object_size(header_size + elt_size +
224                                                 trailer_size);
225                 trailer_size = new_size - header_size - elt_size;
226         }
227
228         /* this is the size of an object, including header and trailer */
229         total_elt_size = header_size + elt_size + trailer_size;
230
231         /* reserve a memory zone for this mempool: private data is
232          * cache-aligned */
233         private_data_size = (private_data_size +
234                              CACHE_LINE_MASK) & (~CACHE_LINE_MASK);
235         mempool_size = total_elt_size * n +
236                 sizeof(struct rte_mempool) + private_data_size;
237         rte_snprintf(mz_name, sizeof(mz_name), "MP_%s", name);
238         mz = rte_memzone_reserve(mz_name, mempool_size, socket_id, mz_flags);
239
240         /*
241          * no more memory: in this case we loose previously reserved
242          * space for the as we cannot free it
243          */
244         if (mz == NULL)
245                 return NULL;
246
247         /* init the mempool structure */
248         mp = mz->addr;
249         memset(mp, 0, sizeof(*mp));
250         rte_snprintf(mp->name, sizeof(mp->name), "%s", name);
251         mp->phys_addr = mz->phys_addr;
252         mp->ring = r;
253         mp->size = n;
254         mp->flags = flags;
255         mp->bulk_default = 1;
256         mp->elt_size = elt_size;
257         mp->header_size = header_size;
258         mp->trailer_size = trailer_size;
259         mp->cache_size = cache_size;
260         mp->private_data_size = private_data_size;
261
262         /* call the initializer */
263         if (mp_init)
264                 mp_init(mp, mp_init_arg);
265
266         /* fill the headers and trailers, and add objects in ring */
267         obj = (char *)mp + sizeof(struct rte_mempool) + private_data_size;
268         for (i = 0; i < n; i++) {
269                 struct rte_mempool **mpp;
270                 obj = (char *)obj + header_size;
271
272                 /* set mempool ptr in header */
273                 mpp = __mempool_from_obj(obj);
274                 *mpp = mp;
275
276 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG
277                 __mempool_write_header_cookie(obj, 1);
278                 __mempool_write_trailer_cookie(obj);
279 #endif
280                 /* call the initializer */
281                 if (obj_init)
282                         obj_init(mp, obj_init_arg, obj, i);
283
284                 /* enqueue in ring */
285                 rte_ring_sp_enqueue(mp->ring, obj);
286                 obj = (char *)obj + elt_size + trailer_size;
287         }
288
289         RTE_EAL_TAILQ_INSERT_TAIL(RTE_TAILQ_MEMPOOL, rte_mempool_list, mp);
290
291         return mp;
292 }
293
294 /* Return the number of entries in the mempool */
295 unsigned
296 rte_mempool_count(const struct rte_mempool *mp)
297 {
298         unsigned count;
299
300         count = rte_ring_count(mp->ring);
301
302 #if RTE_MEMPOOL_CACHE_MAX_SIZE > 0
303         {
304                 unsigned lcore_id;
305                 if (mp->cache_size == 0)
306                         return count;
307
308                 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
309                         count += mp->local_cache[lcore_id].len;
310         }
311 #endif
312
313         /*
314          * due to race condition (access to len is not locked), the
315          * total can be greater than size... so fix the result
316          */
317         if (count > mp->size)
318                 return mp->size;
319         return count;
320 }
321
322 /* dump the cache status */
323 static unsigned
324 rte_mempool_dump_cache(const struct rte_mempool *mp)
325 {
326 #if RTE_MEMPOOL_CACHE_MAX_SIZE > 0
327         unsigned lcore_id;
328         unsigned count = 0;
329         unsigned cache_count;
330
331         printf("  cache infos:\n");
332         printf("    cache_size=%"PRIu32"\n", mp->cache_size);
333         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
334                 cache_count = mp->local_cache[lcore_id].len;
335                 printf("    cache_count[%u]=%u\n", lcore_id, cache_count);
336                 count += cache_count;
337         }
338         printf("    total_cache_count=%u\n", count);
339         return count;
340 #else
341         RTE_SET_USED(mp);
342         printf("  cache disabled\n");
343         return 0;
344 #endif
345 }
346
347 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG
348 /* check cookies before and after objects */
349 #ifndef __INTEL_COMPILER
350 #pragma GCC diagnostic ignored "-Wcast-qual"
351 #endif
352 static void
353 mempool_audit_cookies(const struct rte_mempool *mp)
354 {
355         unsigned i;
356         void *obj;
357         void * const *obj_table;
358
359         obj = (char *)mp + sizeof(struct rte_mempool) + mp->private_data_size;
360         for (i = 0; i < mp->size; i++) {
361                 obj = (char *)obj + mp->header_size;
362                 obj_table = &obj;
363                 __mempool_check_cookies(mp, obj_table, 1, 2);
364                 obj = (char *)obj + mp->elt_size + mp->trailer_size;
365         }
366 }
367 #ifndef __INTEL_COMPILER
368 #pragma GCC diagnostic error "-Wcast-qual"
369 #endif
370 #else
371 #define mempool_audit_cookies(mp) do {} while(0)
372 #endif
373
374 #if RTE_MEMPOOL_CACHE_MAX_SIZE > 0
375 /* check cookies before and after objects */
376 static void
377 mempool_audit_cache(const struct rte_mempool *mp)
378 {
379         /* check cache size consistency */
380         unsigned lcore_id;
381         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
382                 if (mp->local_cache[lcore_id].len > mp->cache_size) {
383                         RTE_LOG(CRIT, MEMPOOL, "badness on cache[%u]\n",
384                                 lcore_id);
385                         rte_panic("MEMPOOL: invalid cache len\n");
386                 }
387         }
388 }
389 #else
390 #define mempool_audit_cache(mp) do {} while(0)
391 #endif
392
393
394 /* check the consistency of mempool (size, cookies, ...) */
395 void
396 rte_mempool_audit(const struct rte_mempool *mp)
397 {
398         mempool_audit_cache(mp);
399         mempool_audit_cookies(mp);
400 }
401
402 /* dump the status of the mempool on the console */
403 void
404 rte_mempool_dump(const struct rte_mempool *mp)
405 {
406 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG
407         struct rte_mempool_debug_stats sum;
408         unsigned lcore_id;
409 #endif
410         unsigned common_count;
411         unsigned cache_count;
412
413         printf("mempool <%s>@%p\n", mp->name, mp);
414         printf("  flags=%x\n", mp->flags);
415         printf("  ring=<%s>@%p\n", mp->ring->name, mp->ring);
416         printf("  size=%"PRIu32"\n", mp->size);
417         printf("  bulk_default=%"PRIu32"\n", mp->bulk_default);
418         printf("  header_size=%"PRIu32"\n", mp->header_size);
419         printf("  elt_size=%"PRIu32"\n", mp->elt_size);
420         printf("  trailer_size=%"PRIu32"\n", mp->trailer_size);
421         printf("  total_obj_size=%"PRIu32"\n",
422                mp->header_size + mp->elt_size + mp->trailer_size);
423
424         cache_count = rte_mempool_dump_cache(mp);
425         common_count = rte_ring_count(mp->ring);
426         if ((cache_count + common_count) > mp->size)
427                 common_count = mp->size - cache_count;
428         printf("  common_pool_count=%u\n", common_count);
429
430         /* sum and dump statistics */
431 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG
432         memset(&sum, 0, sizeof(sum));
433         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
434                 sum.put_bulk += mp->stats[lcore_id].put_bulk;
435                 sum.put_objs += mp->stats[lcore_id].put_objs;
436                 sum.get_success_bulk += mp->stats[lcore_id].get_success_bulk;
437                 sum.get_success_objs += mp->stats[lcore_id].get_success_objs;
438                 sum.get_fail_bulk += mp->stats[lcore_id].get_fail_bulk;
439                 sum.get_fail_objs += mp->stats[lcore_id].get_fail_objs;
440         }
441         printf("  stats:\n");
442         printf("    put_bulk=%"PRIu64"\n", sum.put_bulk);
443         printf("    put_objs=%"PRIu64"\n", sum.put_objs);
444         printf("    get_success_bulk=%"PRIu64"\n", sum.get_success_bulk);
445         printf("    get_success_objs=%"PRIu64"\n", sum.get_success_objs);
446         printf("    get_fail_bulk=%"PRIu64"\n", sum.get_fail_bulk);
447         printf("    get_fail_objs=%"PRIu64"\n", sum.get_fail_objs);
448 #else
449         printf("  no statistics available\n");
450 #endif
451
452         rte_mempool_audit(mp);
453 }
454
455 /* dump the status of all mempools on the console */
456 void
457 rte_mempool_list_dump(void)
458 {
459         const struct rte_mempool *mp = NULL;
460         struct rte_mempool_list *mempool_list;
461
462         if ((mempool_list = 
463              RTE_TAILQ_LOOKUP_BY_IDX(RTE_TAILQ_MEMPOOL, rte_mempool_list)) == NULL) {
464                 rte_errno = E_RTE_NO_TAILQ;
465                 return; 
466         }
467
468         TAILQ_FOREACH(mp, mempool_list, next) {
469                 rte_mempool_dump(mp);
470         }
471 }
472
473 /* search a mempool from its name */
474 struct rte_mempool *
475 rte_mempool_lookup(const char *name)
476 {
477         struct rte_mempool *mp = NULL;
478         struct rte_mempool_list *mempool_list;
479
480         if ((mempool_list = 
481              RTE_TAILQ_LOOKUP_BY_IDX(RTE_TAILQ_MEMPOOL, rte_mempool_list)) == NULL) {
482                 rte_errno = E_RTE_NO_TAILQ;
483                 return NULL;
484         }
485
486         TAILQ_FOREACH(mp, mempool_list, next) {
487                 if (strncmp(name, mp->name, RTE_MEMPOOL_NAMESIZE) == 0)
488                         break;
489         }
490         if (mp == NULL)
491                 rte_errno = ENOENT;
492
493         return mp;
494 }