Currently, the free block bitmap is roughly 4 times larger than it needs to, wasting memory. Let's assume maxsz = 128, minsz = 8 and n_max = 40. Z_MPOOL_LVLS(128, 8) returns 3. The block size for level #0 is 128, the block size for level #1 is 128/4 = 32, and the block size for level #2 is 32/4 = 8. Hence levels 0, 1, and 2 for a total of 3 levels. So far so good. Now let's look at Z_MPOOL_LBIT_WORDS(). We get: Z_MPOOL_LBIT_WORDS_UNCLAMPED(40, 0) = ((40 << 0) + 31) / 32 = 2 Z_MPOOL_LBIT_WORDS_UNCLAMPED(40, 1) = ((40 << 2) + 31) / 32 = 5 Z_MPOOL_LBIT_WORDS_UNCLAMPED(40, 2) = ((40 << 4) + 31) / 32 = 20 None of those are < 2 so Z_MPOOL_LBIT_WORDS() takes the results from Z_MPOOL_LBIT_WORDS_UNCLAMPED(). Finally, let's look at _MPOOL_BITS_SIZE(. It sums all possible levels with Z_MPOOL_LBIT_BYTES() which is: #define Z_MPOOL_LBIT_BYTES(maxsz, minsz, l, n_max) \ (Z_MPOOL_LVLS((maxsz), (minsz)) >= (l) ? \ 4 * Z_MPOOL_LBIT_WORDS((n_max), l) : 0) Or given what we already have: Z_MPOOL_LBIT_BYTES(128, 8, 0, 40) = (3 >= 0) ? 4 * 2 : 0 = 8 Z_MPOOL_LBIT_BYTES(128, 8, 1, 40) = (3 >= 1) ? 4 * 5 : 0 = 20 Z_MPOOL_LBIT_BYTES(128, 8, 2, 40) = (3 >= 2) ? 4 * 20 : 0 = 80 Z_MPOOL_LBIT_BYTES(128, 8, 3, 40) = (3 >= 3) ? 4 * ?? Wait... we're missing this one: Z_MPOOL_LBIT_WORDS_UNCLAMPED(40, 3) = ((40 << 6) + 31) / 32 = 80 then: Z_MPOOL_LBIT_BYTES(128, 8, 3, 40) = (3 >= 3) ? 4 * 80 : 0 = 320 Further levels yeld (3 >= 4), (3 >= 5), etc. so they're all false and produce 0. So this means that we're statically allocating 428 bytes to the bitmap when clearly only the first 3 Z_MPOOL_LBIT_BYTES() results for the corresponding 3 levels that we have should be summed e.g. only 108 bytes. Here the code logic gets confused between level numbers and the number levels, hence the extra allocation which happens to be exponential. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
113 lines
3.4 KiB
C
113 lines
3.4 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef ZEPHYR_INCLUDE_MISC_MEMPOOL_BASE_H_
|
|
#define ZEPHYR_INCLUDE_MISC_MEMPOOL_BASE_H_
|
|
|
|
#include <zephyr/types.h>
|
|
#include <stddef.h>
|
|
|
|
/*
|
|
* Definitions and macros used by both the IRQ-safe k_mem_pool and user-mode
|
|
* compatible sys_mem_pool implementations
|
|
*/
|
|
|
|
struct sys_mem_pool_lvl {
|
|
union {
|
|
u32_t *bits_p;
|
|
u32_t bits;
|
|
};
|
|
sys_dlist_t free_list;
|
|
};
|
|
|
|
#define SYS_MEM_POOL_KERNEL BIT(0)
|
|
#define SYS_MEM_POOL_USER BIT(1)
|
|
|
|
struct sys_mem_pool_base {
|
|
void *buf;
|
|
size_t max_sz;
|
|
u16_t n_max;
|
|
u8_t n_levels;
|
|
s8_t max_inline_level;
|
|
struct sys_mem_pool_lvl *levels;
|
|
u8_t flags;
|
|
};
|
|
|
|
#define _ALIGN4(n) ((((n)+3)/4)*4)
|
|
|
|
#define Z_MPOOL_HAVE_LVL(maxsz, minsz, l) (((maxsz) >> (2*(l))) \
|
|
>= (minsz) ? 1 : 0)
|
|
|
|
#define __MPOOL_LVLS(maxsz, minsz) \
|
|
(Z_MPOOL_HAVE_LVL((maxsz), (minsz), 0) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 1) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 2) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 3) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 4) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 5) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 6) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 7) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 8) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 9) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 10) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 11) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 12) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 13) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 14) + \
|
|
Z_MPOOL_HAVE_LVL((maxsz), (minsz), 15))
|
|
|
|
#define _MPOOL_MINBLK sizeof(sys_dnode_t)
|
|
|
|
#define Z_MPOOL_LVLS(maxsz, minsz) \
|
|
__MPOOL_LVLS((maxsz), (minsz) >= _MPOOL_MINBLK ? (minsz) : \
|
|
_MPOOL_MINBLK)
|
|
|
|
/* Rounds the needed bits up to integer multiples of u32_t */
|
|
#define Z_MPOOL_LBIT_WORDS_UNCLAMPED(n_max, l) \
|
|
((((n_max) << (2*(l))) + 31) / 32)
|
|
|
|
/* One word gets stored free unioned with the pointer, otherwise the
|
|
* calculated unclamped value
|
|
*/
|
|
#define Z_MPOOL_LBIT_WORDS(n_max, l) \
|
|
(Z_MPOOL_LBIT_WORDS_UNCLAMPED(n_max, l) < 2 ? 0 \
|
|
: Z_MPOOL_LBIT_WORDS_UNCLAMPED(n_max, l))
|
|
|
|
/* How many bytes for the bitfields of a single level? */
|
|
#define Z_MPOOL_LBIT_BYTES(maxsz, minsz, l, n_max) \
|
|
(Z_MPOOL_LVLS((maxsz), (minsz)) > (l) ? \
|
|
4 * Z_MPOOL_LBIT_WORDS((n_max), l) : 0)
|
|
|
|
/* Size of the bitmap array that follows the buffer in allocated memory */
|
|
#define _MPOOL_BITS_SIZE(maxsz, minsz, n_max) \
|
|
(Z_MPOOL_LBIT_BYTES(maxsz, minsz, 0, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 1, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 2, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 3, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 4, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 5, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 6, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 7, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 8, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 9, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 10, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 11, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 12, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 13, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 14, n_max) + \
|
|
Z_MPOOL_LBIT_BYTES(maxsz, minsz, 15, n_max))
|
|
|
|
|
|
void z_sys_mem_pool_base_init(struct sys_mem_pool_base *p);
|
|
|
|
int z_sys_mem_pool_block_alloc(struct sys_mem_pool_base *p, size_t size,
|
|
u32_t *level_p, u32_t *block_p, void **data_p);
|
|
|
|
void z_sys_mem_pool_block_free(struct sys_mem_pool_base *p, u32_t level,
|
|
u32_t block);
|
|
|
|
#endif /* ZEPHYR_INCLUDE_MISC_MEMPOOL_BASE_H_ */
|