kernel: Make the "heap" backend to mem_pool default
Remove the MEM_POOL_HEAP_BACKEND kconfig, treating it as true always. Now the legacy mem_pool cannot be enabled and all usage uses the k_heap/sys_heap backend. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
parent
daed944175
commit
8a6aee9cac
21 changed files with 6 additions and 560 deletions
|
@ -4546,7 +4546,7 @@ void k_heap_free(struct k_heap *h, void *mem);
|
||||||
* If the pool is to be accessed outside the module where it is defined, it
|
* If the pool is to be accessed outside the module where it is defined, it
|
||||||
* can be declared via
|
* can be declared via
|
||||||
*
|
*
|
||||||
* @note When @option{CONFIG_MEM_POOL_HEAP_BACKEND} is enabled, the k_mem_pool
|
* @note The k_mem_pool
|
||||||
* API is implemented on top of a k_heap, which is a more general
|
* API is implemented on top of a k_heap, which is a more general
|
||||||
* purpose allocator which does not make the same promises about
|
* purpose allocator which does not make the same promises about
|
||||||
* splitting or alignment detailed above. Blocks will be aligned only
|
* splitting or alignment detailed above. Blocks will be aligned only
|
||||||
|
|
|
@ -27,11 +27,7 @@
|
||||||
#include <sys/util.h>
|
#include <sys/util.h>
|
||||||
#include <sys/mempool_base.h>
|
#include <sys/mempool_base.h>
|
||||||
#include <kernel_structs.h>
|
#include <kernel_structs.h>
|
||||||
#ifdef CONFIG_MEM_POOL_HEAP_BACKEND
|
|
||||||
#include <mempool_heap.h>
|
#include <mempool_heap.h>
|
||||||
#else
|
|
||||||
#include <mempool_sys.h>
|
|
||||||
#endif
|
|
||||||
#include <kernel_version.h>
|
#include <kernel_version.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <sys/printk.h>
|
#include <sys/printk.h>
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ZEPHYR_INCLUDE_MEMPOOL_SYS_H_
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup mem_pool_apis Memory Pool APIs
|
|
||||||
* @ingroup kernel_apis
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Note on sizing: the use of a 20 bit field for block means that,
|
|
||||||
* assuming a reasonable minimum block size of 16 bytes, we're limited
|
|
||||||
* to 16M of memory managed by a single pool. Long term it would be
|
|
||||||
* good to move to a variable bit size based on configuration.
|
|
||||||
*/
|
|
||||||
struct k_mem_block_id {
|
|
||||||
uint32_t pool : 8;
|
|
||||||
uint32_t level : 4;
|
|
||||||
uint32_t block : 20;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct k_mem_block {
|
|
||||||
void *data;
|
|
||||||
struct k_mem_block_id id;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
struct k_mem_pool {
|
|
||||||
struct sys_mem_pool_base base;
|
|
||||||
_wait_q_t wait_q;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define Z_MEM_POOL_DEFINE(name, minsz, maxsz, nmax, align) \
|
|
||||||
char __aligned(WB_UP(align)) _mpool_buf_##name[WB_UP(maxsz) * nmax \
|
|
||||||
+ _MPOOL_BITS_SIZE(maxsz, minsz, nmax)]; \
|
|
||||||
struct sys_mem_pool_lvl \
|
|
||||||
_mpool_lvls_##name[Z_MPOOL_LVLS(maxsz, minsz)]; \
|
|
||||||
Z_STRUCT_SECTION_ITERABLE(k_mem_pool, name) = { \
|
|
||||||
.base = { \
|
|
||||||
.buf = _mpool_buf_##name, \
|
|
||||||
.max_sz = WB_UP(maxsz), \
|
|
||||||
.n_max = nmax, \
|
|
||||||
.n_levels = Z_MPOOL_LVLS(maxsz, minsz), \
|
|
||||||
.levels = _mpool_lvls_##name, \
|
|
||||||
.flags = SYS_MEM_POOL_KERNEL \
|
|
||||||
} \
|
|
||||||
}; \
|
|
||||||
BUILD_ASSERT(WB_UP(maxsz) >= _MPOOL_MINBLK)
|
|
||||||
|
|
||||||
#endif /* ZEPHYR_INCLUDE_MEMPOOL_SYS_H_ */
|
|
|
@ -52,11 +52,6 @@ target_sources_ifdef(CONFIG_POLL kernel PRIVATE poll.c)
|
||||||
|
|
||||||
if(${CONFIG_KERNEL_MEM_POOL})
|
if(${CONFIG_KERNEL_MEM_POOL})
|
||||||
target_sources(kernel PRIVATE mempool.c)
|
target_sources(kernel PRIVATE mempool.c)
|
||||||
|
|
||||||
if(${CONFIG_MEM_POOL_HEAP_BACKEND})
|
|
||||||
else()
|
|
||||||
target_sources(kernel PRIVATE mempool_sys.c)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT CONFIG_MULTITHREADING)
|
if(NOT CONFIG_MULTITHREADING)
|
||||||
|
|
|
@ -502,16 +502,6 @@ config KERNEL_MEM_POOL
|
||||||
|
|
||||||
if KERNEL_MEM_POOL
|
if KERNEL_MEM_POOL
|
||||||
|
|
||||||
config MEM_POOL_HEAP_BACKEND
|
|
||||||
bool "Use k_heap as the backend for k_mem_pool"
|
|
||||||
default y
|
|
||||||
help
|
|
||||||
This selects a backend implementation for k_mem_pool based
|
|
||||||
on the sys_heap abstraction instead of the legacy
|
|
||||||
sys_mem_pool. This backend has significantly better
|
|
||||||
performance and memory utilization for general purpose
|
|
||||||
workloads.
|
|
||||||
|
|
||||||
config HEAP_MEM_POOL_SIZE
|
config HEAP_MEM_POOL_SIZE
|
||||||
int "Heap memory pool size (in bytes)"
|
int "Heap memory pool size (in bytes)"
|
||||||
default 0 if !POSIX_MQUEUE
|
default 0 if !POSIX_MQUEUE
|
||||||
|
|
|
@ -64,7 +64,6 @@ void k_heap_free(struct k_heap *h, void *mem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MEM_POOL_HEAP_BACKEND
|
|
||||||
/* Compatibility layer for legacy k_mem_pool code on top of a k_heap
|
/* Compatibility layer for legacy k_mem_pool code on top of a k_heap
|
||||||
* backend.
|
* backend.
|
||||||
*/
|
*/
|
||||||
|
@ -89,5 +88,3 @@ void k_mem_pool_free_id(struct k_mem_block_id *id)
|
||||||
{
|
{
|
||||||
k_heap_free(id->heap, id->data);
|
k_heap_free(id->heap, id->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_MEM_POOL_HEAP_BACKEND */
|
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017, 2020 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <kernel.h>
|
|
||||||
#include <ksched.h>
|
|
||||||
#include <wait_q.h>
|
|
||||||
#include <init.h>
|
|
||||||
|
|
||||||
static struct k_spinlock lock;
|
|
||||||
|
|
||||||
static struct k_mem_pool *get_pool(int id)
|
|
||||||
{
|
|
||||||
extern struct k_mem_pool _k_mem_pool_list_start[];
|
|
||||||
|
|
||||||
return &_k_mem_pool_list_start[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pool_id(struct k_mem_pool *pool)
|
|
||||||
{
|
|
||||||
extern struct k_mem_pool _k_mem_pool_list_start[];
|
|
||||||
|
|
||||||
return pool - &_k_mem_pool_list_start[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void k_mem_pool_init(struct k_mem_pool *p)
|
|
||||||
{
|
|
||||||
z_waitq_init(&p->wait_q);
|
|
||||||
z_sys_mem_pool_base_init(&p->base);
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_static_pools(const struct device *unused)
|
|
||||||
{
|
|
||||||
ARG_UNUSED(unused);
|
|
||||||
|
|
||||||
Z_STRUCT_SECTION_FOREACH(k_mem_pool, p) {
|
|
||||||
k_mem_pool_init(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_INIT(init_static_pools, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
|
|
||||||
|
|
||||||
int k_mem_pool_alloc(struct k_mem_pool *p, struct k_mem_block *block,
|
|
||||||
size_t size, k_timeout_t timeout)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
uint64_t end = 0;
|
|
||||||
|
|
||||||
__ASSERT(!(arch_is_in_isr() && !K_TIMEOUT_EQ(timeout, K_NO_WAIT)), "");
|
|
||||||
|
|
||||||
end = z_timeout_end_calc(timeout);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
uint32_t level_num, block_num;
|
|
||||||
|
|
||||||
ret = z_sys_mem_pool_block_alloc(&p->base, size,
|
|
||||||
&level_num, &block_num,
|
|
||||||
&block->data);
|
|
||||||
block->id.pool = pool_id(p);
|
|
||||||
block->id.level = level_num;
|
|
||||||
block->id.block = block_num;
|
|
||||||
|
|
||||||
if (ret == 0 || K_TIMEOUT_EQ(timeout, K_NO_WAIT) ||
|
|
||||||
ret != -ENOMEM) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
z_pend_curr_unlocked(&p->wait_q, timeout);
|
|
||||||
|
|
||||||
if (!K_TIMEOUT_EQ(timeout, K_FOREVER)) {
|
|
||||||
int64_t remaining = end - z_tick_get();
|
|
||||||
|
|
||||||
if (remaining <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
timeout = Z_TIMEOUT_TICKS(remaining);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
void k_mem_pool_free_id(struct k_mem_block_id *id)
|
|
||||||
{
|
|
||||||
int need_sched = 0;
|
|
||||||
struct k_mem_pool *p = get_pool(id->pool);
|
|
||||||
|
|
||||||
z_sys_mem_pool_block_free(&p->base, id->level, id->block);
|
|
||||||
|
|
||||||
/* Wake up anyone blocked on this pool and let them repeat
|
|
||||||
* their allocation attempts
|
|
||||||
*
|
|
||||||
* (Note that this spinlock only exists because z_unpend_all()
|
|
||||||
* is unsynchronized. Maybe we want to put the lock into the
|
|
||||||
* wait_q instead and make the API safe?)
|
|
||||||
*/
|
|
||||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
|
||||||
|
|
||||||
need_sched = z_unpend_all(&p->wait_q);
|
|
||||||
|
|
||||||
if (need_sched != 0) {
|
|
||||||
z_reschedule(&lock, key);
|
|
||||||
} else {
|
|
||||||
k_spin_unlock(&lock, key);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -28,7 +28,6 @@ void test_main(void)
|
||||||
ztest_unit_test(test_mheap_malloc_free),
|
ztest_unit_test(test_mheap_malloc_free),
|
||||||
ztest_unit_test(test_mheap_calloc),
|
ztest_unit_test(test_mheap_calloc),
|
||||||
ztest_unit_test(test_mheap_malloc_align4),
|
ztest_unit_test(test_mheap_malloc_align4),
|
||||||
ztest_unit_test(test_mheap_min_block_size),
|
|
||||||
ztest_unit_test(test_mheap_block_desc),
|
ztest_unit_test(test_mheap_block_desc),
|
||||||
ztest_unit_test(test_mheap_block_release));
|
ztest_unit_test(test_mheap_block_release));
|
||||||
ztest_run_test_suite(mheap_api);
|
ztest_run_test_suite(mheap_api);
|
||||||
|
|
|
@ -45,57 +45,6 @@ void test_mheap_malloc_align4(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The test case to ensure heap minimum block size is 64 bytes.
|
|
||||||
*
|
|
||||||
* @ingroup kernel_heap_tests
|
|
||||||
*
|
|
||||||
* @see k_malloc(), k_free()
|
|
||||||
*
|
|
||||||
* @details Heap pool's minimum block size is 64 bytes. The test case tries
|
|
||||||
* to ensure it by allocating blocks lesser than minimum block size.
|
|
||||||
* The test allocates 8 blocks of size 0. The algorithm has to allocate 64
|
|
||||||
* bytes of blocks, this is ensured by allocating one more block of max size
|
|
||||||
* which results in failure. Finally all the blocks are freed and added back
|
|
||||||
* to heap memory pool.
|
|
||||||
*/
|
|
||||||
void test_mheap_min_block_size(void)
|
|
||||||
{
|
|
||||||
void *block[BLK_NUM_MAX], *block_fail;
|
|
||||||
|
|
||||||
/* The k_heap backend doesn't have the splitting behavior
|
|
||||||
* expected here, this test is too specific, and a more
|
|
||||||
* general version of the same test is available in
|
|
||||||
* test_mheap_malloc_free()
|
|
||||||
*/
|
|
||||||
if (IS_ENABLED(CONFIG_MEM_POOL_HEAP_BACKEND)) {
|
|
||||||
ztest_test_skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TESTPOINT: The heap memory pool also defines a minimum block
|
|
||||||
* size of 64 bytes.
|
|
||||||
* Test steps:
|
|
||||||
* initial memory heap status (F for free, U for used):
|
|
||||||
* 64F, 64F, 64F, 64F
|
|
||||||
* 1. request 4 blocks: each 0-byte plus 16-byte block desc,
|
|
||||||
* indeed 64-byte allocated
|
|
||||||
* 2. verify no more free blocks, any further allocation failed
|
|
||||||
*/
|
|
||||||
for (int i = 0; i < BLK_NUM_MAX; i++) {
|
|
||||||
block[i] = k_malloc(TEST_SIZE_0);
|
|
||||||
zassert_not_null(block[i], NULL);
|
|
||||||
}
|
|
||||||
/* verify no more free blocks available*/
|
|
||||||
block_fail = k_malloc(BLK_SIZE_MIN);
|
|
||||||
zassert_is_null(block_fail, NULL);
|
|
||||||
|
|
||||||
/* test case tear down*/
|
|
||||||
for (int i = 0; i < BLK_NUM_MAX; i++) {
|
|
||||||
k_free(block[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Verify if the block descriptor is included
|
* @brief Verify if the block descriptor is included
|
||||||
* in every block which is allocated
|
* in every block which is allocated
|
||||||
|
|
|
@ -34,12 +34,10 @@
|
||||||
* depends on words size. So we keep separate tables for different
|
* depends on words size. So we keep separate tables for different
|
||||||
* configs.
|
* configs.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_MEM_POOL_HEAP_BACKEND
|
#ifdef CONFIG_64BIT
|
||||||
# ifdef CONFIG_64BIT
|
# define HEAP64
|
||||||
# define HEAP64
|
#else
|
||||||
# else
|
# define HEAP32
|
||||||
# define HEAP32
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* size of stack area used by each thread */
|
/* size of stack area used by each thread */
|
||||||
|
@ -317,12 +315,6 @@ void alternate_task(void)
|
||||||
* amount of usable space, due to the hidden block descriptor info the
|
* amount of usable space, due to the hidden block descriptor info the
|
||||||
* kernel adds at the start of any block allocated from this memory pool.)
|
* kernel adds at the start of any block allocated from this memory pool.)
|
||||||
*
|
*
|
||||||
* NOTE: when CONFIG_MEM_POOL_HEAP_BACKEND is in use, the splitting
|
|
||||||
* algorithm being exercised by this test is not used. In fact the
|
|
||||||
* k_heap backend is significantly more fragmentation resistant, so
|
|
||||||
* calls expected to fail here actually succeed. These are disabled
|
|
||||||
* here.
|
|
||||||
*
|
|
||||||
* @see k_malloc(), k_free()
|
* @see k_malloc(), k_free()
|
||||||
*/
|
*/
|
||||||
static void test_pool_malloc(void)
|
static void test_pool_malloc(void)
|
||||||
|
@ -334,12 +326,6 @@ static void test_pool_malloc(void)
|
||||||
block[0] = k_malloc(150);
|
block[0] = k_malloc(150);
|
||||||
zassert_not_null(block[0], "150 byte allocation failed");
|
zassert_not_null(block[0], "150 byte allocation failed");
|
||||||
|
|
||||||
#ifndef CONFIG_MEM_POOL_HEAP_BACKEND
|
|
||||||
/* ensure a small block can no longer be allocated */
|
|
||||||
block[1] = k_malloc(16);
|
|
||||||
zassert_is_null(block[1], "16 byte allocation did not fail");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* return the large block */
|
/* return the large block */
|
||||||
k_free(block[0]);
|
k_free(block[0]);
|
||||||
|
|
||||||
|
@ -347,23 +333,12 @@ static void test_pool_malloc(void)
|
||||||
block[0] = k_malloc(16);
|
block[0] = k_malloc(16);
|
||||||
zassert_not_null(block[0], "16 byte allocation 0 failed");
|
zassert_not_null(block[0], "16 byte allocation 0 failed");
|
||||||
|
|
||||||
#ifndef CONFIG_MEM_POOL_HEAP_BACKEND
|
|
||||||
/* ensure a large block can no longer be allocated */
|
|
||||||
block[1] = k_malloc(80);
|
|
||||||
zassert_is_null(block[1], "80 byte allocation did not fail");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ensure all remaining small blocks can be allocated */
|
/* ensure all remaining small blocks can be allocated */
|
||||||
for (j = 1; j < 4; j++) {
|
for (j = 1; j < 4; j++) {
|
||||||
block[j] = k_malloc(16);
|
block[j] = k_malloc(16);
|
||||||
zassert_not_null(block[j], "16 byte allocation %d failed\n", j);
|
zassert_not_null(block[j], "16 byte allocation %d failed\n", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_MEM_POOL_HEAP_BACKEND
|
|
||||||
/* ensure a small block can no longer be allocated */
|
|
||||||
zassert_is_null(k_malloc(8), "8 byte allocation did not fail");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* return the small blocks to pool in a "random" order */
|
/* return the small blocks to pool in a "random" order */
|
||||||
k_free(block[2]);
|
k_free(block[2]);
|
||||||
k_free(block[0]);
|
k_free(block[0]);
|
||||||
|
@ -374,12 +349,6 @@ static void test_pool_malloc(void)
|
||||||
block[0] = k_malloc(100);
|
block[0] = k_malloc(100);
|
||||||
zassert_not_null(block[0], "100 byte allocation failed");
|
zassert_not_null(block[0], "100 byte allocation failed");
|
||||||
|
|
||||||
|
|
||||||
#ifndef CONFIG_MEM_POOL_HEAP_BACKEND
|
|
||||||
/* ensure a small block can no longer be allocated */
|
|
||||||
zassert_is_null(k_malloc(32), "32 byte allocation did not fail");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ensure overflow detection is working */
|
/* ensure overflow detection is working */
|
||||||
zassert_is_null(k_malloc(0xffffffff), "overflow check failed");
|
zassert_is_null(k_malloc(0xffffffff), "overflow check failed");
|
||||||
zassert_is_null(k_calloc(0xffffffff, 2), "overflow check failed");
|
zassert_is_null(k_calloc(0xffffffff, 2), "overflow check failed");
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
tests:
|
tests:
|
||||||
kernel.memory_pool:
|
kernel.memory_pool:
|
||||||
tags: kernel mem_pool
|
tags: kernel mem_pool
|
||||||
kernel.memory_pool.legacy:
|
|
||||||
min_ram: 32
|
|
||||||
tags: kernel mem_pool
|
|
||||||
extra_configs:
|
|
||||||
- CONFIG_MEM_POOL_HEAP_BACKEND=n
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
extern void test_mpool_alloc_free_thread(void);
|
extern void test_mpool_alloc_free_thread(void);
|
||||||
extern void test_mpool_alloc_free_isr(void);
|
extern void test_mpool_alloc_free_isr(void);
|
||||||
extern void test_mpool_kdefine_extern(void);
|
extern void test_mpool_kdefine_extern(void);
|
||||||
extern void test_mpool_alloc_size(void);
|
|
||||||
extern void test_mpool_alloc_timeout(void);
|
extern void test_mpool_alloc_timeout(void);
|
||||||
extern void test_sys_heap_mem_pool_assign(void);
|
extern void test_sys_heap_mem_pool_assign(void);
|
||||||
|
|
||||||
|
@ -28,7 +27,6 @@ void test_main(void)
|
||||||
ztest_unit_test(test_mpool_alloc_free_thread),
|
ztest_unit_test(test_mpool_alloc_free_thread),
|
||||||
ztest_unit_test(test_mpool_alloc_free_isr),
|
ztest_unit_test(test_mpool_alloc_free_isr),
|
||||||
ztest_unit_test(test_mpool_kdefine_extern),
|
ztest_unit_test(test_mpool_kdefine_extern),
|
||||||
ztest_unit_test(test_mpool_alloc_size),
|
|
||||||
ztest_unit_test(test_mpool_alloc_timeout),
|
ztest_unit_test(test_mpool_alloc_timeout),
|
||||||
ztest_unit_test(test_sys_heap_mem_pool_assign)
|
ztest_unit_test(test_sys_heap_mem_pool_assign)
|
||||||
);
|
);
|
||||||
|
|
|
@ -87,64 +87,6 @@ void test_mpool_alloc_free_isr(void)
|
||||||
irq_offload(tmpool_alloc_free, NULL);
|
irq_offload(tmpool_alloc_free, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @ingroup kernel_memory_pool_tests
|
|
||||||
* @brief Validates breaking a block into quarters feature
|
|
||||||
*
|
|
||||||
* @details The test case validates how a mem_pool provides
|
|
||||||
* functionality to break a block into quarters and repeatedly
|
|
||||||
* allocate and free the blocks.
|
|
||||||
* @see k_mem_pool_alloc(), k_mem_pool_free()
|
|
||||||
*/
|
|
||||||
void test_mpool_alloc_size(void)
|
|
||||||
{
|
|
||||||
static struct k_mem_block block[BLK_NUM_MIN];
|
|
||||||
size_t size = BLK_SIZE_MAX;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
/* The sys_heap backend doesn't use the specific block
|
|
||||||
* breaking algorithm tested here. This is a test of the
|
|
||||||
* legacy sys_mem_pool allocator only.
|
|
||||||
*/
|
|
||||||
if (IS_ENABLED(CONFIG_MEM_POOL_HEAP_BACKEND)) {
|
|
||||||
ztest_test_skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**TESTPOINT: The memory pool allows blocks to be repeatedly partitioned
|
|
||||||
* into quarters, down to blocks of @a min_size bytes long.
|
|
||||||
*/
|
|
||||||
while (size >= BLK_SIZE_MIN) {
|
|
||||||
zassert_true(k_mem_pool_alloc(&kmpool, &block[i], size,
|
|
||||||
K_NO_WAIT) == 0, NULL);
|
|
||||||
zassert_not_null(block[i].data, NULL);
|
|
||||||
zassert_true((uintptr_t)(block[i].data) % BLK_ALIGN == 0, NULL);
|
|
||||||
i++;
|
|
||||||
size = size >> 2;
|
|
||||||
}
|
|
||||||
while (i--) {
|
|
||||||
k_mem_pool_free(&block[i]);
|
|
||||||
block[i].data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
size = BLK_SIZE_MIN;
|
|
||||||
/**TESTPOINT: To ensure that all blocks in the buffer are similarly
|
|
||||||
* aligned to this boundary, min_size must also be a multiple of align.
|
|
||||||
*/
|
|
||||||
while (size <= BLK_SIZE_MAX) {
|
|
||||||
zassert_true(k_mem_pool_alloc(&kmpool, &block[i], size,
|
|
||||||
K_NO_WAIT) == 0, NULL);
|
|
||||||
zassert_not_null(block[i].data, NULL);
|
|
||||||
zassert_true((uintptr_t)(block[i].data) % BLK_ALIGN == 0, NULL);
|
|
||||||
i++;
|
|
||||||
size = size << 2;
|
|
||||||
}
|
|
||||||
while (i--) {
|
|
||||||
k_mem_pool_free(&block[i]);
|
|
||||||
block[i].data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see k_mem_pool_alloc(), k_mem_pool_free()
|
* @see k_mem_pool_alloc(), k_mem_pool_free()
|
||||||
* @brief Verify memory pool allocation with timeouts
|
* @brief Verify memory pool allocation with timeouts
|
||||||
|
@ -164,16 +106,7 @@ void test_mpool_alloc_timeout(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The original mem_pool would always be able to allocate
|
|
||||||
* exactly "min blocks" before running out of space, the
|
|
||||||
* heuristics used to size the sys_heap backend are more
|
|
||||||
* flexible.
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_MEM_POOL_HEAP_BACKEND
|
|
||||||
zassert_true(nb >= BLK_NUM_MIN, NULL);
|
zassert_true(nb >= BLK_NUM_MIN, NULL);
|
||||||
#else
|
|
||||||
zassert_true(nb == BLK_NUM_MIN, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** TESTPOINT: Use K_NO_WAIT to return without waiting*/
|
/** TESTPOINT: Use K_NO_WAIT to return without waiting*/
|
||||||
/** TESTPOINT: @retval -ENOMEM Returned without waiting*/
|
/** TESTPOINT: @retval -ENOMEM Returned without waiting*/
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
tests:
|
tests:
|
||||||
kernel.memory_pool.api:
|
kernel.memory_pool.api:
|
||||||
tags: kernel mem_pool
|
tags: kernel mem_pool
|
||||||
kernel.memory_pool.api.legacy:
|
|
||||||
tags: kernel mem_pool
|
|
||||||
extra_configs:
|
|
||||||
- CONFIG_MEM_POOL_HEAP_BACKEND=n
|
|
||||||
|
|
|
@ -6,17 +6,11 @@
|
||||||
|
|
||||||
#include <ztest.h>
|
#include <ztest.h>
|
||||||
extern void test_mpool_alloc_wait_prio(void);
|
extern void test_mpool_alloc_wait_prio(void);
|
||||||
extern void test_mpool_alloc_size_roundup(void);
|
|
||||||
extern void test_mpool_alloc_merge_failed_diff_size(void);
|
|
||||||
extern void test_mpool_alloc_merge_failed_diff_parent(void);
|
|
||||||
|
|
||||||
/*test case main entry*/
|
/*test case main entry*/
|
||||||
void test_main(void)
|
void test_main(void)
|
||||||
{
|
{
|
||||||
ztest_test_suite(mpool_concept,
|
ztest_test_suite(mpool_concept,
|
||||||
ztest_1cpu_unit_test(test_mpool_alloc_wait_prio),
|
ztest_1cpu_unit_test(test_mpool_alloc_wait_prio));
|
||||||
ztest_unit_test(test_mpool_alloc_size_roundup),
|
|
||||||
ztest_unit_test(test_mpool_alloc_merge_failed_diff_size),
|
|
||||||
ztest_unit_test(test_mpool_alloc_merge_failed_diff_parent));
|
|
||||||
ztest_run_test_suite(mpool_concept);
|
ztest_run_test_suite(mpool_concept);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2016 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ztest.h>
|
|
||||||
#include "test_mpool.h"
|
|
||||||
|
|
||||||
#define TEST_SIZE ((BLK_SIZE_MAX >> 2) + 1)
|
|
||||||
|
|
||||||
extern struct k_mem_pool mpool1;
|
|
||||||
|
|
||||||
/*test cases*/
|
|
||||||
/**
|
|
||||||
* @brief Test alloc and free of different blocks sizes
|
|
||||||
*
|
|
||||||
* @ingroup kernel_memory_pool_tests
|
|
||||||
*
|
|
||||||
* @details The test demonstrates how the request is handled
|
|
||||||
* to allocate the minimum available size block in memory pool
|
|
||||||
* to satisfy the requirement of the application.
|
|
||||||
*/
|
|
||||||
void test_mpool_alloc_size_roundup(void)
|
|
||||||
{
|
|
||||||
struct k_mem_block block[BLK_NUM_MAX], block_fail;
|
|
||||||
|
|
||||||
/* This test is written to assume specific heap layout, in
|
|
||||||
* fact the sys_heap backend can routinely see more than "min
|
|
||||||
* blocks" allocated.
|
|
||||||
*/
|
|
||||||
if (IS_ENABLED(CONFIG_MEM_POOL_HEAP_BACKEND)) {
|
|
||||||
ztest_test_skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TESTPOINT: When an application issues a request for a memory block,
|
|
||||||
* the memory pool first determines the size of the smallest block that
|
|
||||||
* will satisfy the request
|
|
||||||
*/
|
|
||||||
for (int i = 0; i < BLK_NUM_MAX; i++) {
|
|
||||||
/*request a size for the mpool to round up to "BLK_SIZE_MAX"*/
|
|
||||||
zassert_true(k_mem_pool_alloc(&mpool1, &block[i], TEST_SIZE,
|
|
||||||
K_NO_WAIT) == 0, NULL);
|
|
||||||
}
|
|
||||||
/*verify consequently no more blocks available*/
|
|
||||||
zassert_true(k_mem_pool_alloc(&mpool1, &block_fail, BLK_SIZE_MIN,
|
|
||||||
K_NO_WAIT) == -ENOMEM, NULL);
|
|
||||||
|
|
||||||
/*test case tear down*/
|
|
||||||
for (int i = 0; i < BLK_NUM_MAX; i++) {
|
|
||||||
k_mem_pool_free(&block[i]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -63,17 +63,7 @@ void test_mpool_alloc_wait_prio(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The original mem_pool would always be able to allocate
|
|
||||||
* exactly "min blocks" before running out of space, the
|
|
||||||
* heuristics used to size the sys_heap backend are more
|
|
||||||
* flexible.
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_MEM_POOL_HEAP_BACKEND
|
|
||||||
zassert_true(nb >= BLK_NUM_MIN, "nb %d want %d", nb, BLK_NUM_MIN);
|
zassert_true(nb >= BLK_NUM_MIN, "nb %d want %d", nb, BLK_NUM_MIN);
|
||||||
#else
|
|
||||||
zassert_true(nb == BLK_NUM_MIN, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TESTPOINT: when a suitable memory block becomes available, it is
|
* TESTPOINT: when a suitable memory block becomes available, it is
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2016 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ztest.h>
|
|
||||||
#include "test_mpool.h"
|
|
||||||
|
|
||||||
extern struct k_mem_pool mpool1;
|
|
||||||
|
|
||||||
/*test cases*/
|
|
||||||
/**
|
|
||||||
* @brief Test to verify merge of blocks of different quad-block
|
|
||||||
*
|
|
||||||
* @ingroup kernel_memory_pool_tests
|
|
||||||
*
|
|
||||||
* @details TESTPOINT: The algo cannot merge adjacent free blocks
|
|
||||||
* of the same size if they belong to different parent quad-blocks
|
|
||||||
* Test steps: 1. allocate block [0~7] in minimum block size
|
|
||||||
* 2. free block [2~5], belong to diff parental quad-blocks
|
|
||||||
* 3. request a big block
|
|
||||||
* verify blocks [2, 3] and blocks [4, 5] can't be merged
|
|
||||||
* 4. tear down, free blocks [0, 1, 6, 7]
|
|
||||||
*/
|
|
||||||
void test_mpool_alloc_merge_failed_diff_parent(void)
|
|
||||||
{
|
|
||||||
/* The heap backend doesn't use the splitting mechanism tested
|
|
||||||
* here, and in fact is significantly more fragmentation
|
|
||||||
* resistant and succeeds at the "failed" allocation desired
|
|
||||||
* below.
|
|
||||||
*/
|
|
||||||
if (IS_ENABLED(CONFIG_MEM_POOL_HEAP_BACKEND)) {
|
|
||||||
ztest_test_skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct k_mem_block block[BLK_NUM_MIN], block_fail;
|
|
||||||
|
|
||||||
for (int i = 0; i < BLK_NUM_MIN; i++) {
|
|
||||||
/* 1. allocated up all blocks*/
|
|
||||||
zassert_true(k_mem_pool_alloc(&mpool1, &block[i], BLK_SIZE_MIN,
|
|
||||||
K_NO_WAIT) == 0, NULL);
|
|
||||||
}
|
|
||||||
/* 2. free adjacent blocks belong to different parent quad-blocks*/
|
|
||||||
for (int i = 2; i < 6; i++) {
|
|
||||||
k_mem_pool_free(&block[i]);
|
|
||||||
}
|
|
||||||
/* 3. request a big block, expected failed to merge*/
|
|
||||||
zassert_true(k_mem_pool_alloc(&mpool1, &block_fail, BLK_SIZE_MAX,
|
|
||||||
TIMEOUT) == -EAGAIN, NULL);
|
|
||||||
|
|
||||||
/* 4. test case tear down*/
|
|
||||||
k_mem_pool_free(&block[0]);
|
|
||||||
k_mem_pool_free(&block[1]);
|
|
||||||
k_mem_pool_free(&block[6]);
|
|
||||||
k_mem_pool_free(&block[7]);
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2016 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ztest.h>
|
|
||||||
#define TIMEOUT K_MSEC(2000)
|
|
||||||
#define BLK_SIZE_MIN 16
|
|
||||||
#define BLK_SIZE_MID 32
|
|
||||||
#define BLK_SIZE_MAX 256
|
|
||||||
#define BLK_NUM_MIN 32
|
|
||||||
#define BLK_NUM_MAX 2
|
|
||||||
#define BLK_ALIGN BLK_SIZE_MIN
|
|
||||||
|
|
||||||
K_MEM_POOL_DEFINE(mpool3, BLK_SIZE_MIN, BLK_SIZE_MAX, BLK_NUM_MAX, BLK_ALIGN);
|
|
||||||
|
|
||||||
/*test cases*/
|
|
||||||
/**
|
|
||||||
* @brief Verify blocks of different sizes cannot be merged.
|
|
||||||
*
|
|
||||||
* @ingroup kernel_memory_pool_tests
|
|
||||||
*
|
|
||||||
* @details The merging algorithm cannot combine adjacent free blocks
|
|
||||||
* of different sizes
|
|
||||||
* Test steps: 1. allocate 14 blocks in different sizes
|
|
||||||
* 2. free block [2~8], in different sizes
|
|
||||||
* 3. request a big block verify blocks [2~8] can't be merged
|
|
||||||
* 4. tear down, free blocks [0, 1, 9~13]
|
|
||||||
*/
|
|
||||||
void test_mpool_alloc_merge_failed_diff_size(void)
|
|
||||||
{
|
|
||||||
/* The heap backend doesn't use the splitting mechanism tested
|
|
||||||
* here, and in fact is significantly more fragmentation
|
|
||||||
* resistant and succeeds at the "failed" allocation desired
|
|
||||||
* below.
|
|
||||||
*/
|
|
||||||
if (IS_ENABLED(CONFIG_MEM_POOL_HEAP_BACKEND)) {
|
|
||||||
ztest_test_skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct k_mem_block block[BLK_NUM_MIN], block_fail;
|
|
||||||
size_t block_size[] = {
|
|
||||||
BLK_SIZE_MIN, BLK_SIZE_MIN, BLK_SIZE_MIN, BLK_SIZE_MIN,
|
|
||||||
BLK_SIZE_MID, BLK_SIZE_MID, BLK_SIZE_MID,
|
|
||||||
BLK_SIZE_MIN, BLK_SIZE_MIN, BLK_SIZE_MIN, BLK_SIZE_MIN,
|
|
||||||
BLK_SIZE_MID, BLK_SIZE_MID, BLK_SIZE_MID
|
|
||||||
};
|
|
||||||
int block_count = ARRAY_SIZE(block_size);
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < block_count; i++) {
|
|
||||||
/* 1. allocate blocks in different sizes*/
|
|
||||||
zassert_true(k_mem_pool_alloc(&mpool3, &block[i], block_size[i],
|
|
||||||
K_NO_WAIT) == 0, NULL);
|
|
||||||
}
|
|
||||||
/* 2. free block [2~8], in different sizes*/
|
|
||||||
for (int i = 2; i < 9; i++) {
|
|
||||||
k_mem_pool_free(&block[i]);
|
|
||||||
}
|
|
||||||
/* 3. request a big block, expected failed to merge*/
|
|
||||||
zassert_true(k_mem_pool_alloc(&mpool3, &block_fail, BLK_SIZE_MAX,
|
|
||||||
TIMEOUT) == -EAGAIN, NULL);
|
|
||||||
|
|
||||||
/* 4. test case tear down*/
|
|
||||||
k_mem_pool_free(&block[0]);
|
|
||||||
k_mem_pool_free(&block[1]);
|
|
||||||
for (int i = 9; i < block_count; i++) {
|
|
||||||
k_mem_pool_free(&block[i]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,3 @@
|
||||||
tests:
|
tests:
|
||||||
kernel.memory_pool.concept:
|
kernel.memory_pool.concept:
|
||||||
tags: kernel mem_pool
|
tags: kernel mem_pool
|
||||||
kernel.memory_pool.concept.legacy:
|
|
||||||
tags: kernel mem_pool
|
|
||||||
extra_configs:
|
|
||||||
- CONFIG_MEM_POOL_HEAP_BACKEND=n
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
tests:
|
tests:
|
||||||
kernel.memory_pool.threadsafe:
|
kernel.memory_pool.threadsafe:
|
||||||
tags: kernel mem_pool
|
tags: kernel mem_pool
|
||||||
kernel.memory_pool.threadsafe.legacy:
|
|
||||||
tags: kernel mem_pool
|
|
||||||
extra_configs:
|
|
||||||
- CONFIG_MEM_POOL_HEAP_BACKEND=n
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue