From 293ad4cd36481f988d14f22ec5a31aa900674a9a Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Fri, 9 Dec 2016 17:13:45 +0800 Subject: [PATCH] Add xPortGetFreeHeapSizeCaps and xPortGetMinimumEverFreeHeapSizeCaps plus everything it entails. Allows querying the available memory for various capabilities. Also: xPortGetFreeHeapSize and xPortGetMinimumEverFreeHeapSize now return the expected value. Bonus: the linked list used in the allocator is now 4 bytes smaller, which should save some memory. --- components/esp32/heap_alloc_caps.c | 50 ++++ .../esp32/include/esp_heap_alloc_caps.h | 2 + components/freertos/heap_regions.c | 232 ++++++++---------- components/freertos/heap_regions_debug.c | 20 +- .../freertos/include/freertos/heap_regions.h | 6 +- .../include/freertos/heap_regions_debug.h | 2 +- 6 files changed, 175 insertions(+), 137 deletions(-) diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 7e6ce422c..7ce8ba5ca 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -43,6 +43,7 @@ typedef struct { /* Tag descriptors. These describe the capabilities of a bit of memory that's tagged with the index into this table. Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request. +Make sure there are never more than HEAPREGIONS_MAX_TAGCOUNT (in heap_regions.h) tags (ex the last empty marker) */ static const tag_desc_t tag_desc[]={ { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }}, //Tag 0: Plain ole D-port RAM @@ -268,3 +269,52 @@ void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps ) return NULL; } + +size_t xPortGetFreeHeapSizeCaps( uint32_t caps ) +{ + int prio; + int tag; + size_t ret=0; + for (prio=0; prio 0 ) { - /* The wanted size is increased so it can contain a BlockLink_t - structure in addition to the requested amount of bytes. */ - if( xWantedSize > 0 ) - { - xWantedSize += uxHeapStructSize; + xWantedSize += uxHeapStructSize; - /* Ensure that blocks are always aligned to the required number - of bytes. */ - if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) - { - /* Byte alignment required. */ - xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Ensure that blocks are always aligned to the required number + of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); } else { - mtCOVERAGE_TEST_MARKER(); + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining[ tag ] ) ) + { + /* Traverse the list from the start (lowest address) block until + one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { +// ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock); + + #if (configENABLE_MEMORY_DEBUG == 1) + { + mem_check_block(pxBlock); + } + #endif + + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; } - if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) + /* If the end marker was not reached then a block of adequate size + was found. */ + if( pxBlock != pxEnd ) { - /* Traverse the list from the start (lowest address) block until - one of adequate size is found. */ - pxPreviousBlock = &xStart; - pxBlock = xStart.pxNextFreeBlock; - while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + /* Return the memory space pointed to - jumping over the + BlockLink_t structure at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN); + + /* This block is being returned for use so must be taken out + of the list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into + two. */ + + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) { -// ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock); + /* This block is to be split into two. Create a new + block following the number of bytes requested. The void + cast is used to prevent byte alignment warnings from the + compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize); - #if (configENABLE_MEMORY_DEBUG == 1) - { - mem_check_block(pxBlock); - } - #endif + /* Calculate the sizes of two blocks split from the + single block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxNewBlockLink->xTag = tag; + pxBlock->xBlockSize = xWantedSize; - pxPreviousBlock = pxBlock; - pxBlock = pxBlock->pxNextFreeBlock; - } - - /* If the end marker was not reached then a block of adequate size - was found. */ - if( pxBlock != pxEnd ) - { - /* Return the memory space pointed to - jumping over the - BlockLink_t structure at its start. */ - pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN); - - /* This block is being returned for use so must be taken out - of the list of free blocks. */ - pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; - - /* If the block is larger than required it can be split into - two. */ - - if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) - { - /* This block is to be split into two. Create a new - block following the number of bytes requested. The void - cast is used to prevent byte alignment warnings from the - compiler. */ - pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize); - - /* Calculate the sizes of two blocks split from the - single block. */ - pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; - pxNewBlockLink->xTag = tag; - pxBlock->xBlockSize = xWantedSize; - - #if (configENABLE_MEMORY_DEBUG == 1) - { - mem_init_dog(pxNewBlockLink); - } - #endif + #if (configENABLE_MEMORY_DEBUG == 1) + { + mem_init_dog(pxNewBlockLink); + } + #endif - /* Insert the new block into the list of free blocks. */ - prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - xFreeBytesRemaining -= pxBlock->xBlockSize; - - if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) - { - xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - /* The block is being returned - it is allocated and owned - by the application and has no "next" block. */ - pxBlock->xBlockSize |= xBlockAllocatedBit; - pxBlock->pxNextFreeBlock = NULL; - - #if (configENABLE_MEMORY_DEBUG == 1) - { - mem_init_dog(pxBlock); - mem_malloc_block(pxBlock); - } - #endif + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); } else { mtCOVERAGE_TEST_MARKER(); } + + xFreeBytesRemaining[ tag ] -= pxBlock->xBlockSize; + + if( xFreeBytesRemaining[ tag ] < xMinimumEverFreeBytesRemaining[ tag ] ) + { + xMinimumEverFreeBytesRemaining[ tag ] = xFreeBytesRemaining[ tag ]; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The block is being returned - it is allocated and owned + by the application and has no "next" block. */ + pxBlock->xAllocated = 1; + pxBlock->pxNextFreeBlock = NULL; + + #if (configENABLE_MEMORY_DEBUG == 1) + { + mem_init_dog(pxBlock); + mem_malloc_block(pxBlock); + } + #endif } else { @@ -378,21 +364,21 @@ BlockLink_t *pxLink; #endif /* Check the block is actually allocated. */ - configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( ( pxLink->xAllocated ) != 0 ); configASSERT( pxLink->pxNextFreeBlock == NULL ); - if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) + if( pxLink->xAllocated != 0 ) { if( pxLink->pxNextFreeBlock == NULL ) { /* The block is being returned to the heap - it is no longer allocated. */ - pxLink->xBlockSize &= ~xBlockAllocatedBit; + pxLink->xAllocated = 0; taskENTER_CRITICAL(&xMallocMutex); { /* Add this block to the list of free blocks. */ - xFreeBytesRemaining += pxLink->xBlockSize; + xFreeBytesRemaining[ pxLink->xTag ] += pxLink->xBlockSize; traceFREE( pv, pxLink->xBlockSize ); prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); } @@ -411,15 +397,15 @@ BlockLink_t *pxLink; } /*-----------------------------------------------------------*/ -size_t xPortGetFreeHeapSize( void ) +size_t xPortGetFreeHeapSizeTagged( BaseType_t tag ) { - return xFreeBytesRemaining; + return xFreeBytesRemaining[ tag ]; } /*-----------------------------------------------------------*/ -size_t xPortGetMinimumEverFreeHeapSize( void ) +size_t xPortGetMinimumEverFreeHeapSizeTagged( BaseType_t tag ) { - return xMinimumEverFreeBytesRemaining; + return xMinimumEverFreeBytesRemaining[ tag ]; } /*-----------------------------------------------------------*/ @@ -509,6 +495,7 @@ const HeapRegionTagged_t *pxHeapRegion; continue; } + configASSERT(pxHeapRegion->xTag < HEAPREGIONS_MAX_TAGCOUNT); xTotalRegionSize = pxHeapRegion->xSizeInBytes; /* Ensure the heap region starts on a correctly aligned boundary. */ @@ -572,6 +559,8 @@ const HeapRegionTagged_t *pxHeapRegion; } xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; + xMinimumEverFreeBytesRemaining[ pxHeapRegion->xTag ] += pxFirstFreeBlockInRegion->xBlockSize; + xFreeBytesRemaining[ pxHeapRegion->xTag ] += pxFirstFreeBlockInRegion->xBlockSize; /* Move onto the next HeapRegionTagged_t structure. */ xDefinedRegions++; @@ -586,14 +575,9 @@ const HeapRegionTagged_t *pxHeapRegion; #endif } - xMinimumEverFreeBytesRemaining = xTotalHeapSize; - xFreeBytesRemaining = xTotalHeapSize; - /* Check something was actually defined before it is accessed. */ configASSERT( xTotalHeapSize ); - /* Work out the position of the top bit in a size_t variable. */ - xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); #if (configENABLE_MEMORY_DEBUG == 1) { diff --git a/components/freertos/heap_regions_debug.c b/components/freertos/heap_regions_debug.c index d8d444a53..f221e516b 100644 --- a/components/freertos/heap_regions_debug.c +++ b/components/freertos/heap_regions_debug.c @@ -12,19 +12,17 @@ static size_t g_heap_struct_size; static mem_dbg_ctl_t g_mem_dbg; char g_mem_print = 0; static portMUX_TYPE *g_malloc_mutex = NULL; -static unsigned int g_alloc_bit; #define MEM_DEBUG(...) -void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex, unsigned int alloc_bit) +void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex) { - MEM_DEBUG("size=%d start=%p end=%p mutex=%p alloc_bit=0x%x\n", size, start, end, mutex, alloc_bit); + MEM_DEBUG("size=%d start=%p end=%p mutex=%p%x\n", size, start, end, mutex); memset(&g_mem_dbg, 0, sizeof(g_mem_dbg)); memset(&g_malloc_list, 0, sizeof(g_malloc_list)); g_malloc_mutex = mutex; g_heap_struct_size = size; g_free_list = start; g_end = end; - g_alloc_bit = alloc_bit; } void mem_debug_push(char type, void *addr) @@ -35,9 +33,9 @@ void mem_debug_push(char type, void *addr) MEM_DEBUG("push type=%d addr=%p\n", type, addr); if (g_mem_print){ if (type == DEBUG_TYPE_MALLOC){ - ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size&(~g_alloc_bit), addr); + ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size, addr); } else { - ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size&(~g_alloc_bit), addr); + ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size, addr); } } else { mem_dbg_info_t *info = &g_mem_dbg.info[g_mem_dbg.cnt%DEBUG_MAX_INFO_NUM]; @@ -58,7 +56,7 @@ void mem_debug_malloc_show(void) while (b){ d = DEBUG_BLOCK(b); d->head.task[3] = '\0'; - ets_printf("t=%s s=%u a=%p\n", d->head.task?d->head.task:"", b->size&(~g_alloc_bit), b); + ets_printf("t=%s s=%u a=%p\n", d->head.task?d->head.task:"", b->size, b); b = b->next; } taskEXIT_CRITICAL(g_malloc_mutex); @@ -140,7 +138,7 @@ void mem_malloc_show(void) while (b){ debug_b = DEBUG_BLOCK(b); - ets_printf("%s %p %p %u\n", debug_b->head.task, debug_b, b, b->size&(~g_alloc_bit)); + ets_printf("%s %p %p %u\n", debug_b->head.task, debug_b, b, b->size); b = b->next; } } @@ -149,7 +147,7 @@ void mem_malloc_block(void *data) { os_block_t *b = (os_block_t*)data; - MEM_DEBUG("mem malloc block data=%p, size=%u\n", data, b->size&(~g_alloc_bit)); + MEM_DEBUG("mem malloc block data=%p, size=%u\n", data, b->size); mem_debug_push(DEBUG_TYPE_MALLOC, data); if (b){ @@ -165,7 +163,7 @@ void mem_free_block(void *data) os_block_t *pre = &g_malloc_list; debug_block_t *debug_b; - MEM_DEBUG("mem free block data=%p, size=%d\n", data, del->size&(~g_alloc_bit)); + MEM_DEBUG("mem free block data=%p, size=%d\n", data, del->size); mem_debug_push(DEBUG_TYPE_FREE, data); if (!del) { @@ -183,7 +181,7 @@ void mem_free_block(void *data) } debug_b = DEBUG_BLOCK(del); - ets_printf("%s %p %p %u already free\n", debug_b->head.task, debug_b, del, del->size&(~g_alloc_bit)); + ets_printf("%s %p %p %u already free\n", debug_b->head.task, debug_b, del, del->size); mem_malloc_show(); abort(); } diff --git a/components/freertos/include/freertos/heap_regions.h b/components/freertos/include/freertos/heap_regions.h index aedea42a1..3e632dac7 100644 --- a/components/freertos/include/freertos/heap_regions.h +++ b/components/freertos/include/freertos/heap_regions.h @@ -16,6 +16,9 @@ #include "freertos/FreeRTOS.h" +/* The maximum amount of tags in use */ +#define HEAPREGIONS_MAX_TAGCOUNT 16 + typedef struct HeapRegionTagged { @@ -28,7 +31,8 @@ typedef struct HeapRegionTagged void vPortDefineHeapRegionsTagged( const HeapRegionTagged_t * const pxHeapRegions ); void *pvPortMallocTagged( size_t xWantedSize, BaseType_t tag ); - +size_t xPortGetMinimumEverFreeHeapSizeTagged( BaseType_t tag ); +size_t xPortGetFreeHeapSizeTagged( BaseType_t tag ); #endif \ No newline at end of file diff --git a/components/freertos/include/freertos/heap_regions_debug.h b/components/freertos/include/freertos/heap_regions_debug.h index 81bf1d6c3..6ab4681f1 100644 --- a/components/freertos/include/freertos/heap_regions_debug.h +++ b/components/freertos/include/freertos/heap_regions_debug.h @@ -60,7 +60,7 @@ typedef struct _mem_dbg_ctl{ extern void mem_check_block(void * data); extern void mem_init_dog(void *data); -extern void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex, unsigned int alloc_bit); +extern void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex); extern void mem_malloc_block(void *data); extern void mem_free_block(void *data); extern void mem_check_all(void* pv);