📄 osal_memory.c
字号:
/*********************************************************************
Filename: OSAL_Memory.c
Revised: $Date: 2006-10-26 11:15:57 -0700 (Thu, 26 Oct 2006) $
Revision: $Revision: 12421 $
Description: OSAL Heap Memory management functions.
Copyright (c) 2006 by Texas Instruments, Inc.
All Rights Reserved. Permission to use, reproduce, copy, prepare
derivative works, modify, distribute, perform, display or sell this
software and/or its documentation for any purpose is prohibited
without the express written consent of Texas Instruments, Inc.
*********************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "ZComDef.h"
#include "OSAL_Memory.h"
#include "OnBoard.h"
#include "hal_assert.h"
#if ( MAXMEMHEAP >= 32768 )
#error MAXMEMHEAP is too big to manage!
#endif
// Minimum wasted bytes to justify splitting a block before allocation.
#if !defined ( OSALMEM_MIN_BLKSZ )
#define OSALMEM_MIN_BLKSZ 4
#endif
/* Profiling memory allocations showed that a significant % of very high
* frequency allocations/frees are for block sizes less than or equal to 16.
*/
#if !defined ( OSALMEM_SMALL_BLKSZ )
#define OSALMEM_SMALL_BLKSZ 16
#endif
#if !defined ( OSALMEM_NODEBUG )
#define OSALMEM_NODEBUG TRUE
#endif
#if !defined ( OSALMEM_PROFILER )
#define OSALMEM_PROFILER FALSE
#endif
#if !defined ( OSALMEM_GUARD )
#define OSALMEM_GUARD TRUE // TBD - Hacky workaround til Bugzilla 1252 is fixed!
#define OSALMEM_READY 0xE2
#endif
#if ( OSALMEM_PROFILER )
#define OSALMEM_INIT 'X'
#define OSALMEM_ALOC 'A'
#define OSALMEM_REIN 'F'
#endif
/*********************************************************************
* MACROS
*/
/*
* The MAC_ASSERT macro is for use during debugging.
* The given expression must evaluate as "true" or else fatal error occurs.
* At that point, the call stack feature of the debugger can pinpoint where
* the problem occurred.
*
* To disable this feature and save code size, the project should define
* OSALMEM_NODEBUG to TRUE.
*/
#if ( OSALMEM_NODEBUG )
#define OSALMEM_ASSERT( expr )
#define OSALMEM_DEBUG( statement )
#else
#define OSALMEM_ASSERT( expr) HAL_ASSERT( expr )
#define OSALMEM_DEBUG( statement) st( statement )
#endif
/*********************************************************************
* TYPEDEFS
*/
typedef uint16 osalMemHdr_t;
/*********************************************************************
* CONSTANTS
*/
#define OSALMEM_IN_USE 0x8000
/* This number sets the size of the small-block bucket. Although profiling
* shows max simultaneous alloc of 16x18, timing without profiling overhead
* shows that the best worst case is achieved with the following.
*/
#define SMALLBLKHEAP 232
// To maintain data alignment of the pointer returned, reserve the greater
// space for the memory block header.
#define HDRSZ ( (sizeof ( halDataAlign_t ) > sizeof( osalMemHdr_t )) ? \
sizeof ( halDataAlign_t ) : sizeof( osalMemHdr_t ) )
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
#if ( OSALMEM_GUARD )
static byte ready = 0;
#endif
static osalMemHdr_t *ff1; // First free block in the small-block bucket.
static osalMemHdr_t *ff2; // First free block after the small-block bucket.
#if ( OSALMEM_METRICS )
static uint16 blkMax; // Max cnt of all blocks ever seen at once.
static uint16 blkCnt; // Current cnt of all blocks.
static uint16 blkFree; // Current cnt of free blocks.
static uint16 memAlo; // Current total memory allocated.
static uint16 memMax; // Max total memory ever allocated at once.
#endif
#if ( OSALMEM_PROFILER )
#define OSALMEM_PROMAX 8
/* The profiling buckets must differ by at least OSALMEM_MIN_BLKSZ; the
* last bucket must equal the max alloc size. Set the bucket sizes to
* whatever sizes necessary to show how your application is using memory.
*/
static uint16 proCnt[OSALMEM_PROMAX] = {
OSALMEM_SMALL_BLKSZ, 48, 112, 176, 192, 224, 256, 65535 };
static uint16 proCur[OSALMEM_PROMAX] = { 0 };
static uint16 proMax[OSALMEM_PROMAX] = { 0 };
static uint16 proTot[OSALMEM_PROMAX] = { 0 };
static uint16 proSmallBlkMiss;
#endif
// Memory Allocation Heap.
#if defined( EXTERNAL_RAM )
static byte *theHeap = (byte *)EXT_RAM_BEG;
#else
static halDataAlign_t _theHeap[ MAXMEMHEAP / sizeof( halDataAlign_t ) ];
static byte *theHeap = (byte *)_theHeap;
#endif
/*********************************************************************
* LOCAL FUNCTIONS
*/
/*********************************************************************
* @fn osal_mem_init
*
* @brief Initialize the heap memory management system.
*
* @param void
*
* @return void
*/
void osal_mem_init( void )
{
osalMemHdr_t *tmp;
#if ( OSALMEM_PROFILER )
osal_memset( theHeap, OSALMEM_INIT, MAXMEMHEAP );
#endif
// Setup a NULL block at the end of the heap for fast comparisons with zero.
tmp = (osalMemHdr_t *)theHeap + (MAXMEMHEAP / HDRSZ) - 1;
*tmp = 0;
// Setup a small-block bucket.
tmp = (osalMemHdr_t *)theHeap;
*tmp = SMALLBLKHEAP;
// Setup the wilderness.
tmp = (osalMemHdr_t *)theHeap + (SMALLBLKHEAP / HDRSZ);
*tmp = ((MAXMEMHEAP / HDRSZ) * HDRSZ) - SMALLBLKHEAP - HDRSZ;
#if ( OSALMEM_GUARD )
ready = OSALMEM_READY;
#endif
// Setup a NULL block that is never freed so that the small-block bucket
// is never coalesced with the wilderness.
ff1 = tmp;
ff2 = osal_mem_alloc( 0 );
ff1 = (osalMemHdr_t *)theHeap;
#if ( OSALMEM_METRICS )
/* Start with the small-block bucket and the wilderness - don't count the
* end-of-heap NULL block nor the end-of-small-block NULL block.
*/
blkCnt = blkFree = 2;
#endif
}
/*********************************************************************
* @fn osal_mem_kick
*
* @brief Kick the ff1 pointer out past the long-lived OSAL Task blocks.
* Invoke this once after all long-lived blocks have been allocated -
* presently at the end of osal_init_system().
*
* @param void
*
* @return void
*/
void osal_mem_kick( void )
{
halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
/* Logic in osal_mem_free() will ratchet ff1 back down to the first free
* block in the small-block bucket.
*/
ff1 = ff2;
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
}
/*********************************************************************
* @fn osal_mem_alloc
*
* @brief Implementation of the allocator functionality.
*
* @param size - number of bytes to allocate from the heap.
*
* @return void * - pointer to the heap allocation; NULL if error or failure.
*/
void *osal_mem_alloc( uint16 size )
{
osalMemHdr_t *prev;
osalMemHdr_t *hdr;
halIntState_t intState;
uint16 tmp;
byte coal = 0;
#if ( OSALMEM_GUARD )
// Try to protect against premature use by HAL / OSAL.
if ( ready != OSALMEM_READY )
{
osal_mem_init();
}
#endif
OSALMEM_ASSERT( size );
size += HDRSZ;
// Calculate required bytes to add to 'size' to align to halDataAlign_t.
if ( sizeof( halDataAlign_t ) == 2 )
{
size += (size & 0x01);
}
else if ( sizeof( halDataAlign_t ) != 1 )
{
const byte mod = size % sizeof( halDataAlign_t );
if ( mod != 0 )
{
size += (sizeof( halDataAlign_t ) - mod);
}
}
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
// Smaller allocations are first attempted in the small-block bucket.
if ( size <= OSALMEM_SMALL_BLKSZ )
{
hdr = ff1;
}
else
{
hdr = ff2;
}
tmp = *hdr;
do
{
if ( tmp & OSALMEM_IN_USE )
{
tmp ^= OSALMEM_IN_USE;
coal = 0;
}
else
{
if ( coal != 0 )
{
#if ( OSALMEM_METRICS )
blkCnt--;
blkFree--;
#endif
*prev += *hdr;
if ( *prev >= size )
{
hdr = prev;
tmp = *hdr;
break;
}
}
else
{
if ( tmp >= size )
{
break;
}
coal = 1;
prev = hdr;
}
}
hdr = (osalMemHdr_t *)((byte *)hdr + tmp);
tmp = *hdr;
if ( tmp == 0 )
{
hdr = NULL;
break;
}
} while ( 1 );
if ( hdr != NULL )
{
tmp -= size;
// Determine whether the threshold for splitting is met.
if ( tmp >= OSALMEM_MIN_BLKSZ )
{
// Split the block before allocating it.
osalMemHdr_t *next = (osalMemHdr_t *)((byte *)hdr + size);
*next = tmp;
*hdr = (size | OSALMEM_IN_USE);
#if ( OSALMEM_METRICS )
blkCnt++;
if ( blkMax < blkCnt )
{
blkMax = blkCnt;
}
memAlo += size;
#endif
}
else
{
#if ( OSALMEM_METRICS )
memAlo += *hdr;
blkFree--;
#endif
*hdr |= OSALMEM_IN_USE;
}
#if ( OSALMEM_METRICS )
if ( memMax < memAlo )
{
memMax = memAlo;
}
#endif
#if ( OSALMEM_PROFILER )
{
byte idx;
size = *hdr ^ OSALMEM_IN_USE;
for ( idx = 0; idx < OSALMEM_PROMAX; idx++ )
{
if ( size <= proCnt[idx] )
{
break;
}
}
proCur[idx]++;
if ( proMax[idx] < proCur[idx] )
{
proMax[idx] = proCur[idx];
}
proTot[idx]++;
}
#endif
hdr++;
#if ( OSALMEM_PROFILER )
osal_memset( (byte *)hdr, OSALMEM_ALOC, (size - HDRSZ) );
/* A small-block could not be allocated in the small-block bucket.
* When this occurs significantly frequently, increase the size of the
* bucket in order to restore better worst case run times. Set the first
* profiling bucket size in proCnt[] to the small-block bucket size and
* divide proSmallBlkMiss by the corresponding proTot[] size to get % miss.
* Best worst case time on TrasmitApp was achieved at a 0-15% miss rate
* during steady state Tx load, 0% during idle and steady state Rx load.
*/
if ( (size <= OSALMEM_SMALL_BLKSZ) && (hdr > ff2) )
{
proSmallBlkMiss++;
}
#endif
}
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
return (void *)hdr;
}
/*********************************************************************
* @fn osal_mem_free
*
* @brief Implementation of the de-allocator functionality.
*
* @param ptr - pointer to the memory to free.
*
* @return void
*/
void osal_mem_free( void *ptr )
{
osalMemHdr_t *currHdr;
halIntState_t intState;
#if ( OSALMEM_GUARD )
// Try to protect against premature use by HAL / OSAL.
if ( ready != OSALMEM_READY )
{
osal_mem_init();
}
#endif
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
OSALMEM_ASSERT( ptr );
currHdr = (osalMemHdr_t *)ptr - 1;
// Has this block already been freed?
OSALMEM_ASSERT( *currHdr & OSALMEM_IN_USE );
*currHdr &= ~OSALMEM_IN_USE;
#if ( OSALMEM_PROFILER )
{
uint16 size = *currHdr;
byte idx;
for ( idx = 0; idx < OSALMEM_PROMAX; idx++ )
{
if ( size <= proCnt[idx] )
{
break;
}
}
proCur[idx]--;
}
#endif
#if ( OSALMEM_METRICS )
memAlo -= *currHdr;
blkFree++;
#endif
if ( ff1 > currHdr )
{
ff1 = currHdr;
}
#if ( OSALMEM_PROFILER )
osal_memset( (byte *)currHdr+HDRSZ, OSALMEM_REIN, (*currHdr - HDRSZ) );
#endif
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
}
#if ( OSALMEM_METRICS )
/*********************************************************************
* @fn osal_heap_block_max
*
* @brief Return the maximum number of blocks ever allocated at once.
*
* @param none
*
* @return Maximum number of blocks ever allocated at once.
*/
uint16 osal_heap_block_max( void )
{
return blkMax;
}
/*********************************************************************
* @fn osal_heap_block_cnt
*
* @brief Return the current number of blocks now allocated.
*
* @param none
*
* @return Current number of blocks now allocated.
*/
uint16 osal_heap_block_cnt( void )
{
return blkCnt;
}
/*********************************************************************
* @fn osal_heap_block_free
*
* @brief Return the current number of free blocks.
*
* @param none
*
* @return Current number of free blocks.
*/
uint16 osal_heap_block_free( void )
{
return blkFree;
}
/*********************************************************************
* @fn osal_heap_mem_used
*
* @brief Return the current number of bytes allocated.
*
* @param none
*
* @return Current number of bytes allocated.
*/
uint16 osal_heap_mem_used( void )
{
return memAlo;
}
#endif
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
/*********************************************************************
* @fn osal_heap_high_water
*
* @brief Return the highest byte ever allocated in the heap.
*
* @param none
*
* @return Highest number of bytes ever used by the stack.
*/
uint16 osal_heap_high_water( void )
{
#if ( OSALMEM_METRICS )
return memMax;
#else
return MAXMEMHEAP;
#endif
}
#endif
/*********************************************************************
*********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -