|
|
@ -1,4 +1,4 @@ |
|
|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
|
|
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Purpose:
|
|
|
|
// Purpose:
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -30,27 +30,19 @@ |
|
|
|
|
|
|
|
|
|
|
|
typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... ); |
|
|
|
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 |
|
|
|
class CUtlMemoryPool |
|
|
|
{ |
|
|
|
{ |
|
|
|
public: |
|
|
|
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 |
|
|
|
enum MemoryPoolGrowType_t |
|
|
|
{ |
|
|
|
{ |
|
|
|
GROW_NONE=UTLMEMORYPOOL_GROW_NONE, |
|
|
|
GROW_NONE=0, // Don't allow new blobs.
|
|
|
|
GROW_FAST=UTLMEMORYPOOL_GROW_FAST, |
|
|
|
GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates
|
|
|
|
GROW_SLOW=UTLMEMORYPOOL_GROW_SLOW |
|
|
|
// 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(); |
|
|
|
~CUtlMemoryPool(); |
|
|
|
|
|
|
|
|
|
|
|
void* Alloc(); // Allocate the element size you specified in the constructor.
|
|
|
|
void* Alloc(); // Allocate the element size you specified in the constructor.
|
|
|
@ -66,8 +58,12 @@ public: |
|
|
|
static void SetErrorReportFunc( MemoryPoolReportFunc_t func ); |
|
|
|
static void SetErrorReportFunc( MemoryPoolReportFunc_t func ); |
|
|
|
|
|
|
|
|
|
|
|
// returns number of allocated blocks
|
|
|
|
// returns number of allocated blocks
|
|
|
|
int Count() { return m_BlocksAllocated; } |
|
|
|
int Count() const { return m_BlocksAllocated; } |
|
|
|
int PeakCount() { return m_PeakAlloc; } |
|
|
|
int PeakCount() const { return m_PeakAlloc; } |
|
|
|
|
|
|
|
int BlockSize() const { return m_BlockSize; } |
|
|
|
|
|
|
|
int Size() const; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool IsAllocationWithinPool( void *pMem ) const; |
|
|
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
protected: |
|
|
|
class CBlob |
|
|
|
class CBlob |
|
|
@ -89,14 +85,13 @@ protected: |
|
|
|
|
|
|
|
|
|
|
|
int m_GrowMode; // GROW_ enum.
|
|
|
|
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; |
|
|
|
int m_BlocksAllocated; |
|
|
|
// FIXME: Change m_ppMemBlob into a growable array?
|
|
|
|
|
|
|
|
void *m_pHeadOfFreeList; |
|
|
|
|
|
|
|
int m_PeakAlloc; |
|
|
|
int m_PeakAlloc; |
|
|
|
unsigned short m_nAlignment; |
|
|
|
unsigned short m_nAlignment; |
|
|
|
unsigned short m_NumBlobs; |
|
|
|
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; |
|
|
|
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 could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned
|
|
|
|
CBlob m_BlobHead; |
|
|
|
CBlob m_BlobHead; |
|
|
@ -106,13 +101,12 @@ protected: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Multi-thread/Thread Safe Memory Class
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class CMemoryPoolMT : public CUtlMemoryPool |
|
|
|
class CMemoryPoolMT : public CUtlMemoryPool |
|
|
|
{ |
|
|
|
{ |
|
|
|
public: |
|
|
|
public: |
|
|
|
// MoeMod : add alignment
|
|
|
|
CMemoryPoolMT( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment ) {} |
|
|
|
CMemoryPoolMT(int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); } |
|
|
|
void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); } |
|
|
@ -136,15 +130,8 @@ template< class T > |
|
|
|
class CClassMemoryPool : public CUtlMemoryPool |
|
|
|
class CClassMemoryPool : public CUtlMemoryPool |
|
|
|
{ |
|
|
|
{ |
|
|
|
public: |
|
|
|
public: |
|
|
|
// MoeMod : bad default align here, should be alignof(T)
|
|
|
|
CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) : |
|
|
|
CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = alignof(T) ) : |
|
|
|
CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {} |
|
|
|
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 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
T* Alloc(); |
|
|
|
T* Alloc(); |
|
|
|
T* AllocZero(); |
|
|
|
T* AllocZero(); |
|
|
@ -153,16 +140,15 @@ public: |
|
|
|
void Clear(); |
|
|
|
void Clear(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Specialized pool for aligned data management (e.g., Xbox cubemaps)
|
|
|
|
// Specialized pool for aligned data management (e.g., Xbox textures)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
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 |
|
|
|
class CAlignedMemPool |
|
|
|
{ |
|
|
|
{ |
|
|
|
enum |
|
|
|
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: |
|
|
|
public: |
|
|
@ -174,13 +160,13 @@ public: |
|
|
|
static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight ); |
|
|
|
static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight ); |
|
|
|
void Compact(); |
|
|
|
void Compact(); |
|
|
|
|
|
|
|
|
|
|
|
int NumTotal() { return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } |
|
|
|
int NumTotal() { AUTO_LOCK( m_mutex ); return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } |
|
|
|
int NumAllocated() { return NumTotal() - m_nFree; } |
|
|
|
int NumAllocated() { AUTO_LOCK( m_mutex ); return NumTotal() - m_nFree; } |
|
|
|
int NumFree() { return m_nFree; } |
|
|
|
int NumFree() { AUTO_LOCK( m_mutex ); return m_nFree; } |
|
|
|
|
|
|
|
|
|
|
|
int BytesTotal() { return NumTotal() * BLOCK_SIZE; } |
|
|
|
int BytesTotal() { AUTO_LOCK( m_mutex ); return NumTotal() * BLOCK_SIZE; } |
|
|
|
int BytesAllocated() { return NumAllocated() * BLOCK_SIZE; } |
|
|
|
int BytesAllocated() { AUTO_LOCK( m_mutex ); return NumAllocated() * BLOCK_SIZE; } |
|
|
|
int BytesFree() { return NumFree() * BLOCK_SIZE; } |
|
|
|
int BytesFree() { AUTO_LOCK( m_mutex ); return NumFree() * BLOCK_SIZE; } |
|
|
|
|
|
|
|
|
|
|
|
int ItemSize() { return ITEM_SIZE; } |
|
|
|
int ItemSize() { return ITEM_SIZE; } |
|
|
|
int BlockSize() { return BLOCK_SIZE; } |
|
|
|
int BlockSize() { return BLOCK_SIZE; } |
|
|
@ -197,7 +183,9 @@ private: |
|
|
|
FreeBlock_t * m_pFirstFree; |
|
|
|
FreeBlock_t * m_pFirstFree; |
|
|
|
int m_nFree; |
|
|
|
int m_nFree; |
|
|
|
CAllocator m_Allocator; |
|
|
|
CAllocator m_Allocator; |
|
|
|
float m_TimeLastCompact; |
|
|
|
double m_TimeLastCompact; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CThreadFastMutex m_mutex; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@ -228,7 +216,7 @@ public: |
|
|
|
|
|
|
|
|
|
|
|
void Purge() |
|
|
|
void Purge() |
|
|
|
{ |
|
|
|
{ |
|
|
|
T *p; |
|
|
|
T *p = NULL; |
|
|
|
while ( m_AvailableObjects.PopItem( &p ) ) |
|
|
|
while ( m_AvailableObjects.PopItem( &p ) ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
delete p; |
|
|
|
delete p; |
|
|
@ -237,7 +225,7 @@ public: |
|
|
|
|
|
|
|
|
|
|
|
T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty ) |
|
|
|
T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
T *p; |
|
|
|
T *p = NULL; |
|
|
|
if ( !m_AvailableObjects.PopItem( &p ) ) |
|
|
|
if ( !m_AvailableObjects.PopItem( &p ) ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
p = ( bCreateNewIfEmpty ) ? new T : NULL; |
|
|
|
p = ( bCreateNewIfEmpty ) ? new T : NULL; |
|
|
@ -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 > |
|
|
|
template< class T > |
|
|
@ -263,7 +343,7 @@ inline T* CClassMemoryPool<T>::Alloc() |
|
|
|
T *pRet; |
|
|
|
T *pRet; |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); |
|
|
|
MEM_ALLOC_CREDIT_CLASS(); |
|
|
|
pRet = (T*)CUtlMemoryPool::Alloc(); |
|
|
|
pRet = (T*)CUtlMemoryPool::Alloc(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -280,7 +360,7 @@ inline T* CClassMemoryPool<T>::AllocZero() |
|
|
|
T *pRet; |
|
|
|
T *pRet; |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); |
|
|
|
MEM_ALLOC_CREDIT_CLASS(); |
|
|
|
pRet = (T*)CUtlMemoryPool::AllocZero(); |
|
|
|
pRet = (T*)CUtlMemoryPool::AllocZero(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -305,7 +385,7 @@ inline void CClassMemoryPool<T>::Free(T *pMem) |
|
|
|
template< class T > |
|
|
|
template< class T > |
|
|
|
inline void CClassMemoryPool<T>::Clear() |
|
|
|
inline void CClassMemoryPool<T>::Clear() |
|
|
|
{ |
|
|
|
{ |
|
|
|
CUtlRBTree<void *> freeBlocks; |
|
|
|
CUtlRBTree<void *, int> freeBlocks; |
|
|
|
SetDefLessFunc( freeBlocks ); |
|
|
|
SetDefLessFunc( freeBlocks ); |
|
|
|
|
|
|
|
|
|
|
|
void *pCurFree = m_pHeadOfFreeList; |
|
|
|
void *pCurFree = m_pHeadOfFreeList; |
|
|
@ -317,9 +397,9 @@ inline void CClassMemoryPool<T>::Clear() |
|
|
|
|
|
|
|
|
|
|
|
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) |
|
|
|
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// MoeMod : should realign to real data.
|
|
|
|
int nElements = pCur->m_NumBytes / this->m_BlockSize; |
|
|
|
T *p = (T *)AlignValue( pCur->m_Data, m_nAlignment ); |
|
|
|
T *p = ( T * ) AlignValue( pCur->m_Data, this->m_nAlignment ); |
|
|
|
T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes); |
|
|
|
T *pLimit = p + nElements; |
|
|
|
while ( p < pLimit ) |
|
|
|
while ( p < pLimit ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() ) |
|
|
|
if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() ) |
|
|
@ -334,6 +414,9 @@ inline void CClassMemoryPool<T>::Clear() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Macros that make it simple to make a class use a fixed-size allocator
|
|
|
|
// 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,
|
|
|
|
// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class,
|
|
|
@ -364,7 +447,7 @@ inline void CClassMemoryPool<T>::Clear() |
|
|
|
static CMemoryPoolMT s_Allocator |
|
|
|
static CMemoryPoolMT s_Allocator |
|
|
|
|
|
|
|
|
|
|
|
#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ |
|
|
|
#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
|
|
|
|
// Macros that make it simple to make a class use a fixed-size allocator
|
|
|
@ -385,21 +468,30 @@ inline void CClassMemoryPool<T>::Clear() |
|
|
|
CUtlMemoryPool* _class::s_pAllocator = _allocator |
|
|
|
CUtlMemoryPool* _class::s_pAllocator = _allocator |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD > |
|
|
|
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD > |
|
|
|
inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CAlignedMemPool() |
|
|
|
inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::CAlignedMemPool() |
|
|
|
: m_pFirstFree( 0 ), |
|
|
|
: m_pFirstFree( 0 ), |
|
|
|
m_nFree( 0 ), |
|
|
|
m_nFree( 0 ), |
|
|
|
m_TimeLastCompact( 0 ) |
|
|
|
m_TimeLastCompact( 0 ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); |
|
|
|
// These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks
|
|
|
|
COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); |
|
|
|
// 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 > |
|
|
|
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, COMPACT_THRESHOLD>::Alloc() |
|
|
|
inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Alloc() |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
AUTO_LOCK( m_mutex ); |
|
|
|
|
|
|
|
|
|
|
|
if ( !m_pFirstFree ) |
|
|
|
if ( !m_pFirstFree ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
if ( !GROWMODE && m_Chunks.Count() ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE ); |
|
|
|
FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE ); |
|
|
|
Assert( (unsigned)pNew % ALIGNMENT == 0 ); |
|
|
|
Assert( (unsigned)pNew % ALIGNMENT == 0 ); |
|
|
|
m_Chunks.AddToTail( pNew ); |
|
|
|
m_Chunks.AddToTail( pNew ); |
|
|
@ -420,9 +512,11 @@ inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPA |
|
|
|
return p; |
|
|
|
return p; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD > |
|
|
|
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, COMPACT_THRESHOLD>::Free( void *p ) |
|
|
|
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
|
|
|
|
// Insertion sort to encourage allocation clusters in chunks
|
|
|
|
FreeBlock_t *pFree = ((FreeBlock_t *)p); |
|
|
|
FreeBlock_t *pFree = ((FreeBlock_t *)p); |
|
|
|
FreeBlock_t *pCur = m_pFirstFree; |
|
|
|
FreeBlock_t *pCur = m_pFirstFree; |
|
|
@ -448,9 +542,9 @@ inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPAC |
|
|
|
|
|
|
|
|
|
|
|
if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD ) |
|
|
|
if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
float time = Plat_FloatTime(); |
|
|
|
double time = Plat_FloatTime(); |
|
|
|
float compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; |
|
|
|
double compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; |
|
|
|
if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < Plat_FloatTime() ) |
|
|
|
if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < time ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Compact(); |
|
|
|
Compact(); |
|
|
|
m_TimeLastCompact = time; |
|
|
|
m_TimeLastCompact = time; |
|
|
@ -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 > |
|
|
|
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, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight ) |
|
|
|
inline int __cdecl CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return (int)(((uintp)*ppLeft) - ((uintp)*ppRight)); |
|
|
|
return static_cast<int>( (intp)*ppLeft - (intp)*ppRight ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD > |
|
|
|
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, COMPACT_THRESHOLD>::Compact() |
|
|
|
inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Compact() |
|
|
|
{ |
|
|
|
{ |
|
|
|
FreeBlock_t *pCur = m_pFirstFree; |
|
|
|
FreeBlock_t *pCur = m_pFirstFree; |
|
|
|
FreeBlock_t *pPrev = NULL; |
|
|
|
FreeBlock_t *pPrev = NULL; |
|
|
|