From d481e78aa9eed27428365085c63cac20caa846f0 Mon Sep 17 00:00:00 2001 From: rtel Date: Thu, 4 Jul 2019 19:34:48 +0000 Subject: [PATCH 1/1] Add vPortGetHeapStats() function to query heap statistics. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2671 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/include/portable.h | 20 +++++++- FreeRTOS/Source/portable/MemMang/heap_4.c | 60 ++++++++++++++++++++++- FreeRTOS/Source/portable/MemMang/heap_5.c | 60 ++++++++++++++++++++++- 3 files changed, 135 insertions(+), 5 deletions(-) diff --git a/FreeRTOS/Source/include/portable.h b/FreeRTOS/Source/include/portable.h index a1bb44905..d2baf14a4 100644 --- a/FreeRTOS/Source/include/portable.h +++ b/FreeRTOS/Source/include/portable.h @@ -118,13 +118,26 @@ extern "C" { #endif #endif -/* Used by heap_5.c. */ +/* Used by heap_5.c to define the start address and size of each memory region +that together comprise the total FreeRTOS heap space. */ typedef struct HeapRegion { uint8_t *pucStartAddress; size_t xSizeInBytes; } HeapRegion_t; +/* Used to pass information about the heap out of vPortGetHeapStats(). */ +typedef struct xHeapStats +{ + size_t xAvailableHeapSpaceInBytes; /* The total heap size currently available - this is the sum of all the free blocks, not the largest block that can be allocated. */ + size_t xSizeOfLargestFreeBlockInBytes; /* The maximum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */ + size_t xSizeOfSmallestFreeBlockInBytes; /* The minimum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */ + size_t xNumberOfFreeBlocks; /* The number of free memory blocks within the heap at the time vPortGetHeapStats() is called. */ + size_t xMinimumEverFreeBytesRemaining; /* The minimum amount of total free memory (sum of all free blocks) there has been in the heap since the system booted. */ + size_t xNumberOfSuccessfulAllocations; /* The number of calls to pvPortMalloc() that have returned a valid memory block. */ + size_t xNumberOfSuccessfulFrees; /* The number of calls to vPortFree() that has successfully freed a block of memory. */ +} HeapStats_t; + /* * Used to define multiple heap regions for use by heap_5.c. This function * must be called before any calls to pvPortMalloc() - not creating a task, @@ -138,6 +151,11 @@ typedef struct HeapRegion */ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION; +/* + * Returns a HeapStats_t structure filled with information about the current + * heap state. + */ +void vPortGetHeapStats( HeapStats_t *pxHeapStats ); /* * Map to the memory management routines required for the port. diff --git a/FreeRTOS/Source/portable/MemMang/heap_4.c b/FreeRTOS/Source/portable/MemMang/heap_4.c index 23714eb24..927064634 100644 --- a/FreeRTOS/Source/portable/MemMang/heap_4.c +++ b/FreeRTOS/Source/portable/MemMang/heap_4.c @@ -97,10 +97,12 @@ static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( p /* Create a couple of list links to mark the start and end of the list. */ static BlockLink_t xStart, *pxEnd = NULL; -/* Keeps track of the number of free bytes remaining, but says nothing about -fragmentation. */ +/* Keeps track of the number of calls to allocate and free memory as well as the +number of free bytes remaining, but says nothing about fragmentation. */ static size_t xFreeBytesRemaining = 0U; static size_t xMinimumEverFreeBytesRemaining = 0U; +static size_t xNumberOfSuccessfulAllocations = 0; +static size_t xNumberOfSuccessfulFrees = 0; /* Gets set to the top bit of an size_t type. When this bit in the xBlockSize member of an BlockLink_t structure is set then the block belongs to the @@ -221,6 +223,7 @@ void *pvReturn = NULL; by the application and has no "next" block. */ pxBlock->xBlockSize |= xBlockAllocatedBit; pxBlock->pxNextFreeBlock = NULL; + xNumberOfSuccessfulAllocations++; } else { @@ -292,6 +295,7 @@ BlockLink_t *pxLink; xFreeBytesRemaining += pxLink->xBlockSize; traceFREE( pv, pxLink->xBlockSize ); prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + xNumberOfSuccessfulFrees++; } ( void ) xTaskResumeAll(); } @@ -326,6 +330,58 @@ void vPortInitialiseBlocks( void ) } /*-----------------------------------------------------------*/ +void vPortGetHeapStats( HeapStats_t *pxHeapStats ) +{ +BlockLink_t *pxBlock; +size_t xBlocks = 0, xMaxSize = 0, xMinSize = 0; + + vTaskSuspendAll(); + { + pxBlock = xStart.pxNextFreeBlock; + + /* pxBlock will be NULL if the heap has not been initialised. The heap + is initialised automatically when the first allocation is made. */ + if( pxBlock != NULL ) + { + do + { + /* Increment the number of blocks and record the largest block seen + so far. */ + xBlocks++; + + if( pxBlock->xBlockSize > xMaxSize ) + { + xMaxSize = pxBlock->xBlockSize; + } + + if( pxBlock->xBlockSize < xMinSize ) + { + xMinSize = pxBlock->xBlockSize; + } + + /* Move to the next block in the chain until the last block is + reached. */ + pxBlock = pxBlock->pxNextFreeBlock; + } while( pxBlock != pxEnd ); + } + } + xTaskResumeAll(); + + pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize; + pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize; + pxHeapStats->xNumberOfFreeBlocks = xBlocks; + + taskENTER_CRITICAL(); + { + pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining; + pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations; + pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees; + pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + static void prvHeapInit( void ) { BlockLink_t *pxFirstFreeBlock; diff --git a/FreeRTOS/Source/portable/MemMang/heap_5.c b/FreeRTOS/Source/portable/MemMang/heap_5.c index 8e5076236..614210edf 100644 --- a/FreeRTOS/Source/portable/MemMang/heap_5.c +++ b/FreeRTOS/Source/portable/MemMang/heap_5.c @@ -116,10 +116,12 @@ static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( p /* Create a couple of list links to mark the start and end of the list. */ static BlockLink_t xStart, *pxEnd = NULL; -/* Keeps track of the number of free bytes remaining, but says nothing about -fragmentation. */ +/* Keeps track of the number of calls to allocate and free memory as well as the +number of free bytes remaining, but says nothing about fragmentation. */ static size_t xFreeBytesRemaining = 0U; static size_t xMinimumEverFreeBytesRemaining = 0U; +static size_t xNumberOfSuccessfulAllocations = 0; +static size_t xNumberOfSuccessfulFrees = 0; /* Gets set to the top bit of an size_t type. When this bit in the xBlockSize member of an BlockLink_t structure is set then the block belongs to the @@ -231,6 +233,7 @@ void *pvReturn = NULL; by the application and has no "next" block. */ pxBlock->xBlockSize |= xBlockAllocatedBit; pxBlock->pxNextFreeBlock = NULL; + xNumberOfSuccessfulAllocations++; } else { @@ -301,6 +304,7 @@ BlockLink_t *pxLink; xFreeBytesRemaining += pxLink->xBlockSize; traceFREE( pv, pxLink->xBlockSize ); prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + xNumberOfSuccessfulFrees++; } ( void ) xTaskResumeAll(); } @@ -482,4 +486,56 @@ const HeapRegion_t *pxHeapRegion; /* Work out the position of the top bit in a size_t variable. */ xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); } +/*-----------------------------------------------------------*/ + +void vPortGetHeapStats( HeapStats_t *pxHeapStats ) +{ + BlockLink_t *pxBlock; + size_t xBlocks = 0, xMaxSize = 0, xMinSize = 0; + + vTaskSuspendAll(); + { + pxBlock = xStart.pxNextFreeBlock; + + /* pxBlock will be NULL if the heap has not been initialised. The heap + is initialised automatically when the first allocation is made. */ + if( pxBlock != NULL ) + { + do + { + /* Increment the number of blocks and record the largest block seen + so far. */ + xBlocks++; + + if( pxBlock->xBlockSize > xMaxSize ) + { + xMaxSize = pxBlock->xBlockSize; + } + + if( pxBlock->xBlockSize < xMinSize ) + { + xMinSize = pxBlock->xBlockSize; + } + + /* Move to the next block in the chain until the last block is + reached. */ + pxBlock = pxBlock->pxNextFreeBlock; + } while( pxBlock != pxEnd ); + } + } + xTaskResumeAll(); + + pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize; + pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize; + pxHeapStats->xNumberOfFreeBlocks = xBlocks; + + taskENTER_CRITICAL(); + { + pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining; + pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations; + pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees; + pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining; + } + taskEXIT_CRITICAL(); +} -- 2.39.2