heap: Refactor heap regions/capabilities out of FreeRTOS

Remove tagged heap API, rename caps_xxx to heap_caps_xxx

Also includes additional heap_caps_xxx inspection functions.
This commit is contained in:
Angus Gratton
2017-05-03 18:03:28 +10:00
committed by Angus Gratton
parent 5ee49fd311
commit 71c70cb15c
37 changed files with 1166 additions and 995 deletions

View File

@@ -0,0 +1,5 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View File

@@ -0,0 +1,55 @@
/*
Generic test for malloc/free
*/
#include <esp_types.h>
#include <stdio.h>
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/xtensa_api.h"
#include "unity.h"
#include "soc/uart_reg.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "esp_panic.h"
static int tryAllocMem() {
int **mem;
int i, noAllocated, j;
mem=malloc(sizeof(int *)*1024);
if (!mem) return 0;
for (i=0; i<1024; i++) {
mem[i]=malloc(1024);
if (mem[i]==NULL) break;
for (j=0; j<1024/4; j++) mem[i][j]=(0xdeadbeef);
}
noAllocated=i;
for (i=0; i<noAllocated; i++) {
for (j=0; j<1024/4; j++) {
TEST_ASSERT(mem[i][j]==(0xdeadbeef));
}
free(mem[i]);
}
free(mem);
return noAllocated;
}
TEST_CASE("Malloc/overwrite, then free all available DRAM", "[heap]")
{
int m1=0, m2=0;
m1=tryAllocMem();
m2=tryAllocMem();
printf("Could allocate %dK on first try, %dK on 2nd try.\n", m1, m2);
TEST_ASSERT(m1==m2);
}

View File

@@ -0,0 +1,125 @@
/*
Tests for the capabilities-based memory allocator.
*/
#include <esp_types.h>
#include <stdio.h>
#include "unity.h"
#include "esp_attr.h"
#include "esp_heap_caps.h"
#include "esp_spi_flash.h"
#include <stdlib.h>
TEST_CASE("Capabilities allocator test", "[heap]")
{
char *m1, *m2[10];
int x;
size_t free8start, free32start, free8, free32;
/* It's important we printf() something before we take the empty heap sizes,
as the first printf() in a task allocates heap resources... */
printf("Testing capabilities allocator...\n");
free8start = heap_caps_get_free_size(MALLOC_CAP_8BIT);
free32start = heap_caps_get_free_size(MALLOC_CAP_32BIT);
printf("Free 8bit-capable memory (start): %dK, 32-bit capable memory %dK\n", free8start, free32start);
TEST_ASSERT(free32start>free8start);
printf("Allocating 10K of 8-bit capable RAM\n");
m1= heap_caps_malloc(10*1024, MALLOC_CAP_8BIT);
printf("--> %p\n", m1);
free8 = heap_caps_get_free_size(MALLOC_CAP_8BIT);
free32 = heap_caps_get_free_size(MALLOC_CAP_32BIT);
printf("Free 8bit-capable memory (both reduced): %dK, 32-bit capable memory %dK\n", free8, free32);
//Both should have gone down by 10K; 8bit capable ram is also 32-bit capable
TEST_ASSERT(free8<(free8start-10*1024));
TEST_ASSERT(free32<(free32start-10*1024));
//Assume we got DRAM back
TEST_ASSERT((((int)m1)&0xFF000000)==0x3F000000);
free(m1);
printf("Freeing; allocating 10K of 32K-capable RAM\n");
m1 = heap_caps_malloc(10*1024, MALLOC_CAP_32BIT);
printf("--> %p\n", m1);
free8 = heap_caps_get_free_size(MALLOC_CAP_8BIT);
free32 = heap_caps_get_free_size(MALLOC_CAP_32BIT);
printf("Free 8bit-capable memory (after 32-bit): %dK, 32-bit capable memory %dK\n", free8, free32);
//Only 32-bit should have gone down by 10K: 32-bit isn't necessarily 8bit capable
TEST_ASSERT(free32<(free32start-10*1024));
TEST_ASSERT(free8==free8start);
//Assume we got IRAM back
TEST_ASSERT((((int)m1)&0xFF000000)==0x40000000);
free(m1);
printf("Allocating impossible caps\n");
m1= heap_caps_malloc(10*1024, MALLOC_CAP_8BIT|MALLOC_CAP_EXEC);
printf("--> %p\n", m1);
TEST_ASSERT(m1==NULL);
printf("Testing changeover iram -> dram");
// priorities will exhaust IRAM first, then start allocating from DRAM
for (x=0; x<10; x++) {
m2[x]= heap_caps_malloc(10*1024, MALLOC_CAP_32BIT);
printf("--> %p\n", m2[x]);
}
TEST_ASSERT((((int)m2[0])&0xFF000000)==0x40000000);
TEST_ASSERT((((int)m2[9])&0xFF000000)==0x3F000000);
printf("Test if allocating executable code still gives IRAM, even with dedicated IRAM region depleted\n");
// (the allocation should come from D/IRAM)
m1= heap_caps_malloc(10*1024, MALLOC_CAP_EXEC);
printf("--> %p\n", m1);
TEST_ASSERT((((int)m1)&0xFF000000)==0x40000000);
free(m1);
for (x=0; x<10; x++) free(m2[x]);
printf("Done.\n");
}
TEST_CASE("heap_caps metadata test", "[heap]")
{
/* need to print something as first printf allocates some heap */
printf("heap_caps metadata test\n");
heap_caps_print_heap_info(MALLOC_CAP_8BIT);
heap_caps_print_heap_info(MALLOC_CAP_32BIT);
multi_heap_info_t original;
heap_caps_get_info(&original, MALLOC_CAP_8BIT);
void *b = heap_caps_malloc(original.largest_free_block, MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(b);
printf("After allocating %d bytes:\n", original.largest_free_block);
heap_caps_print_heap_info(MALLOC_CAP_8BIT);
multi_heap_info_t after;
heap_caps_get_info(&after, MALLOC_CAP_8BIT);
TEST_ASSERT(after.largest_free_block < original.largest_free_block);
TEST_ASSERT(after.total_free_bytes < original.total_free_bytes);
free(b);
heap_caps_get_info(&after, MALLOC_CAP_8BIT);
TEST_ASSERT_EQUAL(after.total_free_bytes, original.total_free_bytes);
TEST_ASSERT_EQUAL(after.largest_free_block, original.largest_free_block);
TEST_ASSERT(after.minimum_free_bytes < original.total_free_bytes);
}
/* Small function runs from IRAM to check that malloc/free/realloc
all work OK when cache is disabled...
*/
static IRAM_ATTR __attribute__((noinline)) bool iram_malloc_test()
{
g_flash_guard_default_ops.start(); // Disables flash cache
bool result = true;
void *x = heap_caps_malloc(64, MALLOC_CAP_32BIT);
result = result && (x != NULL);
void *y = heap_caps_realloc(x, 32, MALLOC_CAP_32BIT);
result = result && (y != NULL);
heap_caps_free(y);
g_flash_guard_default_ops.end(); // Re-enables flash cache
return result;
}
TEST_CASE("heap_caps_xxx functions work with flash cache disabled", "[heap]")
{
TEST_ASSERT( iram_malloc_test() );
}