Skip to content

my work on "sys_heap: a new/simpler/faster memory allocator" #19602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -4269,6 +4269,9 @@ static inline u32_t k_mem_slab_num_free_get(struct k_mem_slab *slab)

/** @} */

#ifdef CONFIG_SYS_HEAP_MEMPOOL_COMPAT
#include <sys/heap-k_mempool-compat.h>
#else
/**
* @cond INTERNAL_HIDDEN
*/
Expand Down Expand Up @@ -4322,6 +4325,7 @@ struct k_mem_pool {
} \
}; \
BUILD_ASSERT(WB_UP(maxsz) >= _MPOOL_MINBLK)
#endif

/**
* @brief Allocate memory from a memory pool.
Expand Down
2 changes: 2 additions & 0 deletions include/kernel_includes.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
#include <sys/slist.h>
#include <sys/sflist.h>
#include <sys/util.h>
#ifndef CONFIG_SYS_HEAP_MEMPOOL_COMPAT
#include <sys/mempool_base.h>
#endif
#include <kernel_version.h>
#include <random/rand32.h>
#include <kernel_arch_thread.h>
Expand Down
134 changes: 134 additions & 0 deletions include/sys/heap-compat-common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright (c) 2019 BayLibre SAS
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_SYS_HEAP_COMPAT_H_
#define ZEPHYR_INCLUDE_SYS_HEAP_COMPAT_H_

#include <zephyr/types.h>
#include <sys/util.h>

/*
* Internal heap structures copied from lib/os/heap.h
*
* This lives here only for the sake of mempool compatibility wrappers.
* This ought to move back to a more private location eventually.
*/

#define CHUNK_UNIT 8

typedef size_t chunkid_t;

struct z_heap_bucket {
chunkid_t next;
size_t list_size;
};

struct z_heap {
u64_t chunk0_hdr_area; /* matches the largest header */
u32_t len;
u32_t avail_buckets;
struct z_heap_bucket buckets[0];
};

/*
* This normally depends on the heap size, but our heap size depends on this.
* Let's assume big_heap() would be true.
*/
#define CHUNK_HEADER_BYTES 8

/*
* Returns integer value for log2 of x, or a large negative value otherwise.
* This is made so it can be used for constant compile-time evaluation.
*/
#define z_constant_ilog2(x) \
( __builtin_constant_p(x) ? ( \
((x) & (1 << 31)) ? 31 : \
((x) & (1 << 30)) ? 30 : \
((x) & (1 << 29)) ? 29 : \
((x) & (1 << 28)) ? 28 : \
((x) & (1 << 27)) ? 27 : \
((x) & (1 << 26)) ? 26 : \
((x) & (1 << 25)) ? 25 : \
((x) & (1 << 24)) ? 24 : \
((x) & (1 << 23)) ? 23 : \
((x) & (1 << 22)) ? 22 : \
((x) & (1 << 21)) ? 21 : \
((x) & (1 << 20)) ? 20 : \
((x) & (1 << 19)) ? 19 : \
((x) & (1 << 18)) ? 18 : \
((x) & (1 << 17)) ? 17 : \
((x) & (1 << 16)) ? 16 : \
((x) & (1 << 15)) ? 15 : \
((x) & (1 << 14)) ? 14 : \
((x) & (1 << 13)) ? 13 : \
((x) & (1 << 12)) ? 12 : \
((x) & (1 << 11)) ? 11 : \
((x) & (1 << 10)) ? 10 : \
((x) & (1 << 9)) ? 9 : \
((x) & (1 << 8)) ? 8 : \
((x) & (1 << 7)) ? 7 : \
((x) & (1 << 6)) ? 6 : \
((x) & (1 << 5)) ? 5 : \
((x) & (1 << 4)) ? 4 : \
((x) & (1 << 3)) ? 3 : \
((x) & (1 << 2)) ? 2 : \
((x) & (1 << 1)) ? 1 : \
((x) & (1 << 0)) ? 0 : -1000 \
) : -2000 \
)

#define SYS_HEAP_NB_BUCKETS(bytes) \
(z_constant_ilog2((CHUNK_HEADER_BYTES + (bytes) + CHUNK_UNIT - 1) \
/ CHUNK_UNIT) + 1)

#define SYS_HEAP_CHUNK0_SIZE(nb_buckets) \
ROUND_UP(sizeof(struct z_heap) + \
sizeof(struct z_heap_bucket) * (nb_buckets), CHUNK_UNIT)

/*
* The mempool initializer creates support structures according to the
* desired allocatable memory separate from that memory. The heap allocator
* starts with a given buffer and stores its support structures within that
* buffer, leaving the rest as allocatable memory.
*
* The problem with making a compatibility wrapper for the mempool interface
* comes from the fact that figuring out some heap buffer size that will
* contain the desired amount of allocatable memory depends on the size of
* the support structures, which depends on the size of the heap buffer.
* In other words, growing the heap buffer to accommodate the desired
* allocatable memory size might in turn grow the size of the included
* support structure which would not leave as much allocatable memory as
* expected.
*
* So let's do this in two steps: first figure out the buffer size using
* the wanted allocatable memory size, and use that buffer size again to
* figure out the new buffer size. And in this last case let's account for
* one extra bucket to "round up" the size.
*
* Things would be much simpler with struct z_heap outside the heap buffer.
*/

#define SYS_HEAP_BUF_SIZE_1(alloc_bytes) \
(SYS_HEAP_CHUNK0_SIZE(SYS_HEAP_NB_BUCKETS(alloc_bytes)) + \
ROUND_UP(alloc_bytes, CHUNK_UNIT) + \
CHUNK_HEADER_BYTES)

#define SYS_HEAP_BUF_SIZE_2(alloc_bytes) \
(SYS_HEAP_CHUNK0_SIZE(1 + SYS_HEAP_NB_BUCKETS(SYS_HEAP_BUF_SIZE_1(alloc_bytes))) + \
ROUND_UP(alloc_bytes, CHUNK_UNIT) + \
CHUNK_HEADER_BYTES)

/*
* Make sure we can at least accommodate nmax blocks of maxsz bytes by
* accounting the chunk header to go with them, and round it up to a chunk
* unit size. This assumes big_heap will be true. Trying to predict that one
* runs into the same issue as above, so let's keep things simple.
*/
#define SYS_HEAP_BUF_SIZE(maxsz, nmax) \
SYS_HEAP_BUF_SIZE_2(ROUND_UP(CHUNK_HEADER_BYTES + (maxsz), CHUNK_UNIT) \
* (nmax))

#endif
66 changes: 66 additions & 0 deletions include/sys/heap-k_mempool-compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2019 BayLibre SAS
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_SYS_HEAP_KMEMPOOL_COMPAT_H_
#define ZEPHYR_INCLUDE_SYS_HEAP_KMEMPOOL_COMPAT_H_

/*
* This whole wrapper business is of course a hack. And so is the following
* #ifndef to work around situations where sys_heap.h is included first.
*/
#ifndef ZEPHYR_INCLUDE_SYS_SYS_HEAP_H_

#include <sys/heap-compat-common.h>
#include <sys/sys_heap.h>

/*
* ============================================================================
* k_mem_pool compatibility wrappers
* ============================================================================
*/

#define _MPOOL_MINBLK 1

struct k_mem_pool {
struct sys_heap base;
_wait_q_t wait_q;
};

/**
* @brief Wrapper to statically define and initialize a memory pool.
*
* @param name Name of the memory pool.
* @param minsz ignored.
* @param maxsz Size of the largest blocks in the pool (in bytes).
* @param nmax Number of maximum sized blocks in the pool.
* @param align Ignored.
*/
#define K_MEM_POOL_DEFINE(name, minsz, maxsz, nmax, align) \
char __aligned(CHUNK_UNIT) \
_heap_buf_##name[SYS_HEAP_BUF_SIZE(maxsz, nmax)]; \
Z_STRUCT_SECTION_ITERABLE(k_mem_pool, name) = { \
.base = { \
.init_mem = &_heap_buf_##name, \
.init_bytes = SYS_HEAP_BUF_SIZE(maxsz, nmax), \
}, \
}

static inline void z_sys_compat_mem_pool_base_init(struct sys_heap *base)
{
sys_heap_init(base, base->init_mem, base->init_bytes);
}

int z_sys_compat_mem_pool_block_alloc(struct sys_heap *p, size_t size,
u32_t *level_p, u32_t *block_p, void **data_p);
void z_sys_compat_mem_pool_block_free(struct sys_heap *p, u32_t level,
u32_t block);

#define z_sys_mem_pool_base_init z_sys_compat_mem_pool_base_init
#define z_sys_mem_pool_block_alloc z_sys_compat_mem_pool_block_alloc
#define z_sys_mem_pool_block_free z_sys_compat_mem_pool_block_free

#endif
#endif
74 changes: 74 additions & 0 deletions include/sys/heap-sys_mempool-compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2019 BayLibre SAS
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_SYS_HEAP_SYSMEMPOOL_COMPAT_H_
#define ZEPHYR_INCLUDE_SYS_HEAP_SYSMEMPOOL_COMPAT_H_

#include <kernel.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <sys/mutex.h>
#include <sys/heap-compat-common.h>
#include <sys/sys_heap.h>

/*
* ============================================================================
* sys_mem_pool compatibility wrappers
* ============================================================================
*/

struct sys_mem_pool {
struct sys_heap heap;
struct sys_mutex mutex;
};

struct sys_mem_pool_block {
struct sys_mem_pool *pool;
u32_t level : 4;
u32_t block : 28;
};

/**
* @brief Compatibility wrapper for system memory pool using the heap allocator
*
* This pool will not be in an initialized state. You will still need to
* run sys_mem_pool_init() on it before using any other APIs.
*
* @param name Name of the memory pool.
* @param ignored ignored.
* @param minsz ignored.
* @param maxsz Size of the largest blocks in the pool (in bytes).
* @param nmax Number of maximum sized blocks in the pool.
* @param align ignored.
* @param section Destination binary section for pool data
*/
#define SYS_MEM_POOL_DEFINE(name, ignored, minsz, maxsz, nmax, align, section) \
char __aligned(CHUNK_UNIT) Z_GENERIC_SECTION(section) \
_heap_buf_##name[SYS_HEAP_BUF_SIZE(maxsz, nmax)]; \
Z_GENERIC_SECTION(section) struct sys_mem_pool name = { \
.heap = { \
.init_mem = _heap_buf_##name, \
.init_bytes = SYS_HEAP_BUF_SIZE(maxsz, nmax), \
} \
}

static inline void sys_compat_mem_pool_init(struct sys_mem_pool *p)
{
sys_heap_init(&p->heap, p->heap.init_mem, p->heap.init_bytes);
}

void *sys_compat_mem_pool_alloc(struct sys_mem_pool *p, size_t size);

void sys_compat_mem_pool_free(void *ptr);

size_t sys_compat_mem_pool_try_expand_inplace(void *ptr, size_t new_size);

#define sys_mem_pool_init sys_compat_mem_pool_init
#define sys_mem_pool_alloc sys_compat_mem_pool_alloc
#define sys_mem_pool_free sys_compat_mem_pool_free
#define sys_mem_pool_try_expand_inplace sys_compat_mem_pool_try_expand_inplace

#endif
6 changes: 6 additions & 0 deletions include/sys/mempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#ifndef ZEPHYR_INCLUDE_SYS_MEMPOOL_H_
#define ZEPHYR_INCLUDE_SYS_MEMPOOL_H_

#ifdef CONFIG_SYS_HEAP_MEMPOOL_COMPAT
#include <sys/heap-sys_mempool-compat.h>
#else

#include <kernel.h>
#include <sys/mempool_base.h>
#include <sys/mutex.h>
Expand Down Expand Up @@ -112,4 +116,6 @@ void sys_mem_pool_free(void *ptr);
*/
size_t sys_mem_pool_try_expand_inplace(void *ptr, size_t new_size);

#endif /* !CONFIG_SYS_HEAP_MEMPOOL_COMPAT */

#endif
Loading