diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /gcsdk/steamextra/tier1/tsmultimempool.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'gcsdk/steamextra/tier1/tsmultimempool.cpp')
| -rw-r--r-- | gcsdk/steamextra/tier1/tsmultimempool.cpp | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/gcsdk/steamextra/tier1/tsmultimempool.cpp b/gcsdk/steamextra/tier1/tsmultimempool.cpp new file mode 100644 index 0000000..86a8b50 --- /dev/null +++ b/gcsdk/steamextra/tier1/tsmultimempool.cpp @@ -0,0 +1,383 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include <stdafx.h> +#include "tier0/t0constants.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static const int k_cubMemBlockPrefixSize = sizeof(uint32); + +#define ALLOCSIZE_TO_LOOKUP( cubAlloc ) ( (cubAlloc - 1) >> 5 ) +#define LOOKUP_TO_ALLOCSIZE( iLookup ) ( (iLookup << 5) + 1 ) + + +//----------------------------------------------------------------------------- +// Purpose: constructor, the sizes in pMemPoolConfig must be in ascending order +//----------------------------------------------------------------------------- +CThreadSafeMultiMemoryPool::CThreadSafeMultiMemoryPool( const MemPoolConfig_t *pMemPoolConfig, int cnMemPoolConfig, int nGrowMode /*= GROW_FAST*/ ) +{ + m_cubReallocedTotal = 0; + m_MapRawAllocation.SetLessFunc( DefLessFunc( void * ) ); + + for ( int iMemPoolConfig = 0; iMemPoolConfig < cnMemPoolConfig; iMemPoolConfig++ ) + { + MemPoolRecord_t memPoolRecord; + // verify that the mem pool sizes are in ascending order + Assert( iMemPoolConfig == 0 || ( iMemPoolConfig > 0 && pMemPoolConfig[ iMemPoolConfig - 1 ].m_cubBlockSize < pMemPoolConfig[ iMemPoolConfig].m_cubBlockSize ) ); + AssertMsg( pMemPoolConfig[ iMemPoolConfig].m_cubBlockSize % 32 == 0, "Mempools sizes must be multiples of 32" ); + // add an int to the block size so we can note the alloc size + memPoolRecord.m_pMemPool = new CThreadSafeMemoryPool( pMemPoolConfig[ iMemPoolConfig ].m_cubBlockSize + k_cubMemBlockPrefixSize, + pMemPoolConfig[ iMemPoolConfig ].m_cubDefaultPoolSize, nGrowMode ); + Assert( memPoolRecord.m_pMemPool ); + memPoolRecord.m_nBlockSize = pMemPoolConfig[ iMemPoolConfig ].m_cubBlockSize; + m_VecMemPool.AddToTail( memPoolRecord ); + + // update the largest blocksize + m_nBlockSizeMax = MAX( m_nBlockSizeMax, memPoolRecord.m_nBlockSize ); + } + + // build the lookup table + int nLookupMax = m_nBlockSizeMax >> 5; + m_VecMemPoolLookup.AddMultipleToTail( nLookupMax ); + for ( int i = 0; i < nLookupMax; i++ ) + { + uint32 cubAllocSize = LOOKUP_TO_ALLOCSIZE( i ); + for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ ) + { + if ( m_VecMemPool[iMemPool].m_nBlockSize >= cubAllocSize ) + { + m_VecMemPoolLookup[i] = &m_VecMemPool[iMemPool]; + break; + } + } + } + +#if defined(_DEBUG) + // validate the lookup table + for ( int i = 1; i < (int)m_nBlockSizeMax; i++ ) + { + for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ ) + { + if ( (int)m_VecMemPool[iMemPool].m_nBlockSize >= i ) + { + AssertMsg( m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP(i)] == &m_VecMemPool[iMemPool], "Invalid mempool block size, can't generate lookup table" ); + break; + } + } + } +#endif // _DEBUG +} + + +//----------------------------------------------------------------------------- +// Purpose: destructor +//----------------------------------------------------------------------------- +CThreadSafeMultiMemoryPool::~CThreadSafeMultiMemoryPool() +{ + AUTO_LOCK( m_mutexRawAllocations ); + + for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool ++ ) + { + delete m_VecMemPool[iMemPool].m_pMemPool; + } + + FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation ) + { + FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Allocates a block of memory at of least nAllocSize bytes +// Input : nAllocSize - number of bytes to alloc +// Output : pointer to memory alloc'd, NULL on error +//----------------------------------------------------------------------------- +void *CThreadSafeMultiMemoryPool::Alloc( uint32 cubAllocSize ) +{ + if ( cubAllocSize == 0 ) + return NULL; + + if ( cubAllocSize <= m_nBlockSizeMax ) + { + MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubAllocSize )]; + void *pvMem = pMemPoolRecord->m_pMemPool->Alloc( cubAllocSize + k_cubMemBlockPrefixSize ); + *(uint32 *)pvMem = cubAllocSize; + return ( (char *)pvMem + k_cubMemBlockPrefixSize ); + } + + + // can't fit in our mem pools, alloc it in our one off buffer + RawAllocation_t rawAllocation; + rawAllocation.m_nBlockSize = cubAllocSize; + rawAllocation.m_pvMem = PvAlloc( cubAllocSize + k_cubMemBlockPrefixSize ); + if ( !rawAllocation.m_pvMem ) + { + return NULL; + } + *(uint32 *)rawAllocation.m_pvMem = rawAllocation.m_nBlockSize; + AUTO_LOCK( m_mutexRawAllocations ); + m_MapRawAllocation.Insert( rawAllocation.m_pvMem, rawAllocation ); + return ( (char *)rawAllocation.m_pvMem + k_cubMemBlockPrefixSize ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Free a previously alloc'd block +// Input : pMem - memory to free +//----------------------------------------------------------------------------- +void CThreadSafeMultiMemoryPool::Free( void *pvMem ) +{ + if ( !pvMem ) + return; + + uint32 cubAllocSize = *( (uint32 *)pvMem - 1 ); + + if ( cubAllocSize <= m_nBlockSizeMax ) + { + MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubAllocSize )]; + pMemPoolRecord->m_pMemPool->Free( (char *)pvMem - k_cubMemBlockPrefixSize, cubAllocSize + k_cubMemBlockPrefixSize ); + return; + } + + AUTO_LOCK( m_mutexRawAllocations ); + + // must have been alloc'd from the raw heap, find it in map + void *pvAllocedMem = (char *)pvMem - k_cubMemBlockPrefixSize; + int iRawAllocation = m_MapRawAllocation.Find( pvAllocedMem ); + if ( m_MapRawAllocation.InvalidIndex() == iRawAllocation ) + { + AssertMsg3( false, "CThreadSafeMultiMemoryPool::Free: raw allocation %p (original alloc: %p, %d bytes) not found in allocation map", + pvMem, pvAllocedMem, cubAllocSize ); + return; + + } + + FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem ); + m_MapRawAllocation.RemoveAt( iRawAllocation); +} + + +//----------------------------------------------------------------------------- +// Purpose: Return the size alloc'd for this block +// Input : pMem - memory to report +// Output : size in bytes of this memory +//----------------------------------------------------------------------------- +int CThreadSafeMultiMemoryPool::CubAllocSize(void *pvMem) +{ + if ( !pvMem ) + { + return -1; + } + + return *(((uint32 *)pvMem) -1); +} + + +//----------------------------------------------------------------------------- +// Purpose: Frees all previously alloc'd memory +//----------------------------------------------------------------------------- +void CThreadSafeMultiMemoryPool::Clear() +{ + AUTO_LOCK( m_mutexRawAllocations ); + + for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ ) + { + m_VecMemPool[iMemPool].m_pMemPool->Clear(); + } + + FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation ) + { + FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem ); + } + m_MapRawAllocation.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Purpose: print to the console info about our storage +//----------------------------------------------------------------------------- +void CThreadSafeMultiMemoryPool::PrintStats() +{ + for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ ) + { + m_VecMemPool[iMemPool].m_pMemPool->PrintStats(); + } + int cubRawBytesAllocd = 0; + AUTO_LOCK( m_mutexRawAllocations ); + FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation ) + { + cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize; + } + Msg( "Raw bytes alloc'd: %s\n", Q_pretifymem( cubRawBytesAllocd, 2, true ) ); + Msg( "Cumulative bytes re-alloced: %s\n", Q_pretifymem( m_cubReallocedTotal, 2, true ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: return the total mem alloced by this pool in MB +//----------------------------------------------------------------------------- +int CThreadSafeMultiMemoryPool::CMBPoolSize() const +{ + uint64 cubRawBytesAllocd = 0; + for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ ) + { + cubRawBytesAllocd += ( m_VecMemPool[iMemPool].m_pMemPool->CubTotalSize() ); + } + AUTO_LOCK( m_mutexRawAllocations ); + FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation ) + { + cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize; + } + + return ( cubRawBytesAllocd / k_nMegabyte ); +} + +//----------------------------------------------------------------------------- +// Purpose: return the total mem alloced by this pool in MB +//----------------------------------------------------------------------------- +int CThreadSafeMultiMemoryPool::CMBPoolSizeInUse() const +{ + uint64 cubRawBytesAllocd = 0; + for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ ) + { + cubRawBytesAllocd += ( m_VecMemPool[iMemPool].m_pMemPool->CubSizeInUse() ); + } + AUTO_LOCK( m_mutexRawAllocations ); + FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation ) + { + cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize; + } + + return ( cubRawBytesAllocd / k_nMegabyte ); +} + + +//----------------------------------------------------------------------------- +// Purpose: return number of mempool blocks alloc'd +//----------------------------------------------------------------------------- +int CThreadSafeMultiMemoryPool::Count() +{ + int cCount = 0; + for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ ) + { + cCount += m_VecMemPool[iMemPool].m_pMemPool->Count(); + } + return cCount; +} + + +//----------------------------------------------------------------------------- +// Purpose: reallocate an existing block of memory to a new size (and copy the data +// Input: pvMem - a pointer to the existing memory +// cubAlloc - number of bytes to alloc +// Output: returns a pointer to the memory allocated (NULL on error) +//----------------------------------------------------------------------------- +void *CThreadSafeMultiMemoryPool::ReAlloc( void *pvMem, uint32 cubAlloc ) +{ + uint32 cubOldAlloc = CubAllocSize(pvMem); + if ( pvMem && cubAlloc <= cubOldAlloc ) + return pvMem; + + if ( cubOldAlloc > m_nBlockSizeMax ) + { + AUTO_LOCK( m_mutexRawAllocations ); + // okay, must have been alloc'd from the raw heap, search for it + void *pvAllocedMem = (char *)pvMem - k_cubMemBlockPrefixSize; + int iRawAllocation = m_MapRawAllocation.Find( pvAllocedMem ); + if ( m_MapRawAllocation.InvalidIndex() == iRawAllocation ) + { + AssertMsg3( false, "CThreadSafeMultiMemoryPool::ReAlloc: raw allocation %p (original alloc: %p, %d bytes) not found in allocation map", + pvMem, pvAllocedMem, cubOldAlloc ); + return NULL; + } + + // realloc the memory + void *pvNewMem = PvRealloc( pvAllocedMem, cubAlloc + k_cubMemBlockPrefixSize ); + if ( !pvNewMem ) + { + m_MapRawAllocation.RemoveAt( iRawAllocation ); + return NULL; + } + + // update our tracking + *(uint32 *)pvNewMem = cubAlloc; + if ( pvAllocedMem == pvNewMem ) + { + // if pointer is the same, use the same map entry with the same key (the pointer given to caller) + m_MapRawAllocation[iRawAllocation].m_pvMem = pvNewMem; + m_MapRawAllocation[iRawAllocation].m_nBlockSize = cubAlloc; + } + else + { + // if pointer changed, need to remove the old entry and re-insert with new key + m_MapRawAllocation.RemoveAt( iRawAllocation ); + RawAllocation_t rawAllocation; + rawAllocation.m_pvMem = pvNewMem; + rawAllocation.m_nBlockSize = cubAlloc; + m_MapRawAllocation.Insert( rawAllocation.m_pvMem, rawAllocation ); + } + return ( (char *)pvNewMem + k_cubMemBlockPrefixSize ); + } + else + { + // see if we can stay in the same block + MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubOldAlloc )]; + if ( cubAlloc <= pMemPoolRecord->m_nBlockSize ) + { + // re-assign the size + *((uint32 *)pvMem - 1) = cubAlloc; + return pvMem; + } + + void *pvNewMem = Alloc( cubAlloc ); + if ( !pvNewMem ) + { + return NULL; + } + m_cubReallocedTotal += cubOldAlloc; + Q_memcpy( pvNewMem, pvMem, cubOldAlloc ); + Free( pvMem ); // now free the old memory buffer we had + return pvNewMem; + } +} + + +#ifdef DBGFLAG_VALIDATE +//----------------------------------------------------------------------------- +// Purpose: Ensure that all of our internal structures are consistent, and +// account for all memory that we've allocated. +// Input: validator - Our global validator object +// pchName - Our name (typically a member var in our container) +//----------------------------------------------------------------------------- +void CThreadSafeMultiMemoryPool::Validate( CValidator &validator, const char *pchName ) +{ + validator.Push( "CThreadSafeMultiMemoryPool", this, pchName ); + + ValidateObj( m_VecMemPool ); + for( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ ) + { + validator.ClaimMemory_Aligned( m_VecMemPool[iMemPool].m_pMemPool ); + m_VecMemPool[iMemPool].m_pMemPool->Validate( validator, "m_VecMemPool[iMemPool].m_pMemPool" ); + } + + AUTO_LOCK( m_mutexRawAllocations ); + ValidateObj( m_MapRawAllocation ); + FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation ) + { + validator.ClaimMemory( m_MapRawAllocation[iRawAllocation].m_pvMem ); + } + + ValidateObj( m_VecMemPoolLookup ); + + validator.Pop(); +} +#endif // DBGFLAG_VALIDATE + |