Skip to content

Commit 1b03981

Browse files
committed
[BH-1701] Add extended user heap statistics for debugging
Added extended statistics to help track potential memory leaks: * used user heap size per task * number of successful allocations * number of successful frees
1 parent 71f4bb8 commit 1b03981

File tree

4 files changed

+83
-38
lines changed

4 files changed

+83
-38
lines changed

module-bsp/board/linux/os/FreeRTOSConfig.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
1+
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
22
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
33

44
/*
@@ -171,6 +171,7 @@ standard names. */
171171
#ifdef DEBUG_FREERTOS
172172
#define configSYSTEM_HEAP_STATS (1)
173173
#define configUSER_HEAP_STATS (1)
174+
#define configUSER_HEAP_EXTENDED_STATS (0)
174175
#define configSYSTEM_HEAP_INTEGRITY_CHECK (1)
175176
#define PROJECT_CONFIG_HEAP_INTEGRITY_CHECKS (1)
176177
#endif

module-bsp/board/rt1051/os/include/FreeRTOSConfig.h

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ standard names. */
171171
#ifdef DEBUG_FREERTOS
172172
#define configSYSTEM_HEAP_STATS (1)
173173
#define configUSER_HEAP_STATS (1)
174+
#define configUSER_HEAP_EXTENDED_STATS (0)
174175
#define configSYSTEM_HEAP_INTEGRITY_CHECK (1)
175176
#define PROJECT_CONFIG_HEAP_INTEGRITY_CHECKS (1)
176177
#endif

module-os/memory/usermem.c

+79-36
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ typedef struct A_BLOCK_LINK
7272
#if (configUSER_HEAP_STATS == 1)
7373
TaskHandle_t xAllocatingTask; /*<< The task allocating the memory block. */
7474
TickType_t xTimeAllocated; /*<< The timestamp of memory block allocation. */
75-
#endif
75+
#if (configUSER_HEAP_EXTENDED_STATS == 1)
76+
struct A_BLOCK_LINK *pxNextTakenBlock, *pxPrevTakenBlock;
77+
#endif // configUSER_HEAP_EXTENDED_STATS
78+
#endif // configUSER_HEAP_STATS
7679
} BlockLink_t;
7780

7881
/*-----------------------------------------------------------*/
@@ -100,12 +103,22 @@ static const size_t xHeapStructSize = (sizeof(BlockLink_t)
100103
& ~((size_t) usermemBYTE_ALIGNMENT_MASK);
101104

102105
/* Create a couple of list links to mark the start and end of the list. */
103-
static BlockLink_t userxStart, *userpxEnd = NULL;
106+
static BlockLink_t xUserStart, *pxUserEnd = NULL;
107+
108+
/* Start/end of used blocks list */
109+
#if (configUSER_HEAP_STATS == 1 && configUSER_HEAP_EXTENDED_STATS == 1)
110+
static BlockLink_t xUserTakenEnd;
111+
#endif
104112

105113
/* Keeps track of the number of free bytes remaining, but says nothing about
106114
fragmentation. */
107-
static size_t userxFreeBytesRemaining = 0U;
108-
static size_t userxMinimumEverFreeBytesRemaining = 0U;
115+
static size_t xUserFreeBytesRemaining = 0U;
116+
static size_t xUserMinimumEverFreeBytesRemaining = 0U;
117+
118+
#if (configUSER_HEAP_STATS == 1 && configUSER_HEAP_EXTENDED_STATS == 1)
119+
static size_t xUserNumberOfSuccessfulAllocations = 0U;
120+
static size_t xUserNumberOfSuccessfulFrees = 0U;
121+
#endif
109122

110123
/* Allocation statistics */
111124
static size_t xAllocationsCount = 0;
@@ -134,7 +147,7 @@ void *usermalloc(size_t xWantedSize)
134147
{
135148
/* If this is the first call to malloc then the heap will require
136149
initialisation to setup the list of free blocks. */
137-
if( userpxEnd == NULL )
150+
if( pxUserEnd == NULL )
138151
{
139152
prvHeapInit();
140153
}
@@ -173,12 +186,12 @@ void *usermalloc(size_t xWantedSize)
173186
mtCOVERAGE_TEST_MARKER();
174187
}
175188

176-
if( ( xWantedSize > 0 ) && ( xWantedSize <= userxFreeBytesRemaining ) )
189+
if( ( xWantedSize > 0 ) && ( xWantedSize <= xUserFreeBytesRemaining ) )
177190
{
178191
/* Traverse the list from the start (lowest address) block until
179192
one of adequate size is found. */
180-
pxPreviousBlock = &userxStart;
181-
pxBlock = userxStart.pxNextFreeBlock;
193+
pxPreviousBlock = &xUserStart;
194+
pxBlock = xUserStart.pxNextFreeBlock;
182195
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
183196
{
184197
pxPreviousBlock = pxBlock;
@@ -187,7 +200,7 @@ void *usermalloc(size_t xWantedSize)
187200

188201
/* If the end marker was reached then a block of adequate size
189202
was not found. */
190-
if( pxBlock != userpxEnd )
203+
if( pxBlock != pxUserEnd )
191204
{
192205
/* Return the memory space pointed to - jumping over the
193206
BlockLink_t structure at its start. */
@@ -236,11 +249,11 @@ void *usermalloc(size_t xWantedSize)
236249
xAllocatedSum += pxBlock->xBlockSize;
237250
#endif
238251

239-
userxFreeBytesRemaining -= pxBlock->xBlockSize;
252+
xUserFreeBytesRemaining -= pxBlock->xBlockSize;
240253

241-
if( userxFreeBytesRemaining < userxMinimumEverFreeBytesRemaining )
254+
if( xUserFreeBytesRemaining < xUserMinimumEverFreeBytesRemaining )
242255
{
243-
userxMinimumEverFreeBytesRemaining = userxFreeBytesRemaining;
256+
xUserMinimumEverFreeBytesRemaining = xUserFreeBytesRemaining;
244257
}
245258
else
246259
{
@@ -251,9 +264,16 @@ void *usermalloc(size_t xWantedSize)
251264
by the application and has no "next" block. */
252265
pxBlock->xBlockSize |= xBlockAllocatedBit;
253266
#if (configUSER_HEAP_STATS == 1)
267+
#if (configUSER_HEAP_EXTENDED_STATS == 1)
268+
/* Push taken block at the end of the taken list */
269+
xUserTakenEnd.pxPrevTakenBlock->pxNextTakenBlock = pxBlock;
270+
pxBlock->pxPrevTakenBlock = xUserTakenEnd.pxPrevTakenBlock;
271+
pxBlock->pxNextTakenBlock = &xUserTakenEnd;
272+
xUserTakenEnd.pxPrevTakenBlock = pxBlock;
273+
#endif // configUSER_HEAP_EXTENDED_STATS
254274
pxBlock->xAllocatingTask = xTaskGetCurrentTaskHandle();
255275
pxBlock->xTimeAllocated = xTaskGetTickCount();
256-
#endif
276+
#endif // configUSER_HEAP_STATS
257277

258278
#if (PROJECT_CONFIG_HEAP_INTEGRITY_CHECKS != 0)
259279
{
@@ -265,6 +285,9 @@ void *usermalloc(size_t xWantedSize)
265285
#endif
266286

267287
pxBlock->pxNextFreeBlock = NULL;
288+
#if (configUSER_HEAP_STATS == 1 && configUSER_HEAP_EXTENDED_STATS == 1)
289+
xUserNumberOfSuccessfulAllocations++;
290+
#endif
268291
}
269292
else
270293
{
@@ -350,9 +373,17 @@ void userfree(void *pv)
350373
#endif
351374

352375
/* Add this block to the list of free blocks. */
353-
userxFreeBytesRemaining += pxLink->xBlockSize;
376+
xUserFreeBytesRemaining += pxLink->xBlockSize;
354377
traceFREE( pv, pxLink->xBlockSize );
355378
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
379+
#if (configUSER_HEAP_STATS == 1 && configUSER_HEAP_EXTENDED_STATS == 1)
380+
xUserNumberOfSuccessfulFrees++;
381+
/* Update taken list */
382+
pxLink->pxPrevTakenBlock->pxNextTakenBlock = pxLink->pxNextTakenBlock;
383+
pxLink->pxNextTakenBlock->pxPrevTakenBlock = pxLink->pxPrevTakenBlock;
384+
pxLink->pxPrevTakenBlock = NULL;
385+
pxLink->pxNextTakenBlock = NULL;
386+
#endif
356387
}
357388
( void ) xTaskResumeAll();
358389
}
@@ -417,13 +448,13 @@ void *userrealloc(void *pv, size_t xWantedSize) {
417448

418449
size_t usermemGetFreeHeapSize( void )
419450
{
420-
return userxFreeBytesRemaining;
451+
return xUserFreeBytesRemaining;
421452
}
422453
/*-----------------------------------------------------------*/
423454

424455
size_t usermemGetMinimumEverFreeHeapSize( void )
425456
{
426-
return userxMinimumEverFreeBytesRemaining;
457+
return xUserMinimumEverFreeBytesRemaining;
427458
}
428459
/*-----------------------------------------------------------*/
429460

@@ -478,42 +509,54 @@ size_t xTotalHeapSize = USERMEM_TOTAL_HEAP_SIZE;
478509

479510
pucAlignedHeap = ( uint8_t * ) uxAddress;
480511

481-
/* userxStart is used to hold a pointer to the first item in the list of free
512+
/* xUserStart is used to hold a pointer to the first item in the list of free
482513
blocks. The void cast is used to prevent compiler warnings. */
483-
userxStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
484-
userxStart.xBlockSize = ( size_t ) 0;
514+
xUserStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
515+
xUserStart.xBlockSize = ( size_t ) 0;
485516
#if (configUSER_HEAP_STATS == 1)
486-
userxStart.xTimeAllocated = 0;
487-
userxStart.xAllocatingTask = 0;
488-
#endif
489-
490-
/* userpxEnd is used to mark the end of the list of free blocks and is inserted
517+
xUserStart.xTimeAllocated = 0;
518+
xUserStart.xAllocatingTask = 0;
519+
520+
#if (configUSER_HEAP_EXTENDED_STATS == 1)
521+
xUserStart.pxNextTakenBlock = &xUserTakenEnd;
522+
xUserStart.pxPrevTakenBlock = NULL;
523+
524+
xUserTakenEnd.pxNextFreeBlock = NULL;
525+
xUserTakenEnd.xBlockSize = 0;
526+
xUserTakenEnd.pxNextTakenBlock = NULL;
527+
xUserTakenEnd.pxPrevTakenBlock = &xUserStart;
528+
xUserTakenEnd.xTimeAllocated = 0;
529+
xUserTakenEnd.xAllocatingTask = 0;
530+
#endif // configUSER_HEAP_EXTENDED_STATS
531+
#endif // configUSER_HEAP_STATS
532+
533+
/* pxUserEnd is used to mark the end of the list of free blocks and is inserted
491534
at the end of the heap space. */
492535
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
493536
uxAddress -= xHeapStructSize;
494537
uxAddress &= ~( ( size_t ) usermemBYTE_ALIGNMENT_MASK );
495-
userpxEnd = ( void * ) uxAddress;
496-
userpxEnd->xBlockSize = 0;
497-
userpxEnd->pxNextFreeBlock = NULL;
538+
pxUserEnd = ( void * ) uxAddress;
539+
pxUserEnd->xBlockSize = 0;
540+
pxUserEnd->pxNextFreeBlock = NULL;
498541
#if (configUSER_HEAP_STATS == 1)
499-
userpxEnd->xTimeAllocated = 0;
500-
userpxEnd->xAllocatingTask = 0;
542+
pxUserEnd->xTimeAllocated = 0;
543+
pxUserEnd->xAllocatingTask = 0;
501544
#endif
502545

503546
/* To start with there is a single free block that is sized to take up the
504-
entire heap space, minus the space taken by userpxEnd. */
547+
entire heap space, minus the space taken by pxUserEnd. */
505548
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
506549
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
507-
pxFirstFreeBlock->pxNextFreeBlock = userpxEnd;
550+
pxFirstFreeBlock->pxNextFreeBlock = pxUserEnd;
508551
#if( PROJECT_CONFIG_HEAP_INTEGRITY_CHECKS != 0 )
509552
{
510553
pxFirstFreeBlock->ulStamp = INTEGRITY_STAMP_FREE;
511554
}
512555
#endif
513556

514557
/* Only one block exists - and it covers the entire usable heap space. */
515-
userxMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
516-
userxFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
558+
xUserMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
559+
xUserFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
517560

518561
/* Work out the position of the top bit in a size_t variable. */
519562
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
@@ -527,7 +570,7 @@ uint8_t *puc;
527570

528571
/* Iterate through the list until a block is found that has a higher address
529572
than the block being inserted. */
530-
for( pxIterator = &userxStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
573+
for( pxIterator = &xUserStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
531574
{
532575
/* Nothing to do here, just iterate to the right position. */
533576
}
@@ -550,15 +593,15 @@ uint8_t *puc;
550593
puc = ( uint8_t * ) pxBlockToInsert;
551594
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
552595
{
553-
if( pxIterator->pxNextFreeBlock != userpxEnd )
596+
if( pxIterator->pxNextFreeBlock != pxUserEnd )
554597
{
555598
/* Form one big block from the two blocks. */
556599
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
557600
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
558601
}
559602
else
560603
{
561-
pxBlockToInsert->pxNextFreeBlock = userpxEnd;
604+
pxBlockToInsert->pxNextFreeBlock = pxUserEnd;
562605
}
563606
}
564607
else

tools/misc

0 commit comments

Comments
 (0)