heap_tlsf: added implementation of TLSF allocator

heap: ported tlsf allocator into multi heap

heap_host_tests: added tlsf allocator into host test

heap_host_test: update freebytes after using free

heap_tests: tlsf now passing on host tests without poisoning

multi_heap: added support for memalign using tlsf implementation

heap_caps: removed heap_caps_aligned_free

heap/test: fixed broken aligned alloc test build

heap: added poisoning pattern when blocks are being merged

heap/tests: added timing tests for memory allocation

heap: reduced tlsf structure overhead

heap/tlsf: made all short functions inside of tlsf  module as inline to improve timings

heap: moved tlsf heap routines outside of flash memory

newlib: linked multiheap memalign with newlib memalign function

heap: moved block member functions to a separate file so multi_heap can use the functions

heap/test: improved the tlsf timing test

heap/test: added memalign on aligned alloc tests

heap: moved tlsf configuration constants to a separated file

heap: added random allocations test with timings

heap: modified the calculation of heap free bytes

heap: make aligned free true deprecated functions and update their documentation

heap: add extra assert after successive mallocs on small allocation host test

heap: remove legacy aligned alloc implementation.

performance: added malloc and free time performance default values
This commit is contained in:
Felipe Neves
2020-01-16 15:37:19 -03:00
committed by bot
parent a3c90bf59a
commit bd9b921713
23 changed files with 1604 additions and 734 deletions

View File

@@ -18,7 +18,7 @@
TEST_CASE("multi_heap simple allocations", "[multi_heap]")
{
uint8_t small_heap[128];
uint8_t small_heap[10 * 1024];
multi_heap_handle_t heap = multi_heap_register(small_heap, sizeof(small_heap));
@@ -59,10 +59,10 @@ TEST_CASE("multi_heap simple allocations", "[multi_heap]")
TEST_CASE("multi_heap fragmentation", "[multi_heap]")
{
uint8_t small_heap[256];
uint8_t small_heap[10 * 1024];
multi_heap_handle_t heap = multi_heap_register(small_heap, sizeof(small_heap));
const size_t alloc_size = 24;
const size_t alloc_size = 1350;
void *p[4];
for (int i = 0; i < 4; i++) {
@@ -85,13 +85,14 @@ TEST_CASE("multi_heap fragmentation", "[multi_heap]")
multi_heap_free(heap, p[0]);
multi_heap_free(heap, p[1]);
multi_heap_free(heap, p[3]);
printf("1 allocations:\n");
multi_heap_dump(heap);
printf("****************\n");
void *big = multi_heap_malloc(heap, alloc_size * 3);
REQUIRE( p[3] == big ); /* big should go where p[3] was freed from */
//Blocks in TLSF are organized in different form, so this makes no sense
//REQUIRE( p[3] == big ); /* big should go where p[3] was freed from */
multi_heap_free(heap, big);
multi_heap_free(heap, p[2]);
@@ -101,7 +102,8 @@ TEST_CASE("multi_heap fragmentation", "[multi_heap]")
printf("****************\n");
big = multi_heap_malloc(heap, alloc_size * 2);
REQUIRE( p[0] == big ); /* big should now go where p[0] was freed from */
//Blocks in TLSF are organized in different form, so this makes no sense
//REQUIRE( p[0] == big ); /* big should now go where p[0] was freed from */
multi_heap_free(heap, big);
}
@@ -109,7 +111,7 @@ TEST_CASE("multi_heap fragmentation", "[multi_heap]")
TEST_CASE("multi_heap defrag", "[multi_heap]")
{
void *p[4];
uint8_t small_heap[512];
uint8_t small_heap[10 * 1024];
multi_heap_info_t info, info2;
multi_heap_handle_t heap = multi_heap_register(small_heap, sizeof(small_heap));
@@ -159,7 +161,7 @@ TEST_CASE("multi_heap defrag", "[multi_heap]")
TEST_CASE("multi_heap defrag realloc", "[multi_heap]")
{
void *p[4];
uint8_t small_heap[512];
uint8_t small_heap[10 * 1024];
multi_heap_info_t info, info2;
multi_heap_handle_t heap = multi_heap_register(small_heap, sizeof(small_heap));
@@ -204,7 +206,7 @@ TEST_CASE("multi_heap defrag realloc", "[multi_heap]")
TEST_CASE("multi_heap many random allocations", "[multi_heap]")
{
uint8_t big_heap[1024];
uint8_t big_heap[64 * 1024];
const int NUM_POINTERS = 64;
printf("Running multi-allocation test...\n");
@@ -296,7 +298,7 @@ TEST_CASE("multi_heap many random allocations", "[multi_heap]")
TEST_CASE("multi_heap_get_info() function", "[multi_heap]")
{
uint8_t heapdata[256];
uint8_t heapdata[10 * 1024];
multi_heap_handle_t heap = multi_heap_register(heapdata, sizeof(heapdata));
multi_heap_info_t before, after, freed;
@@ -349,25 +351,26 @@ TEST_CASE("multi_heap_get_info() function", "[multi_heap]")
TEST_CASE("multi_heap minimum-size allocations", "[multi_heap]")
{
uint8_t heapdata[16384];
void *p[sizeof(heapdata) / sizeof(void *)];
uint8_t heapdata[4096];
void *p[sizeof(heapdata) / sizeof(void *)] = {NULL};
const size_t NUM_P = sizeof(p) / sizeof(void *);
size_t allocated_size = 0;
multi_heap_handle_t heap = multi_heap_register(heapdata, sizeof(heapdata));
size_t before_free = multi_heap_free_size(heap);
size_t i;
for (i = 0; i < NUM_P; i++) {
//TLSF minimum block size is 4 bytes
p[i] = multi_heap_malloc(heap, 1);
if (p[i] == NULL) {
break;
}
}
}
REQUIRE( i < NUM_P); // Should have run out of heap before we ran out of pointers
printf("Allocated %zu minimum size chunks\n", i);
REQUIRE( 0 == multi_heap_free_size(heap) );
REQUIRE(multi_heap_free_size(heap) < before_free);
multi_heap_check(heap, true);
/* Free in random order */
@@ -391,7 +394,7 @@ TEST_CASE("multi_heap minimum-size allocations", "[multi_heap]")
TEST_CASE("multi_heap_realloc()", "[multi_heap]")
{
const uint32_t PATTERN = 0xABABDADA;
uint8_t small_heap[300];
uint8_t small_heap[10 * 1024];
multi_heap_handle_t heap = multi_heap_register(small_heap, sizeof(small_heap));
uint32_t *a = (uint32_t *)multi_heap_malloc(heap, 64);
@@ -427,9 +430,9 @@ TEST_CASE("multi_heap_realloc()", "[multi_heap]")
REQUIRE( f == b ); /* 'b' should be extended in-place, over space formerly occupied by 'd' */
#ifdef MULTI_HEAP_POISONING
#define TOO_MUCH 92 + 1
#define TOO_MUCH 7420 + 1
#else
#define TOO_MUCH 128 + 1
#define TOO_MUCH 7420 + 1
#endif
/* not enough contiguous space left in the heap */
uint32_t *g = (uint32_t *)multi_heap_realloc(heap, e, TOO_MUCH);
@@ -443,57 +446,12 @@ TEST_CASE("multi_heap_realloc()", "[multi_heap]")
#endif
}
TEST_CASE("corrupt heap block", "[multi_heap]")
{
uint8_t small_heap[256];
multi_heap_handle_t heap = multi_heap_register(small_heap, sizeof(small_heap));
//TEST_CASE("corrupt heap block", "[multi_heap]"), this
// test will crash since heap check failling will trigger
// an assert failure.
void *a = multi_heap_malloc(heap, 32);
REQUIRE( multi_heap_check(heap, true) );
memset(a, 0xEE, 64);
REQUIRE( !multi_heap_check(heap, true) );
}
TEST_CASE("unaligned heaps", "[multi_heap]")
{
const size_t CHUNK_LEN = 256;
const size_t CANARY_LEN = 16;
const uint8_t CANARY_BYTE = 0x3E;
uint8_t heap_chunk[CHUNK_LEN + CANARY_LEN * 2];
/* Put some canary bytes before and after the bytes we intend to use for
the heap, make sure they aren't ever overwritten */
memset(heap_chunk, CANARY_BYTE, CANARY_LEN);
memset(heap_chunk + CANARY_LEN + CHUNK_LEN, CANARY_BYTE, CANARY_LEN);
for (int i = 0; i < 8; i++) {
printf("Testing with offset %d\n", i);
multi_heap_handle_t heap = multi_heap_register(heap_chunk + CANARY_LEN + i, CHUNK_LEN - i);
multi_heap_info_t info;
REQUIRE( multi_heap_check(heap, true) );
multi_heap_get_info(heap, &info);
REQUIRE( info.total_free_bytes > CHUNK_LEN - 64 - i );
REQUIRE( info.largest_free_block > CHUNK_LEN - 64 - i );
void *a = multi_heap_malloc(heap, info.largest_free_block);
REQUIRE( a != NULL );
memset(a, 0xAA, info.largest_free_block);
REQUIRE( multi_heap_check(heap, true) );
multi_heap_free(heap, a);
REQUIRE( multi_heap_check(heap, true) );
for (unsigned j = 0; j < CANARY_LEN; j++) { // check canaries
REQUIRE( heap_chunk[j] == CANARY_BYTE );
REQUIRE( heap_chunk[CHUNK_LEN + CANARY_LEN + j] == CANARY_BYTE );
}
}
}
// TLSF only accepts heaps aligned to 4-byte boundary so
// unaligned test does not make sense
TEST_CASE("multi_heap aligned allocations", "[multi_heap]")
{
@@ -508,7 +466,7 @@ TEST_CASE("multi_heap aligned allocations", "[multi_heap]")
multi_heap_dump(heap);
printf("*********************\n");
for(;aligments < 500 * 1024; aligments++) {
for(;aligments <= 128 * 1024; aligments++) {
//Use some stupid size value to test correct alignment even in strange
//memory layout objects:
@@ -525,7 +483,6 @@ TEST_CASE("multi_heap aligned allocations", "[multi_heap]")
//printf("[ALIGNED_ALLOC] allocated size: %d \n", multi_heap_get_allocated_size(heap, buf));
printf("[ALIGNED_ALLOC] address of allocated memory: %p \n\n", (void *)buf);
//Address of obtained block must be aligned with selected value
if((aligments & 0x03) == 0) {
//Alignment is a multiple of four:
REQUIRE(((intptr_t)buf & 0x03) == 0);
@@ -538,10 +495,10 @@ TEST_CASE("multi_heap aligned allocations", "[multi_heap]")
//canary verification will fail:
memset(buf, 0xA5, (aligments + 137));
multi_heap_aligned_free(heap, buf);
multi_heap_free(heap, buf);
}
}
printf("[ALIGNED_ALLOC] heap_size after: %d \n", multi_heap_free_size(heap));
REQUIRE((old_size - multi_heap_free_size(heap)) <= leakage);
}
}