diff options
| author | Tangyuxin <[email protected]> | 2021-12-16 16:23:58 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-12-16 16:23:58 +0800 |
| commit | d724eed9fc09269c3c6e921c1f8b2df573508419 (patch) | |
| tree | 92f8528e0efbe28d4632692896d0bcaa2e45b3b6 /examples | |
| parent | 874f6c84f19f8ca24ebd00a9a95e7af02afc49a0 (diff) | |
分离内存分配接口与内存分配算法 (#5175)
* [kernel][mem] Multiple instances of small memory allocation algorithm
* [kernel][mem] Change small memory management algorithm memory header flag
* [kernel][mem] Fix assertion problem
* [kernel][slab] Multiple instances of slab memory management algorithm
* [kernel][memheap] Remove rt_malloc/rt_free/rt_realloc and other related memory interfaces
* [kernel][mem] Clean up memory space of small memory management objects
* [kernel][kservice] Add memory application interface and thread protection interface
* [kernel][kservice] Fix function return value problem
* [kernel][memheap] Optimize memheaptrace print
* [kernel][memheap] Support best mode
* [kernel][memory] Remove semaphore lock
* [kernel][memheap] Add locked flag
* [kernel][memory] Support malloc memory in interrupt
* [kernel][memheap] Add 'memheapcheck' cmd
* [kernel][mem] Fix failure to request full memory
* [kernel][memheap] Fix compilation warning
* [kernel][mem] Fix mem realloc ASSERT
* [examples][testcases] Add small mem testcase
* [examples][mem_tc] Modify test memory size
* [examples][testcases] Add slab memory management algorithm test case
* [examples][testcases] fix small memory management algorithm test case
* [kernel][memory] Adjusting memory allocation algorithm object definition and interface
* [kernel][memory] Fix compilation warning
* [examples][utest] Fix mem test case
* [examples][utest] fix slab test case
* [utest][testcases] Shorten test time
* [kernel][memory] Formatting code
* [examples][utest] Adjust test run time
* [examples][utest] Formatting code
* [bsp] update all rtconfig.h
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/utest/testcases/kernel/Kconfig | 10 | ||||
| -rw-r--r-- | examples/utest/testcases/kernel/SConscript | 6 | ||||
| -rw-r--r-- | examples/utest/testcases/kernel/mem_tc.c | 588 | ||||
| -rw-r--r-- | examples/utest/testcases/kernel/slab_tc.c | 323 |
4 files changed, 927 insertions, 0 deletions
diff --git a/examples/utest/testcases/kernel/Kconfig b/examples/utest/testcases/kernel/Kconfig index 08c3022b77..0faa3622fb 100644 --- a/examples/utest/testcases/kernel/Kconfig +++ b/examples/utest/testcases/kernel/Kconfig @@ -5,6 +5,16 @@ config UTEST_MEMHEAP_TC default y depends on RT_USING_MEMHEAP +config UTEST_SMALL_MEM_TC + bool "mem test" + default y + depends on RT_USING_SMALL_MEM + +config UTEST_SLAB_TC + bool "slab test" + default n + depends on RT_USING_SLAB + config UTEST_IRQ_TC bool "IRQ test" default n diff --git a/examples/utest/testcases/kernel/SConscript b/examples/utest/testcases/kernel/SConscript index 0d2645427b..ab98c6065b 100644 --- a/examples/utest/testcases/kernel/SConscript +++ b/examples/utest/testcases/kernel/SConscript @@ -8,6 +8,12 @@ src = Split(''' if GetDepend(['UTEST_MEMHEAP_TC']): src += ['memheap_tc.c'] +if GetDepend(['UTEST_SMALL_MEM_TC']): + src += ['mem_tc.c'] + +if GetDepend(['UTEST_SLAB_TC']): + src += ['slab_tc.c'] + if GetDepend(['UTEST_IRQ_TC']): src += ['irq_tc.c'] diff --git a/examples/utest/testcases/kernel/mem_tc.c b/examples/utest/testcases/kernel/mem_tc.c new file mode 100644 index 0000000000..028876dfa9 --- /dev/null +++ b/examples/utest/testcases/kernel/mem_tc.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-14 tyx the first version + */ + +#include <rtthread.h> +#include <stdlib.h> +#include "utest.h" + +struct rt_small_mem_item +{ + rt_ubase_t pool_ptr; /**< small memory object addr */ +#ifdef ARCH_CPU_64BIT + rt_uint32_t resv; +#endif /* ARCH_CPU_64BIT */ + rt_size_t next; /**< next free item */ + rt_size_t prev; /**< prev free item */ +#ifdef RT_USING_MEMTRACE +#ifdef ARCH_CPU_64BIT + rt_uint8_t thread[8]; /**< thread name */ +#else + rt_uint8_t thread[4]; /**< thread name */ +#endif /* ARCH_CPU_64BIT */ +#endif /* RT_USING_MEMTRACE */ +}; + +struct rt_small_mem +{ + struct rt_memory parent; /**< inherit from rt_memory */ + rt_uint8_t *heap_ptr; /**< pointer to the heap */ + struct rt_small_mem_item *heap_end; + struct rt_small_mem_item *lfree; + rt_size_t mem_size_aligned; /**< aligned memory size */ +}; + +#define MEM_SIZE(_heap, _mem) \ + (((struct rt_small_mem_item *)(_mem))->next - ((rt_ubase_t)(_mem) - \ + (rt_ubase_t)((_heap)->heap_ptr)) - RT_ALIGN(sizeof(struct rt_small_mem_item), RT_ALIGN_SIZE)) + +#define TEST_MEM_SIZE 1024 + +static rt_size_t max_block(struct rt_small_mem *heap) +{ + struct rt_small_mem_item *mem; + rt_size_t max = 0, size; + + for (mem = (struct rt_small_mem_item *)heap->heap_ptr; + mem != heap->heap_end; + mem = (struct rt_small_mem_item *)&heap->heap_ptr[mem->next]) + { + if (((rt_ubase_t)mem->pool_ptr & 0x1) == 0) + { + size = MEM_SIZE(heap, mem); + if (size > max) + { + max = size; + } + } + } + return max; +} + +static int _mem_cmp(void *ptr, rt_uint8_t v, rt_size_t size) +{ + while (size-- != 0) + { + if (*(rt_uint8_t *)ptr != v) + return *(rt_uint8_t *)ptr - v; + } + return 0; +} + +struct mem_test_context +{ + void *ptr; + rt_size_t size; + rt_uint8_t magic; +}; + +static void mem_functional_test(void) +{ + rt_size_t total_size; + rt_uint8_t *buf; + struct rt_small_mem *heap; + rt_uint8_t magic = __LINE__; + + /* Prepare test memory */ + buf = rt_malloc(TEST_MEM_SIZE); + uassert_not_null(buf); + uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf); + rt_memset(buf, 0xAA, TEST_MEM_SIZE); + /* small heap init */ + heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE); + /* get total size */ + total_size = max_block(heap); + uassert_int_not_equal(total_size, 0); + /* + * Allocate all memory at a time and test whether + * the memory allocation release function is effective + */ + { + struct mem_test_context ctx; + ctx.magic = magic++; + ctx.size = max_block(heap); + ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size); + uassert_not_null(ctx.ptr); + rt_memset(ctx.ptr, ctx.magic, ctx.size); + uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0); + rt_smem_free(ctx.ptr); + uassert_int_equal(max_block(heap), total_size); + } + /* + * Apply for memory release sequentially and + * test whether memory block merging is effective + */ + { + rt_size_t i, max_free = 0; + struct mem_test_context ctx[3]; + /* alloc mem */ + for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++) + { + ctx[i].magic = magic++; + ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i); + ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size); + uassert_not_null(ctx[i].ptr); + rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size); + } + /* All memory has been applied. The remaining memory should be 0 */ + uassert_int_equal(max_block(heap), 0); + /* Verify that the memory data is correct */ + for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++) + { + uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0); + } + /* Sequential memory release */ + for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++) + { + uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0); + rt_smem_free(ctx[i].ptr); + max_free += ctx[i].size; + uassert_true(max_block(heap) >= max_free); + } + /* Check whether the memory is fully merged */ + uassert_int_equal(max_block(heap), total_size); + } + /* + * Apply for memory release at an interval to + * test whether memory block merging is effective + */ + { + rt_size_t i, max_free = 0; + struct mem_test_context ctx[3]; + /* alloc mem */ + for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++) + { + ctx[i].magic = magic++; + ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i); + ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size); + uassert_not_null(ctx[i].ptr); + rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size); + } + /* All memory has been applied. The remaining memory should be 0 */ + uassert_int_equal(max_block(heap), 0); + /* Verify that the memory data is correct */ + for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++) + { + uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0); + } + /* Release even address */ + for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++) + { + if (i % 2 == 0) + { + uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0); + rt_smem_free(ctx[i].ptr); + uassert_true(max_block(heap) >= ctx[0].size); + } + } + /* Release odd addresses and merge memory blocks */ + for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++) + { + if (i % 2 != 0) + { + uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0); + rt_smem_free(ctx[i].ptr); + max_free += ctx[i - 1].size + ctx[i + 1].size; + uassert_true(max_block(heap) >= max_free); + } + } + /* Check whether the memory is fully merged */ + uassert_int_equal(max_block(heap), total_size); + } + /* mem realloc test,Small - > Large */ + { + /* Request a piece of memory for subsequent reallocation operations */ + struct mem_test_context ctx[3]; + ctx[0].magic = magic++; + ctx[0].size = max_block(heap) / 3; + ctx[0].ptr = rt_smem_alloc(&heap->parent, ctx[0].size); + uassert_not_null(ctx[0].ptr); + rt_memset(ctx[0].ptr, ctx[0].magic, ctx[0].size); + /* Apply for a small piece of memory and split the continuous memory */ + ctx[1].magic = magic++; + ctx[1].size = RT_ALIGN_SIZE; + ctx[1].ptr = rt_smem_alloc(&heap->parent, ctx[1].size); + uassert_not_null(ctx[1].ptr); + rt_memset(ctx[1].ptr, ctx[1].magic, ctx[1].size); + /* Check whether the maximum memory block is larger than the first piece of memory */ + uassert_true(max_block(heap) > ctx[0].size); + /* Reallocate the first piece of memory */ + ctx[2].magic = magic++; + ctx[2].size = max_block(heap); + ctx[2].ptr = rt_smem_realloc(&heap->parent, ctx[0].ptr, ctx[2].size); + uassert_not_null(ctx[2].ptr); + uassert_int_not_equal(ctx[0].ptr, ctx[2].ptr); + uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[0].magic, ctx[0].size), 0); + rt_memset(ctx[2].ptr, ctx[2].magic, ctx[2].size); + /* Free the second piece of memory */ + uassert_int_equal(_mem_cmp(ctx[1].ptr, ctx[1].magic, ctx[1].size), 0); + rt_smem_free(ctx[1].ptr); + /* Free reallocated memory */ + uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[2].magic, ctx[2].size), 0); + rt_smem_free(ctx[2].ptr); + /* Check memory integrity */ + uassert_int_equal(max_block(heap), total_size); + } + /* mem realloc test,Large - > Small */ + { + rt_size_t max_free; + struct mem_test_context ctx; + /* alloc a piece of memory */ + ctx.magic = magic++; + ctx.size = max_block(heap) / 2; + ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size); + uassert_not_null(ctx.ptr); + rt_memset(ctx.ptr, ctx.magic, ctx.size); + uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0); + /* Get remaining memory */ + max_free = max_block(heap); + /* Change memory size */ + ctx.size = ctx.size / 2; + uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr); + /* Get remaining size */ + uassert_true(max_block(heap) > max_free); + /* Free memory */ + uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0); + rt_smem_free(ctx.ptr); + /* Check memory integrity */ + uassert_int_equal(max_block(heap), total_size); + } + /* mem realloc test,equal */ + { + rt_size_t max_free; + struct mem_test_context ctx; + /* alloc a piece of memory */ + ctx.magic = magic++; + ctx.size = max_block(heap) / 2; + ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size); + uassert_not_null(ctx.ptr); + rt_memset(ctx.ptr, ctx.magic, ctx.size); + uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0); + /* Get remaining memory */ + max_free = max_block(heap); + /* Do not change memory size */ + uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr); + /* Get remaining size */ + uassert_true(max_block(heap) == max_free); + /* Free memory */ + uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0); + rt_smem_free(ctx.ptr); + /* Check memory integrity */ + uassert_int_equal(max_block(heap), total_size); + } + /* small heap deinit */ + rt_smem_detach(&heap->parent); + /* release test resources */ + rt_free(buf); +} + +struct mem_alloc_context +{ + rt_list_t node; + rt_size_t size; + rt_uint8_t magic; +}; + +struct mem_alloc_head +{ + rt_list_t list; + rt_size_t count; + rt_tick_t start; + rt_tick_t end; + rt_tick_t interval; +}; + +#define MEM_RANG_ALLOC_BLK_MIN 2 +#define MEM_RANG_ALLOC_BLK_MAX 5 +#define MEM_RANG_ALLOC_TEST_TIME 5 + +static void mem_alloc_test(void) +{ + struct mem_alloc_head head; + rt_uint8_t *buf; + struct rt_small_mem *heap; + rt_size_t total_size, size; + struct mem_alloc_context *ctx; + + /* init */ + rt_list_init(&head.list); + head.count = 0; + head.start = rt_tick_get(); + head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000); + head.interval = (head.end - head.start) / 20; + buf = rt_malloc(TEST_MEM_SIZE); + uassert_not_null(buf); + uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf); + rt_memset(buf, 0xAA, TEST_MEM_SIZE); + heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE); + total_size = max_block(heap); + uassert_int_not_equal(total_size, 0); + /* test run */ + while (head.end - head.start < RT_TICK_MAX / 2) + { + if (rt_tick_get() - head.start >= head.interval) + { + head.start = rt_tick_get(); + rt_kprintf("#"); + } + /* %60 probability to perform alloc operation */ + if (rand() % 10 >= 4) + { + size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN; + size *= sizeof(struct mem_alloc_context); + ctx = rt_smem_alloc(&heap->parent, size); + if (ctx == RT_NULL) + { + if (head.count == 0) + { + break; + } + size = head.count / 2; + while (size != head.count) + { + ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node); + rt_list_remove(&ctx->node); + if (ctx->size > sizeof(*ctx)) + { + if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0) + { + uassert_true(0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_smem_free(ctx); + head.count --; + } + continue; + } + if (RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE) != (rt_ubase_t)ctx) + { + uassert_int_equal(RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE), (rt_ubase_t)ctx); + } + rt_memset(ctx, 0, size); + rt_list_init(&ctx->node); + ctx->size = size; + ctx->magic = rand() & 0xff; + if (ctx->size > sizeof(*ctx)) + { + rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + } + rt_list_insert_after(&head.list, &ctx->node); + head.count += 1; + } + else + { + if (!rt_list_isempty(&head.list)) + { + ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node); + rt_list_remove(&ctx->node); + if (ctx->size > sizeof(*ctx)) + { + if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0) + { + uassert_true(0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_smem_free(ctx); + head.count --; + } + } + } + while (!rt_list_isempty(&head.list)) + { + ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node); + rt_list_remove(&ctx->node); + if (ctx->size > sizeof(*ctx)) + { + if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0) + { + uassert_true(0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_smem_free(ctx); + head.count --; + } + uassert_int_equal(head.count, 0); + uassert_int_equal(max_block(heap), total_size); + /* small heap deinit */ + rt_smem_detach(&heap->parent); + /* release test resources */ + rt_free(buf); +} + +#define MEM_RANG_REALLOC_BLK_MIN 0 +#define MEM_RANG_REALLOC_BLK_MAX 5 +#define MEM_RANG_REALLOC_TEST_TIME 5 + +struct mem_realloc_context +{ + rt_size_t size; + rt_uint8_t magic; +}; + +struct mem_realloc_head +{ + struct mem_realloc_context **ctx_tab; + rt_size_t count; + rt_tick_t start; + rt_tick_t end; + rt_tick_t interval; +}; + +static void mem_realloc_test(void) +{ + struct mem_realloc_head head; + rt_uint8_t *buf; + struct rt_small_mem *heap; + rt_size_t total_size, size, idx; + struct mem_realloc_context *ctx; + int res; + + size = RT_ALIGN(sizeof(struct mem_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE; + size = TEST_MEM_SIZE / size; + /* init */ + head.ctx_tab = RT_NULL; + head.count = size; + head.start = rt_tick_get(); + head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000); + head.interval = (head.end - head.start) / 20; + buf = rt_malloc(TEST_MEM_SIZE); + uassert_not_null(buf); + uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf); + rt_memset(buf, 0xAA, TEST_MEM_SIZE); + heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE); + total_size = max_block(heap); + uassert_int_not_equal(total_size, 0); + /* init ctx tab */ + size = head.count * sizeof(struct mem_realloc_context *); + head.ctx_tab = rt_smem_alloc(&heap->parent, size); + uassert_not_null(head.ctx_tab); + rt_memset(head.ctx_tab, 0, size); + /* test run */ + while (head.end - head.start < RT_TICK_MAX / 2) + { + if (rt_tick_get() - head.start >= head.interval) + { + head.start = rt_tick_get(); + rt_kprintf("#"); + } + size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN; + size *= sizeof(struct mem_realloc_context); + idx = rand() % head.count; + ctx = rt_smem_realloc(&heap->parent, head.ctx_tab[idx], size); + if (ctx == RT_NULL) + { + if (size == 0) + { + if (head.ctx_tab[idx]) + { + head.ctx_tab[idx] = RT_NULL; + } + } + else + { + for (idx = 0; idx < head.count; idx++) + { + ctx = head.ctx_tab[idx]; + if (rand() % 2 && ctx) + { + if (ctx->size > sizeof(*ctx)) + { + res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + if (res != 0) + { + uassert_int_equal(res, 0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_smem_realloc(&heap->parent, ctx, 0); + head.ctx_tab[idx] = RT_NULL; + } + } + } + continue; + } + /* check mem */ + if (head.ctx_tab[idx] != RT_NULL) + { + res = 0; + if (ctx->size < size) + { + if (ctx->size > sizeof(*ctx)) + { + res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + } + } + else + { + if (size > sizeof(*ctx)) + { + res = _mem_cmp(&ctx[1], ctx->magic, size - sizeof(*ctx)); + } + } + if (res != 0) + { + uassert_int_equal(res, 0); + } + } + /* init mem */ + ctx->magic = rand() & 0xff; + ctx->size = size; + if (ctx->size > sizeof(*ctx)) + { + rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + } + head.ctx_tab[idx] = ctx; + } + /* free all mem */ + for (idx = 0; idx < head.count; idx++) + { + ctx = head.ctx_tab[idx]; + if (ctx == RT_NULL) + { + continue; + } + if (ctx->size > sizeof(*ctx)) + { + res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + if (res != 0) + { + uassert_int_equal(res, 0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_smem_realloc(&heap->parent, ctx, 0); + head.ctx_tab[idx] = RT_NULL; + } + uassert_int_not_equal(max_block(heap), total_size); + /* small heap deinit */ + rt_smem_detach(&heap->parent); + /* release test resources */ + rt_free(buf); +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(mem_functional_test); + UTEST_UNIT_RUN(mem_alloc_test); + UTEST_UNIT_RUN(mem_realloc_test); +} +UTEST_TC_EXPORT(testcase, "testcases.kernel.mem_tc", utest_tc_init, utest_tc_cleanup, 20); diff --git a/examples/utest/testcases/kernel/slab_tc.c b/examples/utest/testcases/kernel/slab_tc.c new file mode 100644 index 0000000000..b273870cca --- /dev/null +++ b/examples/utest/testcases/kernel/slab_tc.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2006-2019, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-14 tyx the first version + */ + +#include <rtthread.h> +#include <stdlib.h> +#include "utest.h" + +#define TEST_SLAB_SIZE 1024 * 1024 + +static int _mem_cmp(void *ptr, rt_uint8_t v, rt_size_t size) +{ + while (size-- != 0) + { + if (*(rt_uint8_t *)ptr != v) + return *(rt_uint8_t *)ptr - v; + } + return 0; +} + +struct slab_alloc_context +{ + rt_list_t node; + rt_size_t size; + rt_uint8_t magic; +}; + +struct slab_alloc_head +{ + rt_list_t list; + rt_size_t count; + rt_tick_t start; + rt_tick_t end; + rt_tick_t interval; +}; + +#define SLAB_RANG_ALLOC_BLK_MIN 2 +#define SLAB_RANG_ALLOC_BLK_MAX 5 +#define SLAB_RANG_ALLOC_TEST_TIME 5 + +static void slab_alloc_test(void) +{ + struct slab_alloc_head head; + rt_uint8_t *buf; + rt_slab_t heap; + rt_size_t size; + struct slab_alloc_context *ctx; + + /* init */ + rt_list_init(&head.list); + head.count = 0; + head.start = rt_tick_get(); + head.end = rt_tick_get() + rt_tick_from_millisecond(SLAB_RANG_ALLOC_TEST_TIME * 1000); + head.interval = (head.end - head.start) / 20; + buf = rt_malloc(TEST_SLAB_SIZE); + uassert_not_null(buf); + uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf); + rt_memset(buf, 0xAA, TEST_SLAB_SIZE); + heap = rt_slab_init("slab_tc", buf, TEST_SLAB_SIZE); + // test run + while (head.end - head.start < RT_TICK_MAX / 2) + { + if (rt_tick_get() - head.start >= head.interval) + { + head.start = rt_tick_get(); + rt_kprintf("#"); + } + // %60 probability to perform alloc operation + if (rand() % 10 >= 4) + { + size = rand() % SLAB_RANG_ALLOC_BLK_MAX + SLAB_RANG_ALLOC_BLK_MIN; + size *= sizeof(struct slab_alloc_context); + ctx = rt_slab_alloc(heap, size); + if (ctx == RT_NULL) + { + if (head.count == 0) + { + break; + } + size = head.count / 2; + while (size != head.count) + { + ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node); + rt_list_remove(&ctx->node); + if (ctx->size > sizeof(*ctx)) + { + if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0) + { + uassert_true(0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_slab_free(heap, ctx); + head.count --; + } + continue; + } + //if (RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE) != (rt_ubase_t)ctx) + //{ + // uassert_int_equal(RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE), (rt_ubase_t)ctx); + //} + rt_memset(ctx, 0, size); + rt_list_init(&ctx->node); + ctx->size = size; + ctx->magic = rand() & 0xff; + if (ctx->size > sizeof(*ctx)) + { + rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + } + rt_list_insert_after(&head.list, &ctx->node); + head.count += 1; + } + else + { + if (!rt_list_isempty(&head.list)) + { + ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node); + rt_list_remove(&ctx->node); + if (ctx->size > sizeof(*ctx)) + { + if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0) + { + uassert_true(0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_slab_free(heap, ctx); + head.count --; + } + } + } + while (!rt_list_isempty(&head.list)) + { + ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node); + rt_list_remove(&ctx->node); + if (ctx->size > sizeof(*ctx)) + { + if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0) + { + uassert_true(0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_slab_free(heap, ctx); + head.count --; + } + uassert_int_equal(head.count, 0); + // slab heap deinit + rt_slab_detach(heap); + /* release test resources */ + rt_free(buf); +} + +#define SLAB_RANG_REALLOC_BLK_MIN 0 +#define SLAB_RANG_REALLOC_BLK_MAX 5 +#define SLAB_RANG_REALLOC_TEST_TIME 5 + +struct slab_realloc_context +{ + rt_size_t size; + rt_uint8_t magic; +}; + +struct slab_realloc_head +{ + struct slab_realloc_context **ctx_tab; + rt_size_t count; + rt_tick_t start; + rt_tick_t end; + rt_tick_t interval; +}; + +static void slab_realloc_test(void) +{ + struct slab_realloc_head head; + rt_uint8_t *buf; + rt_slab_t heap; + rt_size_t size, idx; + struct slab_realloc_context *ctx; + int res; + + size = RT_ALIGN(sizeof(struct slab_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE; + size = TEST_SLAB_SIZE / size; + /* init */ + head.ctx_tab = RT_NULL; + head.count = size; + head.start = rt_tick_get(); + head.end = rt_tick_get() + rt_tick_from_millisecond(SLAB_RANG_ALLOC_TEST_TIME * 1000); + head.interval = (head.end - head.start) / 20; + buf = rt_malloc(TEST_SLAB_SIZE); + uassert_not_null(buf); + uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf); + rt_memset(buf, 0xAA, TEST_SLAB_SIZE); + heap = rt_slab_init("slab_tc", buf, TEST_SLAB_SIZE); + /* init ctx tab */ + size = head.count * sizeof(struct slab_realloc_context *); + head.ctx_tab = rt_slab_alloc(heap, size); + uassert_not_null(head.ctx_tab); + rt_memset(head.ctx_tab, 0, size); + // test run + while (head.end - head.start < RT_TICK_MAX / 2) + { + if (rt_tick_get() - head.start >= head.interval) + { + head.start = rt_tick_get(); + rt_kprintf("#"); + } + size = rand() % SLAB_RANG_ALLOC_BLK_MAX + SLAB_RANG_ALLOC_BLK_MIN; + size *= sizeof(struct slab_realloc_context); + idx = rand() % head.count; + ctx = rt_slab_realloc(heap, head.ctx_tab[idx], size); + if (ctx == RT_NULL) + { + if (size == 0) + { + if (head.ctx_tab[idx]) + { + head.ctx_tab[idx] = RT_NULL; + } + } + else + { + for (idx = 0; idx < head.count; idx++) + { + ctx = head.ctx_tab[idx]; + if (rand() % 2 && ctx) + { + if (ctx->size > sizeof(*ctx)) + { + res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + if (res != 0) + { + uassert_int_equal(res, 0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_slab_realloc(heap, ctx, 0); + head.ctx_tab[idx] = RT_NULL; + } + } + } + continue; + } + /* check slab */ + if (head.ctx_tab[idx] != RT_NULL) + { + res = 0; + if (ctx->size < size) + { + if (ctx->size > sizeof(*ctx)) + { + res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + } + } + else + { + if (size > sizeof(*ctx)) + { + res = _mem_cmp(&ctx[1], ctx->magic, size - sizeof(*ctx)); + } + } + if (res != 0) + { + uassert_int_equal(res, 0); + } + } + /* init slab */ + ctx->magic = rand() & 0xff; + ctx->size = size; + if (ctx->size > sizeof(*ctx)) + { + rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + } + head.ctx_tab[idx] = ctx; + } + // free all slab + for (idx = 0; idx < head.count; idx++) + { + ctx = head.ctx_tab[idx]; + if (ctx == RT_NULL) + { + continue; + } + if (ctx->size > sizeof(*ctx)) + { + res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)); + if (res != 0) + { + uassert_int_equal(res, 0); + } + } + rt_memset(ctx, 0xAA, ctx->size); + rt_slab_realloc(heap, ctx, 0); + head.ctx_tab[idx] = RT_NULL; + } + // slab heap deinit + rt_slab_detach(heap); + /* release test resources */ + rt_free(buf); +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(slab_alloc_test); + UTEST_UNIT_RUN(slab_realloc_test); +} +UTEST_TC_EXPORT(testcase, "testcases.kernel.slab_tc", utest_tc_init, utest_tc_cleanup, 20); |
