2017-05-03 08:03:28 +00:00
|
|
|
/*
|
|
|
|
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>
|
2018-06-27 06:46:20 +00:00
|
|
|
#include <sys/param.h>
|
2017-05-03 08:03:28 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2018-06-27 06:46:20 +00:00
|
|
|
//The goal here is to allocate from IRAM. Since there is no external IRAM (yet)
|
|
|
|
//the following gives size of IRAM-only (not D/IRAM) memory.
|
|
|
|
size_t free_iram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL) -
|
|
|
|
heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
2018-07-25 06:45:39 +00:00
|
|
|
size_t alloc32 = MIN(free_iram / 2, 10*1024) & (~3);
|
2018-06-27 06:46:20 +00:00
|
|
|
printf("Freeing; allocating %u bytes of 32K-capable RAM\n", alloc32);
|
|
|
|
m1 = heap_caps_malloc(alloc32, MALLOC_CAP_32BIT);
|
2017-05-03 08:03:28 +00:00
|
|
|
printf("--> %p\n", m1);
|
2018-06-27 06:46:20 +00:00
|
|
|
//Check that we got IRAM back
|
|
|
|
TEST_ASSERT((((int)m1)&0xFF000000)==0x40000000);
|
2017-05-03 08:03:28 +00:00
|
|
|
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);
|
2018-06-27 06:46:20 +00:00
|
|
|
//Only 32-bit should have gone down by alloc32: 32-bit isn't necessarily 8bit capable
|
|
|
|
TEST_ASSERT(free32<(free32start-alloc32));
|
2017-05-03 08:03:28 +00:00
|
|
|
TEST_ASSERT(free8==free8start);
|
|
|
|
free(m1);
|
2018-06-27 06:46:20 +00:00
|
|
|
|
2017-05-03 08:03:28 +00:00
|
|
|
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++) {
|
2018-06-27 06:46:20 +00:00
|
|
|
m2[x]= heap_caps_malloc(alloc32, MALLOC_CAP_32BIT);
|
2017-05-03 08:03:28 +00:00
|
|
|
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)
|
2018-06-27 06:46:20 +00:00
|
|
|
free_iram = heap_caps_get_free_size(MALLOC_CAP_EXEC);
|
|
|
|
m1= heap_caps_malloc(MIN(free_iram / 2, 10*1024), MALLOC_CAP_EXEC);
|
2017-05-03 08:03:28 +00:00
|
|
|
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);
|
2018-07-30 01:41:30 +00:00
|
|
|
/* Allow some leeway here, because LWIP sometimes allocates up to 144 bytes in the background
|
|
|
|
as part of timer management.
|
|
|
|
*/
|
|
|
|
TEST_ASSERT_INT32_WITHIN(200, after.total_free_bytes, original.total_free_bytes);
|
|
|
|
TEST_ASSERT_INT32_WITHIN(200, after.largest_free_block, original.largest_free_block);
|
2017-05-03 08:03:28 +00:00
|
|
|
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...
|
|
|
|
*/
|
2019-07-16 09:33:30 +00:00
|
|
|
static IRAM_ATTR __attribute__((noinline)) bool iram_malloc_test(void)
|
2017-05-03 08:03:28 +00:00
|
|
|
{
|
2017-11-17 04:00:51 +00:00
|
|
|
spi_flash_guard_get()->start(); // Disables flash cache
|
2017-05-03 08:03:28 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2017-11-17 04:00:51 +00:00
|
|
|
spi_flash_guard_get()->end(); // Re-enables flash cache
|
2017-05-03 08:03:28 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("heap_caps_xxx functions work with flash cache disabled", "[heap]")
|
|
|
|
{
|
|
|
|
TEST_ASSERT( iram_malloc_test() );
|
|
|
|
}
|