@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
//========= Copyright Valve Corporation, All rights reserved. ====== ======//
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
@ -30,27 +30,19 @@
@@ -30,27 +30,19 @@
typedef void ( * MemoryPoolReportFunc_t ) ( PRINTF_FORMAT_STRING char const * pMsg , . . . ) ;
// Ways a memory pool can grow when it needs to make a new blob:
enum MemoryPoolGrowType_t
{
UTLMEMORYPOOL_GROW_NONE = 0 , // Don't allow new blobs.
UTLMEMORYPOOL_GROW_FAST = 1 , // New blob size is numElements * (i+1) (ie: the blocks it allocates
// get larger and larger each time it allocates one).
UTLMEMORYPOOL_GROW_SLOW = 2 // New blob size is numElements.
} ;
class CUtlMemoryPool
{
public :
// !KLUDGE! For legacy code support, import the global enum into this scope
// Ways the memory pool can grow when it needs to make a new blob.
enum MemoryPoolGrowType_t
{
GROW_NONE = UTLMEMORYPOOL_GROW_NONE ,
GROW_FAST = UTLMEMORYPOOL_GROW_FAST ,
GROW_SLOW = UTLMEMORYPOOL_GROW_SLOW
GROW_NONE = 0 , // Don't allow new blobs.
GROW_FAST = 1 , // New blob size is numElements * (i+1) (ie: the blocks it allocates
// get larger and larger each time it allocates one).
GROW_SLOW = 2 // New blob size is numElements.
} ;
CUtlMemoryPool ( int blockSize , int numElements , int growMode = UTLMEMORYPOOL_ GROW_FAST, const char * pszAllocOwner = NULL , int nAlignment = 0 ) ;
CUtlMemoryPool ( int blockSize , int numElements , int growMode = GROW_FAST , const char * pszAllocOwner = NULL , int nAlignment = 0 ) ;
~ CUtlMemoryPool ( ) ;
void * Alloc ( ) ; // Allocate the element size you specified in the constructor.
@ -66,8 +58,12 @@ public:
@@ -66,8 +58,12 @@ public:
static void SetErrorReportFunc ( MemoryPoolReportFunc_t func ) ;
// returns number of allocated blocks
int Count ( ) { return m_BlocksAllocated ; }
int PeakCount ( ) { return m_PeakAlloc ; }
int Count ( ) const { return m_BlocksAllocated ; }
int PeakCount ( ) const { return m_PeakAlloc ; }
int BlockSize ( ) const { return m_BlockSize ; }
int Size ( ) const ;
bool IsAllocationWithinPool ( void * pMem ) const ;
protected :
class CBlob
@ -89,14 +85,13 @@ protected:
@@ -89,14 +85,13 @@ protected:
int m_GrowMode ; // GROW_ enum.
// Put m_BlocksAllocated in front of m_pHeadOfFreeList for better
// packing on 64-bit where pointers are 8-byte aligned.
int m_BlocksAllocated ;
// FIXME: Change m_ppMemBlob into a growable array?
void * m_pHeadOfFreeList ;
int m_PeakAlloc ;
unsigned short m_nAlignment ;
unsigned short m_NumBlobs ;
// Group up pointers at the end of the class to avoid padding bloat
// FIXME: Change m_ppMemBlob into a growable array?
void * m_pHeadOfFreeList ;
const char * m_pszAllocOwner ;
// CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned
CBlob m_BlobHead ;
@ -106,13 +101,12 @@ protected:
@@ -106,13 +101,12 @@ protected:
//-----------------------------------------------------------------------------
//
// Multi-thread/Thread Safe Memory Class
//-----------------------------------------------------------------------------
class CMemoryPoolMT : public CUtlMemoryPool
{
public :
// MoeMod : add alignment
CMemoryPoolMT ( int blockSize , int numElements , int growMode = UTLMEMORYPOOL_GROW_FAST , const char * pszAllocOwner = NULL , int nAlignment = 0 ) : CUtlMemoryPool ( blockSize , numElements , growMode , pszAllocOwner , nAlignment ) { }
CMemoryPoolMT ( int blockSize , int numElements , int growMode = GROW_FAST , const char * pszAllocOwner = NULL , int nAlignment = 0 ) : CUtlMemoryPool ( blockSize , numElements , growMode , pszAllocOwner , nAlignment ) { }
void * Alloc ( ) { AUTO_LOCK ( m_mutex ) ; return CUtlMemoryPool : : Alloc ( ) ; }
@ -136,15 +130,8 @@ template< class T >
@@ -136,15 +130,8 @@ template< class T >
class CClassMemoryPool : public CUtlMemoryPool
{
public :
// MoeMod : bad default align here, should be alignof(T)
CClassMemoryPool ( int numElements , int growMode = GROW_FAST , int nAlignment = alignof ( T ) ) :
CUtlMemoryPool ( sizeof ( T ) , numElements , growMode , MEM_ALLOC_CLASSNAME ( T ) , nAlignment ) {
# ifdef PLATFORM_64BITS
COMPILE_TIME_ASSERT ( sizeof ( CUtlMemoryPool ) = = 64 ) ;
# else
COMPILE_TIME_ASSERT ( sizeof ( CUtlMemoryPool ) = = 48 ) ;
# endif
}
CClassMemoryPool ( int numElements , int growMode = GROW_FAST , int nAlignment = 0 ) :
CUtlMemoryPool ( sizeof ( T ) , numElements , growMode , MEM_ALLOC_CLASSNAME ( T ) , nAlignment ) { }
T * Alloc ( ) ;
T * AllocZero ( ) ;
@ -153,16 +140,15 @@ public:
@@ -153,16 +140,15 @@ public:
void Clear ( ) ;
} ;
//-----------------------------------------------------------------------------
// Specialized pool for aligned data management (e.g., Xbox cubemap s)
// Specialized pool for aligned data management (e.g., Xbox texture s)
//-----------------------------------------------------------------------------
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , int COMPACT_THRESHOLD = 4 >
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , bool GROWMODE = false , int COMPACT_THRESHOLD = 4 >
class CAlignedMemPool
{
enum
{
BLOCK_SIZE = ALIGN_VALUE ( ITEM_SIZE , ALIGNMENT ) > 8 ? ALIGN_VALUE ( ITEM_SIZE , ALIGNMENT ) : 8
BLOCK_SIZE = COMPILETIME_MAX ( ALIGN_VALUE ( ITEM_SIZE , ALIGNMENT ) , 8 ) ,
} ;
public :
@ -174,13 +160,13 @@ public:
@@ -174,13 +160,13 @@ public:
static int __cdecl CompareChunk ( void * const * ppLeft , void * const * ppRight ) ;
void Compact ( ) ;
int NumTotal ( ) { return m_Chunks . Count ( ) * ( CHUNK_SIZE / BLOCK_SIZE ) ; }
int NumAllocated ( ) { return NumTotal ( ) - m_nFree ; }
int NumFree ( ) { return m_nFree ; }
int NumTotal ( ) { AUTO_LOCK ( m_mutex ) ; return m_Chunks . Count ( ) * ( CHUNK_SIZE / BLOCK_SIZE ) ; }
int NumAllocated ( ) { AUTO_LOCK ( m_mutex ) ; return NumTotal ( ) - m_nFree ; }
int NumFree ( ) { AUTO_LOCK ( m_mutex ) ; return m_nFree ; }
int BytesTotal ( ) { return NumTotal ( ) * BLOCK_SIZE ; }
int BytesAllocated ( ) { return NumAllocated ( ) * BLOCK_SIZE ; }
int BytesFree ( ) { return NumFree ( ) * BLOCK_SIZE ; }
int BytesTotal ( ) { AUTO_LOCK ( m_mutex ) ; return NumTotal ( ) * BLOCK_SIZE ; }
int BytesAllocated ( ) { AUTO_LOCK ( m_mutex ) ; return NumAllocated ( ) * BLOCK_SIZE ; }
int BytesFree ( ) { AUTO_LOCK ( m_mutex ) ; return NumFree ( ) * BLOCK_SIZE ; }
int ItemSize ( ) { return ITEM_SIZE ; }
int BlockSize ( ) { return BLOCK_SIZE ; }
@ -197,7 +183,9 @@ private:
@@ -197,7 +183,9 @@ private:
FreeBlock_t * m_pFirstFree ;
int m_nFree ;
CAllocator m_Allocator ;
float m_TimeLastCompact ;
double m_TimeLastCompact ;
CThreadFastMutex m_mutex ;
} ;
//-----------------------------------------------------------------------------
@ -228,7 +216,7 @@ public:
@@ -228,7 +216,7 @@ public:
void Purge ( )
{
T * p ;
T * p = NULL ;
while ( m_AvailableObjects . PopItem ( & p ) )
{
delete p ;
@ -237,7 +225,7 @@ public:
@@ -237,7 +225,7 @@ public:
T * GetObject ( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty )
{
T * p ;
T * p = NULL ;
if ( ! m_AvailableObjects . PopItem ( & p ) )
{
p = ( bCreateNewIfEmpty ) ? new T : NULL ;
@ -255,6 +243,98 @@ private:
@@ -255,6 +243,98 @@ private:
} ;
//-----------------------------------------------------------------------------
// Fixed budget pool with overflow to malloc
//-----------------------------------------------------------------------------
template < size_t PROVIDED_ITEM_SIZE , int ITEM_COUNT >
class CFixedBudgetMemoryPool
{
public :
CFixedBudgetMemoryPool ( )
{
m_pBase = m_pLimit = 0 ;
COMPILE_TIME_ASSERT ( ITEM_SIZE % 4 = = 0 ) ;
}
bool Owns ( void * p )
{
return ( p > = m_pBase & & p < m_pLimit ) ;
}
void * Alloc ( )
{
MEM_ALLOC_CREDIT_CLASS ( ) ;
# ifndef USE_MEM_DEBUG
if ( ! m_pBase )
{
LOCAL_THREAD_LOCK ( ) ;
if ( ! m_pBase )
{
byte * pMemory = m_pBase = ( byte * ) malloc ( ITEM_COUNT * ITEM_SIZE ) ;
m_pLimit = m_pBase + ( ITEM_COUNT * ITEM_SIZE ) ;
for ( int i = 0 ; i < ITEM_COUNT ; i + + )
{
m_freeList . Push ( ( TSLNodeBase_t * ) pMemory ) ;
pMemory + = ITEM_SIZE ;
}
}
}
void * p = m_freeList . Pop ( ) ;
if ( p )
return p ;
# endif
return malloc ( ITEM_SIZE ) ;
}
void Free ( void * p )
{
# ifndef USE_MEM_DEBUG
if ( Owns ( p ) )
m_freeList . Push ( ( TSLNodeBase_t * ) p ) ;
else
# endif
free ( p ) ;
}
void Clear ( )
{
# ifndef USE_MEM_DEBUG
if ( m_pBase )
{
free ( m_pBase ) ;
}
m_pBase = m_pLimit = 0 ;
Construct ( & m_freeList ) ;
# endif
}
bool IsEmpty ( )
{
# ifndef USE_MEM_DEBUG
if ( m_pBase & & m_freeList . Count ( ) ! = ITEM_COUNT )
return false ;
# endif
return true ;
}
enum
{
ITEM_SIZE = ALIGN_VALUE ( PROVIDED_ITEM_SIZE , TSLIST_NODE_ALIGNMENT )
} ;
CTSListBase m_freeList ;
byte * m_pBase ;
byte * m_pLimit ;
} ;
# define BIND_TO_FIXED_BUDGET_POOL( poolName ) \
inline void * operator new ( size_t size ) { return poolName . Alloc ( ) ; } \
inline void * operator new ( size_t size , int nBlockUse , const char * pFileName , int nLine ) { return poolName . Alloc ( ) ; } \
inline void operator delete ( void * p ) { poolName . Free ( p ) ; } \
inline void operator delete ( void * p , int nBlockUse , const char * pFileName , int nLine ) { poolName . Free ( p ) ; }
//-----------------------------------------------------------------------------
template < class T >
@ -263,7 +343,7 @@ inline T* CClassMemoryPool<T>::Alloc()
@@ -263,7 +343,7 @@ inline T* CClassMemoryPool<T>::Alloc()
T * pRet ;
{
MEM_ALLOC_CREDIT_ ( MEM_ALLOC_ CLASSNAME ( T ) ) ;
MEM_ALLOC_CREDIT_CLASS ( ) ;
pRet = ( T * ) CUtlMemoryPool : : Alloc ( ) ;
}
@ -280,7 +360,7 @@ inline T* CClassMemoryPool<T>::AllocZero()
@@ -280,7 +360,7 @@ inline T* CClassMemoryPool<T>::AllocZero()
T * pRet ;
{
MEM_ALLOC_CREDIT_ ( MEM_ALLOC_ CLASSNAME ( T ) ) ;
MEM_ALLOC_CREDIT_CLASS ( ) ;
pRet = ( T * ) CUtlMemoryPool : : AllocZero ( ) ;
}
@ -305,7 +385,7 @@ inline void CClassMemoryPool<T>::Free(T *pMem)
@@ -305,7 +385,7 @@ inline void CClassMemoryPool<T>::Free(T *pMem)
template < class T >
inline void CClassMemoryPool < T > : : Clear ( )
{
CUtlRBTree < void * > freeBlocks ;
CUtlRBTree < void * , int > freeBlocks ;
SetDefLessFunc ( freeBlocks ) ;
void * pCurFree = m_pHeadOfFreeList ;
@ -317,9 +397,9 @@ inline void CClassMemoryPool<T>::Clear()
@@ -317,9 +397,9 @@ inline void CClassMemoryPool<T>::Clear()
for ( CBlob * pCur = m_BlobHead . m_pNext ; pCur ! = & m_BlobHead ; pCur = pCur - > m_pNext )
{
// MoeMod : should realign to real data.
T * p = ( T * ) AlignValue ( pCur - > m_Data , m_nAlignment ) ;
T * pLimit = ( T * ) ( pCur - > m_Data + pCur - > m_NumBytes ) ;
int nElements = pCur - > m_NumBytes / this - > m_BlockSize ;
T * p = ( T * ) AlignValue ( pCur - > m_Data , this - > m_nAlignment ) ;
T * pLimit = p + nElements ;
while ( p < pLimit )
{
if ( freeBlocks . Find ( p ) = = freeBlocks . InvalidIndex ( ) )
@ -334,6 +414,9 @@ inline void CClassMemoryPool<T>::Clear()
@@ -334,6 +414,9 @@ inline void CClassMemoryPool<T>::Clear()
}
//-----------------------------------------------------------------------------
// Macros that make it simple to make a class use a fixed-size allocator
// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class,
@ -364,7 +447,7 @@ inline void CClassMemoryPool<T>::Clear()
@@ -364,7 +447,7 @@ inline void CClassMemoryPool<T>::Clear()
static CMemoryPoolMT s_Allocator
# define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \
CMemoryPoolMT _class : : s_Allocator ( sizeof ( _class ) , _initsize , _grow , # _class " pool " , alignof ( _class ) )
CMemoryPoolMT _class : : s_Allocator ( sizeof ( _class ) , _initsize , _grow , # _class " pool " )
//-----------------------------------------------------------------------------
// Macros that make it simple to make a class use a fixed-size allocator
@ -385,21 +468,30 @@ inline void CClassMemoryPool<T>::Clear()
@@ -385,21 +468,30 @@ inline void CClassMemoryPool<T>::Clear()
CUtlMemoryPool * _class : : s_pAllocator = _allocator
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , int COMPACT_THRESHOLD >
inline CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , COMPACT_THRESHOLD > : : CAlignedMemPool ( )
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , bool GROWMODE , int COMPACT_THRESHOLD >
inline CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , GROWMODE , COMPACT_THRESHOLD > : : CAlignedMemPool ( )
: m_pFirstFree ( 0 ) ,
m_nFree ( 0 ) ,
m_TimeLastCompact ( 0 )
{
COMPILE_TIME_ASSERT ( sizeof ( FreeBlock_t ) > = BLOCK_SIZE ) ;
COMPILE_TIME_ASSERT ( ALIGN_VALUE ( sizeof ( FreeBlock_t ) , ALIGNMENT ) = = sizeof ( FreeBlock_t ) ) ;
// These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks
// on MacOS and Linux due to a gcc bug.
{ COMPILE_TIME_ASSERT ( sizeof ( FreeBlock_t ) > = BLOCK_SIZE ) ; }
{ COMPILE_TIME_ASSERT ( ALIGN_VALUE ( sizeof ( FreeBlock_t ) , ALIGNMENT ) = = sizeof ( FreeBlock_t ) ) ; }
}
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , int COMPACT_THRESHOLD >
inline void * CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , COMPACT_THRESHOLD > : : Alloc ( )
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , bool GROWMODE , int COMPACT_THRESHOLD >
inline void * CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , GROWMODE , COMPACT_THRESHOLD > : : Alloc ( )
{
AUTO_LOCK ( m_mutex ) ;
if ( ! m_pFirstFree )
{
if ( ! GROWMODE & & m_Chunks . Count ( ) )
{
return NULL ;
}
FreeBlock_t * pNew = ( FreeBlock_t * ) m_Allocator . Alloc ( CHUNK_SIZE ) ;
Assert ( ( unsigned ) pNew % ALIGNMENT = = 0 ) ;
m_Chunks . AddToTail ( pNew ) ;
@ -420,9 +512,11 @@ inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPA
@@ -420,9 +512,11 @@ inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPA
return p ;
}
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , int COMPACT_THRESHOLD >
inline void CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , COMPACT_THRESHOLD > : : Free ( void * p )
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , bool GROWMODE , int COMPACT_THRESHOLD >
inline void CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , GROWMODE , COMPACT_THRESHOLD > : : Free ( void * p )
{
AUTO_LOCK ( m_mutex ) ;
// Insertion sort to encourage allocation clusters in chunks
FreeBlock_t * pFree = ( ( FreeBlock_t * ) p ) ;
FreeBlock_t * pCur = m_pFirstFree ;
@ -448,9 +542,9 @@ inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPAC
@@ -448,9 +542,9 @@ inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPAC
if ( m_nFree > = ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD )
{
float time = Plat_FloatTime ( ) ;
float compactTime = ( m_nFree > = ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0 ;
if ( m_TimeLastCompact > time | | m_TimeLastCompact + compactTime < Pla t_FloatT ime( ) )
double time = Plat_FloatTime ( ) ;
double compactTime = ( m_nFree > = ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0 ;
if ( m_TimeLastCompact > time | | m_TimeLastCompact + compactTime < time )
{
Compact ( ) ;
m_TimeLastCompact = time ;
@ -458,14 +552,14 @@ inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPAC
@@ -458,14 +552,14 @@ inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPAC
}
}
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , int COMPACT_THRESHOLD >
inline int __cdecl CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , COMPACT_THRESHOLD > : : CompareChunk ( void * const * ppLeft , void * const * ppRight )
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , bool GROWMODE , int COMPACT_THRESHOLD >
inline int __cdecl CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , GROWMODE , COMPACT_THRESHOLD > : : CompareChunk ( void * const * ppLeft , void * const * ppRight )
{
return ( int ) ( ( ( u intp) * ppLeft ) - ( ( u intp) * ppRight ) ) ;
return static_cast < int > ( ( intp ) * ppLeft - ( intp ) * ppRight ) ;
}
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , int COMPACT_THRESHOLD >
inline void CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , COMPACT_THRESHOLD > : : Compact ( )
template < int ITEM_SIZE , int ALIGNMENT , int CHUNK_SIZE , class CAllocator , bool GROWMODE , int COMPACT_THRESHOLD >
inline void CAlignedMemPool < ITEM_SIZE , ALIGNMENT , CHUNK_SIZE , CAllocator , GROWMODE , COMPACT_THRESHOLD > : : Compact ( )
{
FreeBlock_t * pCur = m_pFirstFree ;
FreeBlock_t * pPrev = NULL ;