mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Memory usage statistics for heap and pools.
This commit is contained in:
parent
d25d33cd58
commit
aaf3d76cae
2
Makefile
2
Makefile
@ -80,7 +80,7 @@ MCU_CFLAGS += -ffunction-sections -fdata-sections
|
||||
DEBUG_OPTIONS = -g3 -O0 -DDEBUG #-fsanitize=address
|
||||
RELEASE_OPTIONS = -Os -Werror -DNDEBUG
|
||||
|
||||
DEFINES = -DMEM_HEAP_CHUNK_SIZE=256 -DMEM_HEAP_AREA_SIZE=32768
|
||||
DEFINES = -DMEM_HEAP_CHUNK_SIZE=256 -DMEM_HEAP_AREA_SIZE=32768 -DMEM_STATS
|
||||
TARGET_HOST = -D__HOST
|
||||
TARGET_MCU = -D__MCU
|
||||
|
||||
|
||||
@ -64,22 +64,12 @@ typedef enum
|
||||
*/
|
||||
typedef struct mem_BlockHeader_t
|
||||
{
|
||||
mem_MagicNumOfBlock_t m_MagicNum; /**< magic number - MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK for allocated block
|
||||
and MEM_MAGIC_NUM_OF_FREE_BLOCK for free block */
|
||||
mem_MagicNumOfBlock_t m_MagicNum; /**< magic number - MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK for allocated block
|
||||
and MEM_MAGIC_NUM_OF_FREE_BLOCK for free block */
|
||||
struct mem_BlockHeader_t *m_Neighbours[ MEM_DIRECTION_COUNT ]; /**< neighbour blocks */
|
||||
size_t m_SizeInChunks; /**< size of block with header in chunks */
|
||||
size_t allocated_bytes; /**< allocated area size - for allocated blocks; 0 - for free blocks */
|
||||
} mem_BlockHeader_t;
|
||||
|
||||
/**
|
||||
* Calculate size in bytes of the block space, that can be used to store data
|
||||
*/
|
||||
#define mem_GetHeapBlockDataSpaceSizeInBytes( pBlockHeader) ( MEM_HEAP_CHUNK_SIZE * pBlockHeader->m_SizeInChunks - sizeof(mem_BlockHeader_t) )
|
||||
|
||||
/**
|
||||
* Calculate size in chunks of heap block from data space size in bytes
|
||||
*/
|
||||
#define mem_GetHeapBlockSizeInChunksFromDataSpaceSizeInBytes( size) ( ( sizeof(mem_BlockHeader_t) + size + MEM_HEAP_CHUNK_SIZE - 1 ) / MEM_HEAP_CHUNK_SIZE )
|
||||
|
||||
/**
|
||||
* Chunk should have enough space for block header
|
||||
*/
|
||||
@ -95,8 +85,8 @@ JERRY_STATIC_ASSERT( MEM_HEAP_CHUNK_SIZE % MEM_ALIGNMENT == 0 );
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t* m_HeapStart; /**< first address of heap space */
|
||||
size_t m_HeapSize; /**< heap space size */
|
||||
uint8_t* m_HeapStart; /**< first address of heap space */
|
||||
size_t m_HeapSize; /**< heap space size */
|
||||
mem_BlockHeader_t* m_pFirstBlock; /**< first block of the heap */
|
||||
mem_BlockHeader_t* m_pLastBlock; /**< last block of the heap */
|
||||
} mem_HeapState_t;
|
||||
@ -106,6 +96,10 @@ typedef struct
|
||||
*/
|
||||
mem_HeapState_t mem_Heap;
|
||||
|
||||
static inline size_t mem_get_block_chunks_count( const mem_BlockHeader_t *block_header_p);
|
||||
static inline size_t mem_get_block_data_space_size( const mem_BlockHeader_t *block_header_p);
|
||||
static inline size_t mem_get_block_chunks_count_from_data_size( size_t block_allocated_size);
|
||||
|
||||
static void mem_InitBlockHeader( uint8_t *pFirstChunk,
|
||||
size_t sizeInChunks,
|
||||
mem_BlockState_t blockState,
|
||||
@ -113,12 +107,80 @@ static void mem_InitBlockHeader( uint8_t *pFirstChunk,
|
||||
mem_BlockHeader_t *pNextBlock);
|
||||
static void mem_CheckHeap( void);
|
||||
|
||||
#ifdef MEM_STATS
|
||||
/**
|
||||
* Heap's memory usage statistics
|
||||
*/
|
||||
static mem_HeapStats_t mem_HeapStats;
|
||||
|
||||
static void mem_HeapStatInit( void);
|
||||
static void mem_HeapStatAllocBlock( mem_BlockHeader_t *block_header_p);
|
||||
static void mem_HeapStatFreeBlock( mem_BlockHeader_t *block_header_p);
|
||||
static void mem_HeapStatFreeBlockSplit( void);
|
||||
static void mem_HeapStatFreeBlockMerge( void);
|
||||
#else /* !MEM_STATS */
|
||||
# define mem_InitStats()
|
||||
# define mem_HeapStatAllocBlock( v)
|
||||
# define mem_HeapStatFreeBlock( v)
|
||||
# define mem_HeapStatFreeBlockSplit()
|
||||
# define mem_HeapStatFreeBlockMerge()
|
||||
#endif /* !MEM_STATS */
|
||||
|
||||
/**
|
||||
* get chunk count, used by the block.
|
||||
*
|
||||
* @return chunks count
|
||||
*/
|
||||
static inline size_t
|
||||
mem_get_block_chunks_count( const mem_BlockHeader_t *block_header_p) /**< block header */
|
||||
{
|
||||
JERRY_ASSERT( block_header_p != NULL );
|
||||
|
||||
const mem_BlockHeader_t *next_block_p = block_header_p->m_Neighbours[ MEM_DIRECTION_NEXT ];
|
||||
size_t dist_till_block_end;
|
||||
|
||||
if ( next_block_p == NULL )
|
||||
{
|
||||
dist_till_block_end = (size_t) ( mem_Heap.m_HeapStart + mem_Heap.m_HeapSize - (uint8_t*) block_header_p );
|
||||
} else
|
||||
{
|
||||
dist_till_block_end = (size_t) ( (uint8_t*) next_block_p - (uint8_t*) block_header_p );
|
||||
}
|
||||
|
||||
JERRY_ASSERT( dist_till_block_end <= mem_Heap.m_HeapSize );
|
||||
JERRY_ASSERT( dist_till_block_end % MEM_HEAP_CHUNK_SIZE == 0 );
|
||||
|
||||
return dist_till_block_end / MEM_HEAP_CHUNK_SIZE;
|
||||
} /* mem_get_block_chunks_count */
|
||||
|
||||
/**
|
||||
* Calculate block's data space size
|
||||
*
|
||||
* @return size of block area that can be used to store data
|
||||
*/
|
||||
static inline size_t
|
||||
mem_get_block_data_space_size( const mem_BlockHeader_t *block_header_p) /**< block header */
|
||||
{
|
||||
return mem_get_block_chunks_count( block_header_p) * MEM_HEAP_CHUNK_SIZE - sizeof (mem_BlockHeader_t);
|
||||
} /* mem_get_block_data_space_size */
|
||||
|
||||
/**
|
||||
* Calculate minimum chunks count needed for block with specified size of allocated data area.
|
||||
*
|
||||
* @return chunks count
|
||||
*/
|
||||
static inline size_t
|
||||
mem_get_block_chunks_count_from_data_size( size_t block_allocated_size) /**< size of block's allocated area */
|
||||
{
|
||||
return JERRY_ALIGNUP( sizeof (mem_BlockHeader_t) + block_allocated_size, MEM_HEAP_CHUNK_SIZE) / MEM_HEAP_CHUNK_SIZE;
|
||||
} /* mem_get_block_chunks_count_from_data_size */
|
||||
|
||||
/**
|
||||
* Startup initialization of heap
|
||||
*/
|
||||
void
|
||||
mem_HeapInit( uint8_t *heapStart, /**< first address of heap space */
|
||||
size_t heapSize) /**< heap space size */
|
||||
mem_HeapInit(uint8_t *heapStart, /**< first address of heap space */
|
||||
size_t heapSize) /**< heap space size */
|
||||
{
|
||||
JERRY_ASSERT( heapStart != NULL );
|
||||
JERRY_ASSERT( heapSize != 0 );
|
||||
@ -128,22 +190,24 @@ mem_HeapInit( uint8_t *heapStart, /**< first address of heap space */
|
||||
mem_Heap.m_HeapStart = heapStart;
|
||||
mem_Heap.m_HeapSize = heapSize;
|
||||
|
||||
mem_InitBlockHeader( mem_Heap.m_HeapStart,
|
||||
heapSize / MEM_HEAP_CHUNK_SIZE,
|
||||
mem_InitBlockHeader(mem_Heap.m_HeapStart,
|
||||
0,
|
||||
MEM_BLOCK_FREE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
mem_Heap.m_pFirstBlock = (mem_BlockHeader_t*) mem_Heap.m_HeapStart;
|
||||
mem_Heap.m_pLastBlock = mem_Heap.m_pFirstBlock;
|
||||
|
||||
mem_HeapStatInit();
|
||||
} /* mem_HeapInit */
|
||||
|
||||
/**
|
||||
* Initialize block header
|
||||
*/
|
||||
static void
|
||||
mem_InitBlockHeader( uint8_t *pFirstChunk, /**< address of the first chunk to use for the block */
|
||||
size_t sizeInChunks, /**< size of block with header in chunks */
|
||||
mem_InitBlockHeader( uint8_t *pFirstChunk, /**< address of the first chunk to use for the block */
|
||||
size_t allocated_bytes, /**< size of block's allocated area */
|
||||
mem_BlockState_t blockState, /**< state of the block (allocated or free) */
|
||||
mem_BlockHeader_t *pPrevBlock, /**< previous block */
|
||||
mem_BlockHeader_t *pNextBlock) /**< next block */
|
||||
@ -151,17 +215,21 @@ mem_InitBlockHeader( uint8_t *pFirstChunk, /**< address of the fir
|
||||
mem_BlockHeader_t *pBlockHeader = (mem_BlockHeader_t*) pFirstChunk;
|
||||
|
||||
if ( blockState == MEM_BLOCK_FREE )
|
||||
{
|
||||
pBlockHeader->m_MagicNum = MEM_MAGIC_NUM_OF_FREE_BLOCK;
|
||||
} else
|
||||
{
|
||||
pBlockHeader->m_MagicNum = MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK;
|
||||
}
|
||||
{
|
||||
pBlockHeader->m_MagicNum = MEM_MAGIC_NUM_OF_FREE_BLOCK;
|
||||
|
||||
pBlockHeader->m_Neighbours[ MEM_DIRECTION_PREV ] = pPrevBlock;
|
||||
pBlockHeader->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock;
|
||||
pBlockHeader->m_SizeInChunks = sizeInChunks;
|
||||
} /* mem_InitFreeBlock */
|
||||
JERRY_ASSERT( allocated_bytes == 0 );
|
||||
} else
|
||||
{
|
||||
pBlockHeader->m_MagicNum = MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK;
|
||||
}
|
||||
|
||||
pBlockHeader->m_Neighbours[ MEM_DIRECTION_PREV ] = pPrevBlock;
|
||||
pBlockHeader->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock;
|
||||
pBlockHeader->allocated_bytes = allocated_bytes;
|
||||
|
||||
JERRY_ASSERT( allocated_bytes <= mem_get_block_data_space_size( pBlockHeader) );
|
||||
} /* mem_InitBlockHeader */
|
||||
|
||||
/**
|
||||
* Allocation of memory region.
|
||||
@ -177,7 +245,7 @@ mem_InitBlockHeader( uint8_t *pFirstChunk, /**< address of the fir
|
||||
* NULL - if there is not enough memory.
|
||||
*/
|
||||
uint8_t*
|
||||
mem_HeapAllocBlock( size_t sizeInBytes, /**< size of region to allocate in bytes */
|
||||
mem_HeapAllocBlock( size_t sizeInBytes, /**< size of region to allocate in bytes */
|
||||
mem_HeapAllocTerm_t allocTerm) /**< expected allocation term */
|
||||
{
|
||||
mem_BlockHeader_t *pBlock;
|
||||
@ -186,82 +254,86 @@ mem_HeapAllocBlock( size_t sizeInBytes, /**< size of region to allo
|
||||
mem_CheckHeap();
|
||||
|
||||
if ( allocTerm == MEM_HEAP_ALLOC_SHORT_TERM )
|
||||
{
|
||||
pBlock = mem_Heap.m_pFirstBlock;
|
||||
direction = MEM_DIRECTION_NEXT;
|
||||
} else
|
||||
{
|
||||
pBlock = mem_Heap.m_pLastBlock;
|
||||
direction = MEM_DIRECTION_PREV;
|
||||
}
|
||||
|
||||
/* searching for appropriate block */
|
||||
while ( pBlock != NULL )
|
||||
{
|
||||
if ( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK )
|
||||
{
|
||||
pBlock = mem_Heap.m_pFirstBlock;
|
||||
direction = MEM_DIRECTION_NEXT;
|
||||
if ( mem_get_block_data_space_size( pBlock) >= sizeInBytes )
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
pBlock = mem_Heap.m_pLastBlock;
|
||||
direction = MEM_DIRECTION_PREV;
|
||||
}
|
||||
{
|
||||
JERRY_ASSERT( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK );
|
||||
}
|
||||
|
||||
/* searching for appropriate block */
|
||||
while ( pBlock != NULL )
|
||||
{
|
||||
if ( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK )
|
||||
{
|
||||
if ( mem_GetHeapBlockDataSpaceSizeInBytes( pBlock) >= sizeInBytes )
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
JERRY_ASSERT( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK );
|
||||
}
|
||||
pBlock = pBlock->m_Neighbours[ direction ];
|
||||
}
|
||||
|
||||
pBlock = pBlock->m_Neighbours[ direction ];
|
||||
}
|
||||
if ( pBlock == NULL )
|
||||
{
|
||||
/* not enough free space */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( pBlock == NULL )
|
||||
{
|
||||
/* not enough free space */
|
||||
return NULL;
|
||||
}
|
||||
/* appropriate block found, allocating space */
|
||||
size_t newBlockSizeInChunks = mem_get_block_chunks_count_from_data_size( sizeInBytes);
|
||||
size_t foundBlockSizeInChunks = mem_get_block_chunks_count( pBlock);
|
||||
|
||||
/* appropriate block found, allocating space */
|
||||
size_t newBlockSizeInChunks = mem_GetHeapBlockSizeInChunksFromDataSpaceSizeInBytes( sizeInBytes);
|
||||
size_t foundBlockSizeInChunks = pBlock->m_SizeInChunks;
|
||||
JERRY_ASSERT( newBlockSizeInChunks <= foundBlockSizeInChunks );
|
||||
|
||||
JERRY_ASSERT( newBlockSizeInChunks <= foundBlockSizeInChunks );
|
||||
mem_BlockHeader_t *pPrevBlock = pBlock->m_Neighbours[ MEM_DIRECTION_PREV ];
|
||||
mem_BlockHeader_t *pNextBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ];
|
||||
|
||||
mem_BlockHeader_t *pPrevBlock = pBlock->m_Neighbours[ MEM_DIRECTION_PREV ];
|
||||
mem_BlockHeader_t *pNextBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ];
|
||||
if ( newBlockSizeInChunks < foundBlockSizeInChunks )
|
||||
{
|
||||
mem_HeapStatFreeBlockSplit();
|
||||
|
||||
if ( newBlockSizeInChunks < foundBlockSizeInChunks )
|
||||
{
|
||||
uint8_t *pNewFreeBlockFirstChunk = (uint8_t*) pBlock + newBlockSizeInChunks * MEM_HEAP_CHUNK_SIZE;
|
||||
mem_InitBlockHeader( pNewFreeBlockFirstChunk,
|
||||
foundBlockSizeInChunks - newBlockSizeInChunks,
|
||||
MEM_BLOCK_FREE,
|
||||
pBlock /* there we will place new allocated block */,
|
||||
pNextBlock);
|
||||
|
||||
mem_BlockHeader_t *pNewFreeBlock = (mem_BlockHeader_t*) pNewFreeBlockFirstChunk;
|
||||
|
||||
if ( pNextBlock == NULL )
|
||||
{
|
||||
mem_Heap.m_pLastBlock = pNewFreeBlock;
|
||||
}
|
||||
|
||||
pNextBlock = pNewFreeBlock;
|
||||
}
|
||||
|
||||
mem_InitBlockHeader( (uint8_t*) pBlock,
|
||||
newBlockSizeInChunks,
|
||||
MEM_BLOCK_ALLOCATED,
|
||||
pPrevBlock,
|
||||
uint8_t *pNewFreeBlockFirstChunk = (uint8_t*) pBlock + newBlockSizeInChunks * MEM_HEAP_CHUNK_SIZE;
|
||||
mem_InitBlockHeader(pNewFreeBlockFirstChunk,
|
||||
0,
|
||||
MEM_BLOCK_FREE,
|
||||
pBlock /* there we will place new allocated block */,
|
||||
pNextBlock);
|
||||
|
||||
JERRY_ASSERT( mem_GetHeapBlockDataSpaceSizeInBytes( pBlock) >= sizeInBytes );
|
||||
mem_BlockHeader_t *pNewFreeBlock = (mem_BlockHeader_t*) pNewFreeBlockFirstChunk;
|
||||
|
||||
mem_CheckHeap();
|
||||
if ( pNextBlock == NULL )
|
||||
{
|
||||
mem_Heap.m_pLastBlock = pNewFreeBlock;
|
||||
}
|
||||
|
||||
/* return data space beginning address */
|
||||
uint8_t *pDataSpace = (uint8_t*) (pBlock + 1);
|
||||
JERRY_ASSERT( (uintptr_t) pDataSpace % MEM_ALIGNMENT == 0);
|
||||
pNextBlock = pNewFreeBlock;
|
||||
}
|
||||
|
||||
return pDataSpace;
|
||||
} /* mem_Alloc */
|
||||
mem_InitBlockHeader((uint8_t*) pBlock,
|
||||
sizeInBytes,
|
||||
MEM_BLOCK_ALLOCATED,
|
||||
pPrevBlock,
|
||||
pNextBlock);
|
||||
|
||||
mem_HeapStatAllocBlock( pBlock);
|
||||
|
||||
JERRY_ASSERT( mem_get_block_data_space_size( pBlock) >= sizeInBytes );
|
||||
|
||||
mem_CheckHeap();
|
||||
|
||||
/* return data space beginning address */
|
||||
uint8_t *pDataSpace = (uint8_t*) (pBlock + 1);
|
||||
JERRY_ASSERT( (uintptr_t) pDataSpace % MEM_ALIGNMENT == 0);
|
||||
|
||||
return pDataSpace;
|
||||
} /* mem_HeapAllocBlock */
|
||||
|
||||
/**
|
||||
* Free the memory block.
|
||||
@ -279,49 +351,53 @@ mem_HeapFreeBlock( uint8_t *ptr) /**< pointer to beginning of data space of the
|
||||
mem_BlockHeader_t *pPrevBlock = pBlock->m_Neighbours[ MEM_DIRECTION_PREV ];
|
||||
mem_BlockHeader_t *pNextBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ];
|
||||
|
||||
mem_HeapStatFreeBlock( pBlock);
|
||||
|
||||
/* checking magic nums that are neighbour to data space */
|
||||
JERRY_ASSERT( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK );
|
||||
if ( pNextBlock != NULL )
|
||||
{
|
||||
JERRY_ASSERT( pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK
|
||||
|| pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK );
|
||||
}
|
||||
{
|
||||
JERRY_ASSERT( pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK
|
||||
|| pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK );
|
||||
}
|
||||
|
||||
pBlock->m_MagicNum = MEM_MAGIC_NUM_OF_FREE_BLOCK;
|
||||
|
||||
if ( pNextBlock != NULL
|
||||
&& pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK )
|
||||
&& pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK )
|
||||
{
|
||||
/* merge with the next block */
|
||||
mem_HeapStatFreeBlockMerge();
|
||||
|
||||
pNextBlock = pNextBlock->m_Neighbours[ MEM_DIRECTION_NEXT ];
|
||||
pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock;
|
||||
if ( pNextBlock != NULL )
|
||||
{
|
||||
/* merge with the next block */
|
||||
pBlock->m_SizeInChunks += pNextBlock->m_SizeInChunks;
|
||||
pNextBlock = pNextBlock->m_Neighbours[ MEM_DIRECTION_NEXT ];
|
||||
pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock;
|
||||
if ( pNextBlock != NULL )
|
||||
{
|
||||
pNextBlock->m_Neighbours[ MEM_DIRECTION_PREV ] = pBlock;
|
||||
} else
|
||||
{
|
||||
mem_Heap.m_pLastBlock = pBlock;
|
||||
}
|
||||
pNextBlock->m_Neighbours[ MEM_DIRECTION_PREV ] = pBlock;
|
||||
} else
|
||||
{
|
||||
mem_Heap.m_pLastBlock = pBlock;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pPrevBlock != NULL
|
||||
&& pPrevBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK )
|
||||
&& pPrevBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK )
|
||||
{
|
||||
/* merge with the previous block */
|
||||
mem_HeapStatFreeBlockMerge();
|
||||
|
||||
pPrevBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock;
|
||||
if ( pNextBlock != NULL )
|
||||
{
|
||||
/* merge with the previous block */
|
||||
pPrevBlock->m_SizeInChunks += pBlock->m_SizeInChunks;
|
||||
pPrevBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock;
|
||||
if ( pNextBlock != NULL )
|
||||
{
|
||||
pNextBlock->m_Neighbours[ MEM_DIRECTION_PREV ] = pBlock->m_Neighbours[ MEM_DIRECTION_PREV ];
|
||||
} else
|
||||
{
|
||||
mem_Heap.m_pLastBlock = pPrevBlock;
|
||||
}
|
||||
pNextBlock->m_Neighbours[ MEM_DIRECTION_PREV ] = pBlock->m_Neighbours[ MEM_DIRECTION_PREV ];
|
||||
} else
|
||||
{
|
||||
mem_Heap.m_pLastBlock = pPrevBlock;
|
||||
}
|
||||
}
|
||||
|
||||
mem_CheckHeap();
|
||||
} /* mem_Free */
|
||||
} /* mem_HeapFreeBlock */
|
||||
|
||||
/**
|
||||
* Recommend allocation size based on chunk size.
|
||||
@ -353,28 +429,52 @@ mem_HeapPrint( bool dumpBlockData) /**< print block with data (true)
|
||||
(void*) mem_Heap.m_pLastBlock);
|
||||
|
||||
for ( mem_BlockHeader_t *pBlock = mem_Heap.m_pFirstBlock;
|
||||
pBlock != NULL;
|
||||
pBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] )
|
||||
{
|
||||
libc_printf("Block (%p): magic num=0x%08x, size in chunks=%lu, previous block->%p next block->%p\n",
|
||||
(void*) pBlock,
|
||||
pBlock->m_MagicNum,
|
||||
pBlock->m_SizeInChunks,
|
||||
(void*) pBlock->m_Neighbours[ MEM_DIRECTION_PREV ],
|
||||
(void*) pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ]);
|
||||
pBlock != NULL;
|
||||
pBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] )
|
||||
{
|
||||
libc_printf("Block (%p): magic num=0x%08x, size in chunks=%lu, previous block->%p next block->%p\n",
|
||||
(void*) pBlock,
|
||||
pBlock->m_MagicNum,
|
||||
mem_get_block_chunks_count( pBlock),
|
||||
(void*) pBlock->m_Neighbours[ MEM_DIRECTION_PREV ],
|
||||
(void*) pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ]);
|
||||
|
||||
if ( dumpBlockData )
|
||||
{
|
||||
uint8_t *pBlockData = (uint8_t*) (pBlock + 1);
|
||||
for ( uint32_t offset = 0;
|
||||
offset < mem_GetHeapBlockDataSpaceSizeInBytes( pBlock);
|
||||
offset++ )
|
||||
{
|
||||
libc_printf("%02x ", pBlockData[ offset ]);
|
||||
}
|
||||
libc_printf("\n");
|
||||
}
|
||||
if ( dumpBlockData )
|
||||
{
|
||||
uint8_t *pBlockData = (uint8_t*) (pBlock + 1);
|
||||
for ( uint32_t offset = 0;
|
||||
offset < mem_get_block_data_space_size( pBlock);
|
||||
offset++ )
|
||||
{
|
||||
libc_printf("%02x ", pBlockData[ offset ]);
|
||||
}
|
||||
libc_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MEM_STATS
|
||||
libc_printf("Heap stats:\n");
|
||||
libc_printf(" Size = %lu\n"
|
||||
" Blocks count = %lu\n"
|
||||
" Allocated blocks count = %lu\n"
|
||||
" Allocated chunks count = %lu\n"
|
||||
" Allocated bytes count = %lu\n"
|
||||
" Waste bytes count = %lu\n"
|
||||
" Peak allocated blocks count = %lu\n"
|
||||
" Peak allocated chunks count = %lu\n"
|
||||
" Peak allocated bytes count = %lu\n"
|
||||
" Peak waste bytes count = %lu\n",
|
||||
mem_HeapStats.size,
|
||||
mem_HeapStats.blocks,
|
||||
mem_HeapStats.allocated_blocks,
|
||||
mem_HeapStats.allocated_chunks,
|
||||
mem_HeapStats.allocated_bytes,
|
||||
mem_HeapStats.waste_bytes,
|
||||
mem_HeapStats.peak_allocated_blocks,
|
||||
mem_HeapStats.peak_allocated_chunks,
|
||||
mem_HeapStats.peak_allocated_bytes,
|
||||
mem_HeapStats.peak_waste_bytes);
|
||||
#endif /* MEM_STATS */
|
||||
|
||||
libc_printf("\n");
|
||||
} /* mem_PrintHeap */
|
||||
@ -389,38 +489,141 @@ mem_CheckHeap( void)
|
||||
JERRY_ASSERT( (uint8_t*) mem_Heap.m_pFirstBlock == mem_Heap.m_HeapStart );
|
||||
JERRY_ASSERT( mem_Heap.m_HeapSize % MEM_HEAP_CHUNK_SIZE == 0 );
|
||||
|
||||
size_t chunksCount = 0;
|
||||
bool isLastBlockWasMet = false;
|
||||
for ( mem_BlockHeader_t *pBlock = mem_Heap.m_pFirstBlock;
|
||||
pBlock != NULL;
|
||||
pBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] )
|
||||
pBlock != NULL;
|
||||
pBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] )
|
||||
{
|
||||
JERRY_ASSERT( pBlock != NULL );
|
||||
JERRY_ASSERT( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK
|
||||
|| pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK );
|
||||
|
||||
mem_BlockHeader_t *pNextBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ];
|
||||
if ( pBlock == mem_Heap.m_pLastBlock )
|
||||
{
|
||||
JERRY_ASSERT( pBlock != NULL );
|
||||
JERRY_ASSERT( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK
|
||||
|| pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK );
|
||||
isLastBlockWasMet = true;
|
||||
|
||||
chunksCount += pBlock->m_SizeInChunks;
|
||||
|
||||
mem_BlockHeader_t *pNextBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ];
|
||||
if ( pBlock == mem_Heap.m_pLastBlock )
|
||||
{
|
||||
isLastBlockWasMet = true;
|
||||
|
||||
JERRY_ASSERT( pNextBlock == NULL );
|
||||
JERRY_ASSERT( mem_Heap.m_HeapStart + mem_Heap.m_HeapSize
|
||||
== (uint8_t*) pBlock + pBlock->m_SizeInChunks * MEM_HEAP_CHUNK_SIZE );
|
||||
} else
|
||||
{
|
||||
JERRY_ASSERT( pNextBlock != NULL );
|
||||
JERRY_ASSERT( (uint8_t*) pNextBlock == (uint8_t*) pBlock + pBlock->m_SizeInChunks * MEM_HEAP_CHUNK_SIZE );
|
||||
}
|
||||
JERRY_ASSERT( pNextBlock == NULL );
|
||||
} else
|
||||
{
|
||||
JERRY_ASSERT( pNextBlock != NULL );
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_ASSERT( isLastBlockWasMet );
|
||||
JERRY_ASSERT( chunksCount == mem_Heap.m_HeapSize / MEM_HEAP_CHUNK_SIZE );
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
} /* mem_CheckHeap */
|
||||
|
||||
#ifdef MEM_STATS
|
||||
/**
|
||||
* Get heap memory usage statistics
|
||||
*/
|
||||
void
|
||||
mem_HeapGetStats( mem_HeapStats_t *out_heap_stats_p) /**< out: heap stats */
|
||||
{
|
||||
*out_heap_stats_p = mem_HeapStats;
|
||||
} /* mem_HeapGetStats */
|
||||
|
||||
/**
|
||||
* Initalize heap memory usage statistics account structure
|
||||
*/
|
||||
static void
|
||||
mem_HeapStatInit()
|
||||
{
|
||||
libc_memset( &mem_HeapStats, 0, sizeof (mem_HeapStats));
|
||||
|
||||
mem_HeapStats.size = mem_Heap.m_HeapSize;
|
||||
mem_HeapStats.blocks = 1;
|
||||
} /* mem_InitStats */
|
||||
|
||||
/**
|
||||
* Account block allocation
|
||||
*/
|
||||
static void
|
||||
mem_HeapStatAllocBlock( mem_BlockHeader_t *block_header_p) /**< allocated block */
|
||||
{
|
||||
JERRY_ASSERT( block_header_p->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK );
|
||||
|
||||
const size_t chunks = mem_get_block_chunks_count( block_header_p);
|
||||
const size_t bytes = block_header_p->allocated_bytes;
|
||||
const size_t waste_bytes = chunks * MEM_HEAP_CHUNK_SIZE - bytes;
|
||||
|
||||
mem_HeapStats.allocated_blocks++;
|
||||
mem_HeapStats.allocated_chunks += chunks;
|
||||
mem_HeapStats.allocated_bytes += bytes;
|
||||
mem_HeapStats.waste_bytes += waste_bytes;
|
||||
|
||||
if ( mem_HeapStats.allocated_blocks > mem_HeapStats.peak_allocated_blocks )
|
||||
{
|
||||
mem_HeapStats.peak_allocated_blocks = mem_HeapStats.allocated_blocks;
|
||||
}
|
||||
|
||||
if ( mem_HeapStats.allocated_chunks > mem_HeapStats.peak_allocated_chunks )
|
||||
{
|
||||
mem_HeapStats.peak_allocated_chunks = mem_HeapStats.allocated_chunks;
|
||||
}
|
||||
|
||||
if ( mem_HeapStats.allocated_bytes > mem_HeapStats.peak_allocated_bytes )
|
||||
{
|
||||
mem_HeapStats.peak_allocated_bytes = mem_HeapStats.allocated_bytes;
|
||||
}
|
||||
|
||||
if ( mem_HeapStats.waste_bytes > mem_HeapStats.peak_waste_bytes )
|
||||
{
|
||||
mem_HeapStats.peak_waste_bytes = mem_HeapStats.waste_bytes;
|
||||
}
|
||||
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_blocks <= mem_HeapStats.blocks );
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_bytes <= mem_HeapStats.size );
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_chunks <= mem_HeapStats.size / MEM_HEAP_CHUNK_SIZE );
|
||||
} /* mem_HeapStatAllocBlock */
|
||||
|
||||
/**
|
||||
* Account block freeing
|
||||
*/
|
||||
static void
|
||||
mem_HeapStatFreeBlock( mem_BlockHeader_t *block_header_p) /**< block to be freed */
|
||||
{
|
||||
JERRY_ASSERT( block_header_p->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK );
|
||||
|
||||
const size_t chunks = mem_get_block_chunks_count( block_header_p);
|
||||
const size_t bytes = block_header_p->allocated_bytes;
|
||||
const size_t waste_bytes = chunks * MEM_HEAP_CHUNK_SIZE - bytes;
|
||||
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_blocks <= mem_HeapStats.blocks );
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_bytes <= mem_HeapStats.size );
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_chunks <= mem_HeapStats.size / MEM_HEAP_CHUNK_SIZE );
|
||||
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_blocks >= 1 );
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_chunks >= chunks );
|
||||
JERRY_ASSERT( mem_HeapStats.allocated_bytes >= bytes );
|
||||
JERRY_ASSERT( mem_HeapStats.waste_bytes >= waste_bytes );
|
||||
|
||||
mem_HeapStats.allocated_blocks--;
|
||||
mem_HeapStats.allocated_chunks -= chunks;
|
||||
mem_HeapStats.allocated_bytes -= bytes;
|
||||
mem_HeapStats.waste_bytes -= waste_bytes;
|
||||
} /* mem_HeapStatFreeBlock */
|
||||
|
||||
/**
|
||||
* Account free block split
|
||||
*/
|
||||
static void
|
||||
mem_HeapStatFreeBlockSplit( void)
|
||||
{
|
||||
mem_HeapStats.blocks++;
|
||||
} /* mem_HeapStatFreeBlockSplit */
|
||||
|
||||
/**
|
||||
* Account free block merge
|
||||
*/
|
||||
static void
|
||||
mem_HeapStatFreeBlockMerge( void)
|
||||
{
|
||||
mem_HeapStats.blocks--;
|
||||
} /* mem_HeapStatFreeBlockMerge */
|
||||
#endif /* MEM_STATS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@ -44,6 +44,31 @@ extern void mem_HeapFreeBlock(uint8_t *ptr);
|
||||
extern size_t mem_HeapRecommendAllocationSize(size_t minimumAllocationSize);
|
||||
extern void mem_HeapPrint(bool dumpBlockData);
|
||||
|
||||
#ifdef MEM_STATS
|
||||
/**
|
||||
* Heap memory usage statistics
|
||||
*/
|
||||
typedef struct {
|
||||
size_t size; /**< size */
|
||||
size_t blocks; /**< blocks count */
|
||||
|
||||
size_t allocated_chunks; /**< currently allocated chunks */
|
||||
size_t peak_allocated_chunks; /**< peak allocated chunks */
|
||||
|
||||
size_t allocated_blocks; /**< currently allocated blocks */
|
||||
size_t peak_allocated_blocks; /**< peak allocated blocks */
|
||||
|
||||
size_t allocated_bytes; /**< currently allocated bytes */
|
||||
size_t peak_allocated_bytes; /**< peak allocated bytes */
|
||||
|
||||
size_t waste_bytes; /**< bytes waste due to blocks filled partially
|
||||
and due to block headers */
|
||||
size_t peak_waste_bytes; /**< peak bytes waste */
|
||||
} mem_HeapStats_t;
|
||||
|
||||
extern void mem_HeapGetStats(mem_HeapStats_t *out_heap_stats_p);
|
||||
#endif /* MEM_STATS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#define JERRY_MEM_POOL_INTERNAL
|
||||
|
||||
#include "globals.h"
|
||||
#include "jerry-libc.h"
|
||||
#include "mem-allocator.h"
|
||||
#include "mem-heap.h"
|
||||
#include "mem-pool.h"
|
||||
@ -52,6 +53,25 @@ mem_PoolState_t mem_PoolForPoolHeaders;
|
||||
*/
|
||||
uint8_t *mem_SpaceForPoolForPoolHeaders;
|
||||
|
||||
#ifdef MEM_STATS
|
||||
/**
|
||||
* Pools' memory usage statistics
|
||||
*/
|
||||
mem_PoolsStats_t mem_PoolsStats;
|
||||
|
||||
static void mem_PoolsStatInit( void);
|
||||
static void mem_PoolsStatAllocPool( mem_PoolChunkType_t);
|
||||
static void mem_PoolsStatFreePool( mem_PoolChunkType_t);
|
||||
static void mem_PoolsStatAllocChunk( mem_PoolChunkType_t);
|
||||
static void mem_PoolsStatFreeChunk( mem_PoolChunkType_t);
|
||||
#else /* !MEM_STATS */
|
||||
# define mem_PoolsStatsInit()
|
||||
# define mem_PoolsStatAllocPool()
|
||||
# define mem_PoolsStatsFreePool()
|
||||
# define mem_PoolsStatAllocChunk()
|
||||
# define mem_PoolsStatFreeChunk()
|
||||
#endif /* !MEM_STATS */
|
||||
|
||||
/**
|
||||
* Initialize pool manager
|
||||
*/
|
||||
@ -83,6 +103,8 @@ mem_PoolsInit(void)
|
||||
mem_GetChunkSize( chunkType),
|
||||
mem_SpaceForPoolForPoolHeaders,
|
||||
poolSpaceSize);
|
||||
|
||||
mem_PoolsStatInit();
|
||||
} /* mem_PoolsInit */
|
||||
|
||||
/**
|
||||
@ -138,6 +160,8 @@ mem_PoolsAlloc( mem_PoolChunkType_t chunkType) /**< chunk type */
|
||||
mem_Pools[ chunkType ] = poolState;
|
||||
|
||||
mem_FreeChunksNumber[ chunkType ] += poolState->m_FreeChunksNumber;
|
||||
|
||||
mem_PoolsStatAllocPool( chunkType);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,6 +183,8 @@ mem_PoolsAlloc( mem_PoolChunkType_t chunkType) /**< chunk type */
|
||||
*/
|
||||
mem_FreeChunksNumber[ chunkType ]--;
|
||||
|
||||
mem_PoolsStatAllocChunk( chunkType);
|
||||
|
||||
return mem_PoolAllocChunk( poolState);
|
||||
} /* mem_PoolsAlloc */
|
||||
|
||||
@ -189,6 +215,8 @@ mem_PoolsFree( mem_PoolChunkType_t chunkType, /**< the chunk type */
|
||||
mem_PoolFreeChunk( poolState, pChunk);
|
||||
mem_FreeChunksNumber[ chunkType ]++;
|
||||
|
||||
mem_PoolsStatFreeChunk( chunkType);
|
||||
|
||||
/**
|
||||
* If all chunks of the pool are free, free the pool itself.
|
||||
*/
|
||||
@ -207,9 +235,89 @@ mem_PoolsFree( mem_PoolChunkType_t chunkType, /**< the chunk type */
|
||||
mem_HeapFreeBlock( poolState->m_pPoolStart);
|
||||
|
||||
mem_PoolFreeChunk( &mem_PoolForPoolHeaders, (uint8_t*) poolState);
|
||||
}
|
||||
|
||||
mem_PoolsStatFreePool( chunkType);
|
||||
}
|
||||
} /* mem_PoolsFree */
|
||||
|
||||
#ifdef MEM_STATS
|
||||
/**
|
||||
* Get pools memory usage statistics
|
||||
*/
|
||||
void
|
||||
mem_PoolsGetStats( mem_PoolsStats_t *out_pools_stats_p) /**< out: pools' stats */
|
||||
{
|
||||
JERRY_ASSERT( out_pools_stats_p != NULL );
|
||||
|
||||
*out_pools_stats_p = mem_PoolsStats;
|
||||
} /* mem_PoolsGetStats */
|
||||
|
||||
/**
|
||||
* Initalize pools' memory usage statistics account structure
|
||||
*/
|
||||
static void
|
||||
mem_PoolsStatInit( void)
|
||||
{
|
||||
libc_memset( &mem_PoolsStats, 0, sizeof (mem_PoolsStats));
|
||||
} /* mem_PoolsStatInit */
|
||||
|
||||
/**
|
||||
* Account allocation of a pool
|
||||
*/
|
||||
static void
|
||||
mem_PoolsStatAllocPool( mem_PoolChunkType_t chunkType) /**< chunk type */
|
||||
{
|
||||
mem_PoolsStats.pools_count[ chunkType ]++;
|
||||
mem_PoolsStats.free_chunks[ chunkType ] = mem_FreeChunksNumber[ chunkType ];
|
||||
|
||||
if ( mem_PoolsStats.pools_count[ chunkType ] > mem_PoolsStats.peak_pools_count[ chunkType ] )
|
||||
{
|
||||
mem_PoolsStats.peak_pools_count[ chunkType ] = mem_PoolsStats.pools_count[ chunkType ];
|
||||
}
|
||||
} /* mem_PoolsStatAllocPool */
|
||||
|
||||
/**
|
||||
* Account freeing of a pool
|
||||
*/
|
||||
static void
|
||||
mem_PoolsStatFreePool( mem_PoolChunkType_t chunkType) /**< chunk type */
|
||||
{
|
||||
JERRY_ASSERT( mem_PoolsStats.pools_count[ chunkType ] > 0 );
|
||||
|
||||
mem_PoolsStats.pools_count[ chunkType ]--;
|
||||
mem_PoolsStats.free_chunks[ chunkType ] = mem_FreeChunksNumber[ chunkType ];
|
||||
} /* mem_PoolsStatFreePool */
|
||||
|
||||
/**
|
||||
* Account allocation of chunk in a pool
|
||||
*/
|
||||
static void
|
||||
mem_PoolsStatAllocChunk( mem_PoolChunkType_t chunkType) /**< chunk type */
|
||||
{
|
||||
JERRY_ASSERT( mem_PoolsStats.free_chunks[ chunkType ] > 0 );
|
||||
|
||||
mem_PoolsStats.allocated_chunks[ chunkType ]++;
|
||||
mem_PoolsStats.free_chunks[ chunkType ]--;
|
||||
|
||||
if ( mem_PoolsStats.allocated_chunks[ chunkType ] > mem_PoolsStats.peak_allocated_chunks[ chunkType ] )
|
||||
{
|
||||
mem_PoolsStats.peak_allocated_chunks[ chunkType ] = mem_PoolsStats.allocated_chunks[ chunkType ];
|
||||
}
|
||||
} /* mem_PoolsStatAllocChunk */
|
||||
|
||||
/**
|
||||
* Account freeing of chunk in a pool
|
||||
*/
|
||||
static void
|
||||
mem_PoolsStatFreeChunk( mem_PoolChunkType_t chunkType) /**< chunk type */
|
||||
{
|
||||
JERRY_ASSERT( mem_PoolsStats.allocated_chunks[ chunkType ] > 0 );
|
||||
|
||||
mem_PoolsStats.allocated_chunks[ chunkType ]--;
|
||||
mem_PoolsStats.free_chunks[ chunkType ]++;
|
||||
} /* mem_PoolsStatFreeChunk */
|
||||
#endif /* MEM_STATS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@ -71,6 +71,31 @@ extern void mem_PoolsInit(void);
|
||||
extern uint8_t* mem_PoolsAlloc(mem_PoolChunkType_t chunkType);
|
||||
extern void mem_PoolsFree(mem_PoolChunkType_t chunkType, uint8_t *pChunk);
|
||||
|
||||
#ifdef MEM_STATS
|
||||
/**
|
||||
* Pools' memory usage statistics
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/** pools' count, per type */
|
||||
size_t pools_count[ MEM_POOL_CHUNK_TYPE__COUNT ];
|
||||
|
||||
/** peak pools' count, per type */
|
||||
size_t peak_pools_count[ MEM_POOL_CHUNK_TYPE__COUNT ];
|
||||
|
||||
/** allocated chunks count, per type */
|
||||
size_t allocated_chunks[ MEM_POOL_CHUNK_TYPE__COUNT ];
|
||||
|
||||
/** peak allocated chunks count, per type */
|
||||
size_t peak_allocated_chunks[ MEM_POOL_CHUNK_TYPE__COUNT ];
|
||||
|
||||
/** free chunks count, per type */
|
||||
size_t free_chunks[ MEM_POOL_CHUNK_TYPE__COUNT ];
|
||||
} mem_PoolsStats_t;
|
||||
|
||||
extern void mem_PoolsGetStats( mem_PoolsStats_t *out_pools_stats_p);
|
||||
#endif /* MEM_STATS */
|
||||
|
||||
#endif /* JERRY_MEM_POOLMAN_H */
|
||||
|
||||
/**
|
||||
|
||||
@ -82,5 +82,7 @@ main( int __unused argc,
|
||||
}
|
||||
}
|
||||
|
||||
mem_HeapPrint( false);
|
||||
|
||||
return 0;
|
||||
} /* main */
|
||||
|
||||
@ -93,5 +93,28 @@ main( int __unused argc,
|
||||
}
|
||||
}
|
||||
|
||||
mem_PoolsStats_t stats;
|
||||
mem_PoolsGetStats( &stats);
|
||||
|
||||
libc_printf("Pools stats:\n");
|
||||
for(mem_PoolChunkType_t type = 0;
|
||||
type < MEM_POOL_CHUNK_TYPE__COUNT;
|
||||
type++)
|
||||
{
|
||||
libc_printf(" Chunk size: %u\n"
|
||||
" Pools: %lu\n"
|
||||
" Allocated chunks: %lu\n"
|
||||
" Free chunks: %lu\n"
|
||||
" Peak pools: %lu\n"
|
||||
" Peak allocated chunks: %lu\n",
|
||||
mem_GetChunkSize( type),
|
||||
stats.pools_count[ type ],
|
||||
stats.allocated_chunks[ type ],
|
||||
stats.free_chunks[ type ],
|
||||
stats.peak_pools_count[ type ],
|
||||
stats.peak_allocated_chunks[ type ]);
|
||||
}
|
||||
libc_printf("\n");
|
||||
|
||||
return 0;
|
||||
} /* main */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user