From 20481792013d3b5944f40b2a7208714e3c10b2cf Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sat, 19 Mar 2016 15:09:05 +0000 Subject: [PATCH] Heaps tested in NIL. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9140 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/common/oslib/include/chheap.h | 7 + test/nil/configuration.xml | 246 +++++++++++++++++++++-- test/nil/source/test/test_sequence_006.c | 192 +++++++++++++++++- 3 files changed, 426 insertions(+), 19 deletions(-) diff --git a/os/common/oslib/include/chheap.h b/os/common/oslib/include/chheap.h index cd677177a..9a90d0488 100644 --- a/os/common/oslib/include/chheap.h +++ b/os/common/oslib/include/chheap.h @@ -102,6 +102,13 @@ struct memory_heap { /* Module macros. */ /*===========================================================================*/ +/** + * @brief Allocation of an aligned static heap buffer. + */ +#define CH_HEAP_AREA(name, size) \ + ALIGNED_VAR(CH_HEAP_ALIGNMENT) \ + uint8_t name[MEM_ALIGN_NEXT((size), CH_HEAP_ALIGNMENT)] + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ diff --git a/test/nil/configuration.xml b/test/nil/configuration.xml index 2b9fe9cad..bb6fbaf4e 100644 --- a/test/nil/configuration.xml +++ b/test/nil/configuration.xml @@ -10,20 +10,20 @@ - @@ -1205,7 +1205,11 @@ test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");]]> This sequence tests the ChibiOS/NIL functionalities related to memory heaps. - + @@ -1220,16 +1224,222 @@ test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");]]> - + - + - + + + + Testing initial conditions, the heap must not be fragmented and one free block present. + + + + + + + + + + + Trying to allocate an block bigger than available space, an error is expected. + + + + + + + + + + + Single block allocation using chHeapAlloc() then the block is freed using chHeapFree(), must not fail. + + + + + + + + + + + Using chHeapStatus() to assess the heap state. There must be at least one free block of sufficient size. + + + + + + = ALLOC_SIZE, "unexpected heap state"); +test_assert(total_size == largest_size, "unexpected heap state");]]> + + + + + Allocating then freeing in the same order. + + + + + + + + + + + Allocating then freeing in reverse order. + + + + + + + + + + + Small fragments handling. Checking the behavior when allocating blocks with size not multiple of alignment unit. + + + + + + + + + + + Skipping a fragment, the first fragment in the list is too small so the allocator must pick the second one. + + + + + + + + + + + Allocating the whole available space. + + + + + + + + + + + Testing final conditions. The heap geometry must be the same than the one registered at beginning. + + + + + + + + + + + + + Default Heap. + + + The default heap is pre-allocated in the system. We test base functionality. + + + CH_CFG_USE_HEAP + + + + + + + + + + + + + + + + Single block allocation using chHeapAlloc() then the block is freed using chHeapFree(), must not fail. + + + + + + + + + + + Testing allocation failure. + + + + + + + + + diff --git a/test/nil/source/test/test_sequence_006.c b/test/nil/source/test/test_sequence_006.c index fe3e2aaf6..0261f1026 100644 --- a/test/nil/source/test/test_sequence_006.c +++ b/test/nil/source/test/test_sequence_006.c @@ -29,6 +29,7 @@ * *

Test Cases

* - @subpage test_006_001 + * - @subpage test_006_002 * . */ @@ -36,6 +37,11 @@ * Shared code. ****************************************************************************/ +#define ALLOC_SIZE 16 +#define HEAP_SIZE (ALLOC_SIZE * 8) + +static memory_heap_t test_heap; +static CH_HEAP_AREA(myheap, HEAP_SIZE); /**************************************************************************** * Test cases. @@ -58,13 +64,143 @@ * . * *

Test Steps

+ * - Testing initial conditions, the heap must not be fragmented and + * one free block present. + * - Trying to allocate an block bigger than available space, an error + * is expected. + * - Single block allocation using chHeapAlloc() then the block is + * freed using chHeapFree(), must not fail. + * - Using chHeapStatus() to assess the heap state. There must be at + * least one free block of sufficient size. + * - Allocating then freeing in the same order. + * - Allocating then freeing in reverse order. + * - Small fragments handling. Checking the behavior when allocating + * blocks with size not multiple of alignment unit. + * - Skipping a fragment, the first fragment in the list is too small + * so the allocator must pick the second one. + * - Allocating the whole available space. + * - Testing final conditions. The heap geometry must be the same than + * the one registered at beginning. + * . */ static void test_006_001_setup(void) { - chHeapObjectInit(&test_heap, test.buffer, sizeof(union test_buffers)); + chHeapObjectInit(&test_heap, myheap, sizeof(myheap)); } static void test_006_001_execute(void) { + void *p1, *p2, *p3; + size_t n, sz; + + /* Testing initial conditions, the heap must not be fragmented and + one free block present.*/ + test_set_step(1); + { + test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented"); + } + + /* Trying to allocate an block bigger than available space, an error + is expected.*/ + test_set_step(2); + { + p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2); + test_assert(p1 == NULL, "allocation not failed"); + } + + /* Single block allocation using chHeapAlloc() then the block is + freed using chHeapFree(), must not fail.*/ + test_set_step(3); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + test_assert(p1 != NULL, "allocation failed"); + chHeapFree(p1); + } + + /* Using chHeapStatus() to assess the heap state. There must be at + least one free block of sufficient size.*/ + test_set_step(4); + { + size_t total_size, largest_size; + + n = chHeapStatus(&test_heap, &total_size, &largest_size); + test_assert(n == 1, "missing free block"); + test_assert(total_size >= ALLOC_SIZE, "unexpected heap state"); + test_assert(total_size == largest_size, "unexpected heap state"); + } + + /* Allocating then freeing in the same order.*/ + test_set_step(5); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); /* Does not merge.*/ + chHeapFree(p2); /* Merges backward.*/ + chHeapFree(p3); /* Merges both sides.*/ + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* Allocating then freeing in reverse order.*/ + test_set_step(6); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p3); /* Merges forward.*/ + chHeapFree(p2); /* Merges forward.*/ + chHeapFree(p1); /* Merges forward.*/ + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* Small fragments handling. Checking the behavior when allocating + blocks with size not multiple of alignment unit.*/ + test_set_step(7); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + /* Note, the first situation happens when the alignment size is smaller + than the header size, the second in the other cases.*/ + test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) || + (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented"); + chHeapFree(p2); + chHeapFree(p1); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* Skipping a fragment, the first fragment in the list is too small + so the allocator must pick the second one.*/ + test_set_step(8); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); + test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/ + chHeapFree(p1); + chHeapFree(p2); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* Allocating the whole available space.*/ + test_set_step(9); + { + (void)chHeapStatus(&test_heap, &n, NULL); + p1 = chHeapAlloc(&test_heap, n); + test_assert(p1 != NULL, "allocation failed"); + test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty"); + chHeapFree(p1); + } + + /* Testing final conditions. The heap geometry must be the same than + the one registered at beginning.*/ + test_set_step(10); + { + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + test_assert(n == sz, "size changed"); + } } static const testcase_t test_006_001 = { @@ -75,6 +211,57 @@ static const testcase_t test_006_001 = { }; #endif /* CH_CFG_USE_HEAP */ +#if CH_CFG_USE_HEAP || defined(__DOXYGEN__) +/** + * @page test_006_002 Default Heap + * + *

Description

+ * The default heap is pre-allocated in the system. We test base + * functionality. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_HEAP + * . + * + *

Test Steps

+ * - Single block allocation using chHeapAlloc() then the block is + * freed using chHeapFree(), must not fail. + * - Testing allocation failure. + * . + */ + +static void test_006_002_execute(void) { + void *p1; + size_t total_size, largest_size; + + /* Single block allocation using chHeapAlloc() then the block is + freed using chHeapFree(), must not fail.*/ + test_set_step(1); + { + (void)chHeapStatus(NULL, &total_size, &largest_size); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + test_assert(p1 != NULL, "allocation failed"); + chHeapFree(p1); + } + + /* Testing allocation failure.*/ + test_set_step(2); + { + p1 = chHeapAlloc(NULL, (size_t)-256); + test_assert(p1 == NULL, "allocation not failed"); + } +} + +static const testcase_t test_006_002 = { + "Default Heap", + NULL, + NULL, + test_006_002_execute +}; +#endif /* CH_CFG_USE_HEAP */ + /**************************************************************************** * Exported data. ****************************************************************************/ @@ -85,6 +272,9 @@ static const testcase_t test_006_001 = { const testcase_t * const test_sequence_006[] = { #if CH_CFG_USE_HEAP || defined(__DOXYGEN__) &test_006_001, +#endif +#if CH_CFG_USE_HEAP || defined(__DOXYGEN__) + &test_006_002, #endif NULL };