]> granicus.if.org Git - esp-idf/commitdiff
Add xPortGetFreeHeapSizeCaps and xPortGetMinimumEverFreeHeapSizeCaps plus everything...
authorJeroen Domburg <git@j0h.nl>
Fri, 9 Dec 2016 09:13:45 +0000 (17:13 +0800)
committerJeroen Domburg <jeroen@espressif.com>
Thu, 15 Dec 2016 07:03:22 +0000 (15:03 +0800)
components/esp32/heap_alloc_caps.c
components/esp32/include/esp_heap_alloc_caps.h
components/freertos/heap_regions.c
components/freertos/heap_regions_debug.c
components/freertos/include/freertos/heap_regions.h
components/freertos/include/freertos/heap_regions_debug.h

index 7e6ce422c955c98ab0dffdd4d292b03ed1b74f0e..7ce8ba5ca664a573bd402921d46486f2dce99af1 100644 (file)
@@ -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<NO_PRIOS; prio++) {
+        //Iterate over tag descriptors for this priority
+        for (tag=0; tag_desc[tag].prio[prio]!=MALLOC_CAP_INVALID; tag++) {
+            if ((tag_desc[tag].prio[prio]&caps)!=0) {
+                ret+=xPortGetFreeHeapSizeTagged(tag);
+            }
+        }
+    }
+    return ret;
+}
+
+size_t xPortGetMinimumEverFreeHeapSizeCaps( uint32_t caps )
+{
+    int prio;
+    int tag;
+    size_t ret=0;
+    for (prio=0; prio<NO_PRIOS; prio++) {
+        //Iterate over tag descriptors for this priority
+        for (tag=0; tag_desc[tag].prio[prio]!=MALLOC_CAP_INVALID; tag++) {
+            if ((tag_desc[tag].prio[prio]&caps)!=0) {
+                ret+=xPortGetMinimumEverFreeHeapSizeTagged(tag);
+            }
+        }
+    }
+    return ret;
+}
+
+size_t xPortGetFreeHeapSize( void )
+{
+    return xPortGetFreeHeapSizeCaps( MALLOC_CAP_8BIT );
+}
+
+size_t xPortGetMinimumEverFreeHeapSize( void )
+{
+    return xPortGetMinimumEverFreeHeapSizeCaps( MALLOC_CAP_8BIT );
+}
+
+
+
+
+
+
+
index cb880d6a42d40131bc2cdcabe87e069a2bde65f2..42bc614c21fa52c2a143f212a16690152e6ab60b 100644 (file)
@@ -30,5 +30,7 @@
 
 void heap_alloc_caps_init();
 void *pvPortMallocCaps(size_t xWantedSize, uint32_t caps);
+size_t xPortGetFreeHeapSizeCaps( uint32_t caps );
+size_t xPortGetMinimumEverFreeHeapSizeCaps( uint32_t caps );
 
 #endif
\ No newline at end of file
index 51df477f27f1a74de02c8d5b268f073e07ca7446..6e1cb103fd74067ff8a0c407662aed06f2163e71 100644 (file)
@@ -148,11 +148,13 @@ task.h is included from an application file. */
 
 /* Define the linked list structure.  This is used to link free blocks in order
 of their memory address. */
+/* This is optimized and assumes a region is never larger than 16MiB. */
 typedef struct A_BLOCK_LINK
 {
     struct A_BLOCK_LINK *pxNextFreeBlock;   /*<< The next free block in the list. */
-    size_t xBlockSize;                      /*<< The size of the free block. */
-    BaseType_t xTag;                            /*<< Tag of this region */
+    int xBlockSize: 24;                     /*<< The size of the free block. */
+    int xTag: 7;                            /*<< Tag of this region */
+    int xAllocated: 1;                      /*<< 1 if allocated */
 } BlockLink_t;
 
 //Mux to protect the memory status data
@@ -179,14 +181,9 @@ static BlockLink_t xStart, *pxEnd = NULL;
 
 /* Keeps track of the number of free bytes remaining, but says nothing about
 fragmentation. */
-static size_t xFreeBytesRemaining = 0;
-static size_t xMinimumEverFreeBytesRemaining = 0;
+static size_t xFreeBytesRemaining[HEAPREGIONS_MAX_TAGCOUNT] = {0};
+static size_t xMinimumEverFreeBytesRemaining[HEAPREGIONS_MAX_TAGCOUNT] = {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
-application.  When the bit is free the block is still part of the free heap
-space. */
-static size_t xBlockAllocatedBit = 0;
 
 /*-----------------------------------------------------------*/
 
@@ -201,126 +198,115 @@ void *pvReturn = NULL;
 
     taskENTER_CRITICAL(&xMallocMutex);
     {
-        /* Check the requested block size is not so large that the top bit is
-        set.  The top bit of the block size member of the BlockLink_t structure
-        is used to determine who owns the block - the application or the
-        kernel, so it must be free. */
-        if( ( xWantedSize & xBlockAllocatedBit ) == 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 )
         {
-            /* 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 ) )
+        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 ) )
             {
-                /* 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);
+//             ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock);
 
-                                        #if (configENABLE_MEMORY_DEBUG == 1)
-                                        {
-                                            mem_check_block(pxBlock);
-                                        }
-                                        #endif
+                                    #if (configENABLE_MEMORY_DEBUG == 1)
+                                    {
+                                        mem_check_block(pxBlock);
+                                    }
+                                    #endif
 
-                    pxPreviousBlock = pxBlock;
-                    pxBlock = pxBlock->pxNextFreeBlock;
-                }
+               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);
 
-                /* If the end marker was not reached then a block of adequate size
-                was found. */
-                if( pxBlock != pxEnd )
+                /* 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 )
                 {
-                    /* 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
-
-
-                        /* 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
+                    /* 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
+
+
+                    /* 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)
         {
index d8d444a53724f2e715865d867146aa606b88f792..f221e516b0b4875127b1527f77acd58b25a4eabb 100644 (file)
@@ -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();
 }
index aedea42a1698e6d9dc812cf5161449819d810306..3e632dac7adad1b4db54000a9da2f570e786a9ec 100644 (file)
@@ -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
index 81bf1d6c3b18972f0b2d980f418c37db20410092..6ab4681f18f7d254c777c9ea1d9b422d553fde27 100644 (file)
@@ -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);