mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Add CMemStack class
This commit is contained in:
parent
edeb8ea586
commit
3a4a5a08f8
105
r5dev/public/imemalloc.h
Normal file
105
r5dev/public/imemalloc.h
Normal file
@ -0,0 +1,105 @@
|
||||
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======//
|
||||
//
|
||||
// Purpose: This header should never be used directly from leaf code!!!
|
||||
// Instead, just add the file memoverride.cpp into your project and all this
|
||||
// will automagically be used
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TIER0_IMEMALLOC_H
|
||||
#define TIER0_IMEMALLOC_H
|
||||
|
||||
/// This interface class is used to let the mem_dump command retrieve
|
||||
/// information about memory allocations outside of the heap. It is currently
|
||||
/// used by CMemoryStack to report on its allocations.
|
||||
abstract_class IMemoryInfo
|
||||
{
|
||||
public:
|
||||
virtual const char* GetMemoryName() const = 0; // User friendly name for this stack or pool
|
||||
virtual size_t GetAllocatedBytes() const = 0; // Number of bytes currently allocated
|
||||
virtual size_t GetCommittedBytes() const = 0; // Bytes committed -- may be greater than allocated.
|
||||
virtual size_t GetReservedBytes() const = 0; // Bytes reserved -- may be greater than committed.
|
||||
virtual size_t GetHighestBytes() const = 0; // The maximum number of bytes allocated or committed.
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if (defined(_DEBUG) || defined(USE_MEM_DEBUG))
|
||||
struct MemAllocFileLine_t
|
||||
{
|
||||
const char* pszFile;
|
||||
int line;
|
||||
};
|
||||
|
||||
#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) \
|
||||
static CUtlMap<void *, MemAllocFileLine_t, int> s_##tag##Allocs( DefLessFunc( void *) ); \
|
||||
CUtlMap<void *, MemAllocFileLine_t, int> * g_p##tag##Allocs = &s_##tag##Allocs; \
|
||||
static CThreadFastMutex s_##tag##AllocsMutex; \
|
||||
CThreadFastMutex * g_p##tag##AllocsMutex = &s_##tag##AllocsMutex; \
|
||||
const char * g_psz##tag##Alloc = strcpy( (char *)MemAlloc_Alloc( strlen( #tag "Alloc" ) + 1, "intentional leak", 0 ), #tag "Alloc" );
|
||||
|
||||
#define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag ) \
|
||||
extern CUtlMap<void *, MemAllocFileLine_t, int> * g_p##tag##Allocs; \
|
||||
extern CThreadFastMutex *g_p##tag##AllocsMutex; \
|
||||
extern const char * g_psz##tag##Alloc;
|
||||
|
||||
#define MemAlloc_RegisterExternalAllocation( tag, p, size ) \
|
||||
if ( !p ) \
|
||||
; \
|
||||
else \
|
||||
{ \
|
||||
AUTO_LOCK_FM( *g_p##tag##AllocsMutex ); \
|
||||
MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \
|
||||
g_pMemAlloc->GetActualDbgInfo( fileLine.pszFile, fileLine.line ); \
|
||||
if ( fileLine.pszFile != g_psz##tag##Alloc ) \
|
||||
{ \
|
||||
g_p##tag##Allocs->Insert( p, fileLine ); \
|
||||
} \
|
||||
\
|
||||
MemAlloc_RegisterAllocation( fileLine.pszFile, fileLine.line, size, size, 0); \
|
||||
}
|
||||
|
||||
#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) \
|
||||
if ( !p ) \
|
||||
; \
|
||||
else \
|
||||
{ \
|
||||
AUTO_LOCK_FM( *g_p##tag##AllocsMutex ); \
|
||||
MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \
|
||||
CUtlMap<void *, MemAllocFileLine_t, int>::IndexType_t iRecordedFileLine = g_p##tag##Allocs->Find( p ); \
|
||||
if ( iRecordedFileLine != g_p##tag##Allocs->InvalidIndex() ) \
|
||||
{ \
|
||||
fileLine = (*g_p##tag##Allocs)[iRecordedFileLine]; \
|
||||
g_p##tag##Allocs->RemoveAt( iRecordedFileLine ); \
|
||||
} \
|
||||
\
|
||||
MemAlloc_RegisterDeallocation( fileLine.pszFile, fileLine.line, size, size, 0); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag )
|
||||
#define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag )
|
||||
#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0)
|
||||
#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if (defined(_DEBUG) || defined(USE_MEM_DEBUG))
|
||||
#define MEM_ALLOC_CREDIT_(tag) CMemAllocAttributeAlloction memAllocAttributeAlloction( tag, __LINE__ )
|
||||
#define MemAlloc_PushAllocDbgInfo( pszFile, line ) g_pMemAlloc->PushAllocDbgInfo( pszFile, line )
|
||||
#define MemAlloc_PopAllocDbgInfo() g_pMemAlloc->PopAllocDbgInfo()
|
||||
#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime )
|
||||
#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime )
|
||||
#else
|
||||
#define MEM_ALLOC_CREDIT_(tag) ((void)0)
|
||||
#define MemAlloc_PushAllocDbgInfo( pszFile, line ) ((void)0)
|
||||
#define MemAlloc_PopAllocDbgInfo() ((void)0)
|
||||
#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
|
||||
#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
|
||||
#endif
|
||||
|
||||
#endif /* TIER0_MEMALLOC_H */
|
@ -217,6 +217,12 @@ void Swap(T& a, T& b)
|
||||
b = temp;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T AlignValue(T val, uintptr_t alignment)
|
||||
{
|
||||
return (T)(((uintp)val + alignment - 1) & ~(alignment - 1));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val)))
|
||||
|
488
r5dev/tier1/memstack.cpp
Normal file
488
r5dev/tier1/memstack.cpp
Normal file
@ -0,0 +1,488 @@
|
||||
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "core/stdafx.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier0/memstd.h"
|
||||
#include "memstack.h"
|
||||
#include "utlmap.h"
|
||||
//#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4073)
|
||||
#pragma init_seg(lib)
|
||||
#endif
|
||||
|
||||
#define VA_COMMIT_FLAGS MEM_COMMIT
|
||||
#define VA_RESERVE_FLAGS MEM_RESERVE
|
||||
|
||||
static volatile bool bSpewAllocations = false; // TODO: Register CMemoryStacks with g_pMemAlloc, so it can spew a summary
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMemoryStack);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PrintStatus( void* p )
|
||||
{
|
||||
CMemoryStack* pMemoryStack = (CMemoryStack*)p;
|
||||
|
||||
pMemoryStack->PrintContents();
|
||||
}
|
||||
|
||||
CMemoryStack::CMemoryStack()
|
||||
: m_pNextAlloc( NULL )
|
||||
, m_pCommitLimit( NULL )
|
||||
, m_pAllocLimit( NULL )
|
||||
, m_pHighestAllocLimit( NULL )
|
||||
, m_pBase( NULL )
|
||||
, m_bRegisteredAllocation( false )
|
||||
, m_maxSize( 0 )
|
||||
, m_alignment( 16 )
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
, m_commitIncrement( 0 )
|
||||
, m_minCommit( 0 )
|
||||
#ifdef _PS3
|
||||
, m_pVirtualMemorySection( NULL )
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
AddMemoryInfoCallback( this );
|
||||
m_pszAllocOwner = strdup( "CMemoryStack unattributed" );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
CMemoryStack::~CMemoryStack()
|
||||
{
|
||||
if ( m_pBase )
|
||||
Term();
|
||||
|
||||
RemoveMemoryInfoCallback( this );
|
||||
free( m_pszAllocOwner );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
bool CMemoryStack::Init( const char *pszAllocOwner, unsigned maxSize, unsigned commitIncrement, unsigned initialCommit, unsigned alignment )
|
||||
{
|
||||
Assert( !m_pBase );
|
||||
|
||||
m_bPhysical = false;
|
||||
|
||||
m_maxSize = maxSize;
|
||||
m_alignment = AlignValue( alignment, 4 );
|
||||
|
||||
Assert( m_alignment == alignment );
|
||||
Assert( m_maxSize > 0 );
|
||||
|
||||
SetAllocOwner( pszAllocOwner );
|
||||
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
|
||||
#ifdef _PS3
|
||||
// Memory can only be committed in page-size increments on PS3
|
||||
static const unsigned PS3_PAGE_SIZE = 64*1024;
|
||||
if ( commitSize < PS3_PAGE_SIZE )
|
||||
commitSize = PS3_PAGE_SIZE;
|
||||
#endif
|
||||
|
||||
if ( commitIncrement != 0 )
|
||||
{
|
||||
m_commitIncrement = commitIncrement;
|
||||
}
|
||||
|
||||
unsigned pageSize;
|
||||
|
||||
#ifdef _PS3
|
||||
pageSize = PS3_PAGE_SIZE;
|
||||
#elif defined( _X360 )
|
||||
pageSize = 64 * 1024;
|
||||
#else
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo( &sysInfo );
|
||||
Assert( !( sysInfo.dwPageSize & (sysInfo.dwPageSize-1)) );
|
||||
pageSize = sysInfo.dwPageSize;
|
||||
#endif
|
||||
|
||||
if ( m_commitIncrement == 0 )
|
||||
{
|
||||
m_commitIncrement = pageSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_commitIncrement = AlignValue( m_commitIncrement, pageSize );
|
||||
}
|
||||
|
||||
m_maxSize = AlignValue( m_maxSize, m_commitIncrement );
|
||||
|
||||
Assert( m_maxSize % pageSize == 0 && m_commitIncrement % pageSize == 0 && m_commitIncrement <= m_maxSize );
|
||||
|
||||
#ifdef _WIN32
|
||||
m_pBase = (unsigned char *)VirtualAlloc( NULL, m_maxSize, VA_RESERVE_FLAGS, PAGE_NOACCESS );
|
||||
#else
|
||||
m_pVirtualMemorySection = g_pMemAlloc->AllocateVirtualMemorySection( m_maxSize );
|
||||
if ( !m_pVirtualMemorySection )
|
||||
{
|
||||
Warning( "AllocateVirtualMemorySection failed( size=%d )\n", m_maxSize );
|
||||
Assert( 0 );
|
||||
m_pBase = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pBase = ( byte* ) m_pVirtualMemorySection->GetBaseAddress();
|
||||
}
|
||||
#endif
|
||||
if ( !m_pBase )
|
||||
{
|
||||
#if !defined( NO_MALLOC_OVERRIDE )
|
||||
g_pMemAlloc->OutOfMemory();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
m_pCommitLimit = m_pNextAlloc = m_pBase;
|
||||
|
||||
if ( initialCommit )
|
||||
{
|
||||
initialCommit = AlignValue( initialCommit, m_commitIncrement );
|
||||
Assert( initialCommit <= m_maxSize );
|
||||
bool bInitialCommitSucceeded = false;
|
||||
#ifdef _WIN32
|
||||
bInitialCommitSucceeded = !!VirtualAlloc( m_pCommitLimit, initialCommit, VA_COMMIT_FLAGS, PAGE_READWRITE );
|
||||
#else
|
||||
m_pVirtualMemorySection->CommitPages( m_pCommitLimit, initialCommit );
|
||||
bInitialCommitSucceeded = true;
|
||||
#endif
|
||||
if ( !bInitialCommitSucceeded )
|
||||
{
|
||||
#if !defined( NO_MALLOC_OVERRIDE )
|
||||
g_pMemAlloc->OutOfMemory( initialCommit );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
m_minCommit = initialCommit;
|
||||
m_pCommitLimit += initialCommit;
|
||||
RegisterAllocation();
|
||||
}
|
||||
|
||||
#else
|
||||
m_pBase = (byte*)MemAlloc_AllocAligned( m_maxSize, alignment ? alignment : 1 );
|
||||
m_pNextAlloc = m_pBase;
|
||||
m_pCommitLimit = m_pBase + m_maxSize;
|
||||
#endif
|
||||
|
||||
m_pHighestAllocLimit = m_pNextAlloc;
|
||||
|
||||
m_pAllocLimit = m_pBase + m_maxSize;
|
||||
|
||||
return ( m_pBase != NULL );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
#ifdef _GAMECONSOLE
|
||||
bool CMemoryStack::InitPhysical( const char *pszAllocOwner, uint size, uint nBaseAddrAlignment, uint alignment, uint32 nFlags )
|
||||
{
|
||||
m_bPhysical = true;
|
||||
|
||||
m_maxSize = m_commitIncrement = size;
|
||||
m_alignment = AlignValue( alignment, 4 );
|
||||
|
||||
SetAllocOwner( pszAllocOwner );
|
||||
|
||||
#ifdef _X360
|
||||
int flags = PAGE_READWRITE | nFlags;
|
||||
if ( size >= 16*1024*1024 )
|
||||
{
|
||||
flags |= MEM_16MB_PAGES;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags |= MEM_LARGE_PAGES;
|
||||
}
|
||||
m_pBase = (unsigned char *)XPhysicalAlloc( m_maxSize, MAXULONG_PTR, nBaseAddrAlignment, flags );
|
||||
#elif defined (_PS3)
|
||||
m_pBase = (byte*)nFlags;
|
||||
m_pBase = (byte*)AlignValue( (uintp)m_pBase, m_alignment );
|
||||
#else
|
||||
#pragma error
|
||||
#endif
|
||||
|
||||
Assert( m_pBase );
|
||||
m_pNextAlloc = m_pBase;
|
||||
m_pCommitLimit = m_pBase + m_maxSize;
|
||||
m_pAllocLimit = m_pBase + m_maxSize;
|
||||
m_pHighestAllocLimit = m_pNextAlloc;
|
||||
|
||||
RegisterAllocation();
|
||||
return ( m_pBase != NULL );
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::Term()
|
||||
{
|
||||
FreeAll();
|
||||
if ( m_pBase )
|
||||
{
|
||||
#ifdef _GAMECONSOLE
|
||||
if ( m_bPhysical )
|
||||
{
|
||||
#if defined( _X360 )
|
||||
XPhysicalFree( m_pBase );
|
||||
#elif defined( _PS3 )
|
||||
#else
|
||||
#pragma error
|
||||
#endif
|
||||
m_pCommitLimit = m_pBase = NULL;
|
||||
m_maxSize = 0;
|
||||
RegisterDeallocation(true);
|
||||
m_bPhysical = false;
|
||||
return;
|
||||
}
|
||||
#endif // _GAMECONSOLE
|
||||
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
#if defined(_WIN32)
|
||||
VirtualFree( m_pBase, 0, MEM_RELEASE );
|
||||
#else
|
||||
m_pVirtualMemorySection->Release();
|
||||
m_pVirtualMemorySection = NULL;
|
||||
#endif
|
||||
#else
|
||||
MemAlloc_FreeAligned( m_pBase );
|
||||
#endif
|
||||
m_pBase = NULL;
|
||||
// Zero these variables to avoid getting misleading mem_dump
|
||||
// results when m_pBase is NULL.
|
||||
m_pNextAlloc = NULL;
|
||||
m_pCommitLimit = NULL;
|
||||
m_pHighestAllocLimit = NULL;
|
||||
m_maxSize = 0;
|
||||
RegisterDeallocation(true);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
int CMemoryStack::GetSize() const
|
||||
{
|
||||
if ( m_bPhysical )
|
||||
return m_maxSize;
|
||||
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
return m_pCommitLimit - m_pBase;
|
||||
#else
|
||||
return m_maxSize;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
bool CMemoryStack::CommitTo( byte *pNextAlloc ) RESTRICT
|
||||
{
|
||||
if ( m_bPhysical )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
unsigned char * pNewCommitLimit = AlignValue( pNextAlloc, m_commitIncrement );
|
||||
ptrdiff_t commitIncrement = pNewCommitLimit - m_pCommitLimit;
|
||||
|
||||
if( m_pCommitLimit + commitIncrement > m_pAllocLimit )
|
||||
{
|
||||
#if !defined( NO_MALLOC_OVERRIDE )
|
||||
g_pMemAlloc->OutOfMemory( commitIncrement );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( pNewCommitLimit > m_pCommitLimit )
|
||||
{
|
||||
RegisterDeallocation(false);
|
||||
bool bAllocationSucceeded = false;
|
||||
#ifdef _WIN32
|
||||
bAllocationSucceeded = !!VirtualAlloc( m_pCommitLimit, commitIncrement, VA_COMMIT_FLAGS, PAGE_READWRITE );
|
||||
#else
|
||||
bAllocationSucceeded = m_pVirtualMemorySection->CommitPages( m_pCommitLimit, commitIncrement );
|
||||
#endif
|
||||
if ( !bAllocationSucceeded )
|
||||
{
|
||||
#if !defined( NO_MALLOC_OVERRIDE )
|
||||
g_pMemAlloc->OutOfMemory( commitIncrement );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
m_pCommitLimit = pNewCommitLimit;
|
||||
|
||||
RegisterAllocation();
|
||||
}
|
||||
else if ( pNewCommitLimit < m_pCommitLimit )
|
||||
{
|
||||
if ( m_pNextAlloc > pNewCommitLimit )
|
||||
{
|
||||
Warning( eDLL_T::COMMON, "ATTEMPTED TO DECOMMIT OWNED MEMORY STACK SPACE\n" );
|
||||
pNewCommitLimit = AlignValue( m_pNextAlloc, m_commitIncrement );
|
||||
}
|
||||
|
||||
if ( pNewCommitLimit < m_pCommitLimit )
|
||||
{
|
||||
RegisterDeallocation(false);
|
||||
ptrdiff_t decommitIncrement = m_pCommitLimit - pNewCommitLimit;
|
||||
#ifdef _WIN32
|
||||
VirtualFree( pNewCommitLimit, decommitIncrement, MEM_DECOMMIT );
|
||||
#else
|
||||
m_pVirtualMemorySection->DecommitPages( pNewCommitLimit, decommitIncrement );
|
||||
#endif
|
||||
m_pCommitLimit = pNewCommitLimit;
|
||||
RegisterAllocation();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Identify the owner of this memory stack's memory
|
||||
void CMemoryStack::SetAllocOwner( const char *pszAllocOwner )
|
||||
{
|
||||
if ( !pszAllocOwner || !Q_strcmp( m_pszAllocOwner, pszAllocOwner ) )
|
||||
return;
|
||||
free( m_pszAllocOwner );
|
||||
m_pszAllocOwner = strdup( pszAllocOwner );
|
||||
}
|
||||
|
||||
void CMemoryStack::RegisterAllocation()
|
||||
{
|
||||
// 'physical' allocations on PS3 come from RSX local memory, so we don't count them here:
|
||||
if ( IsPS3() && m_bPhysical )
|
||||
return;
|
||||
|
||||
if ( GetSize() )
|
||||
{
|
||||
if ( m_bRegisteredAllocation )
|
||||
Warning( eDLL_T::COMMON, "CMemoryStack: ERROR - mismatched RegisterAllocation/RegisterDeallocation!\n" );
|
||||
|
||||
// NOTE: we deliberately don't use MemAlloc_RegisterExternalAllocation. CMemoryStack needs to bypass 'GetActualDbgInfo'
|
||||
// due to the way it allocates memory: there's just one representative memory address (m_pBase), it grows at unpredictable
|
||||
// times (in CommitTo, not every Alloc call) and it is freed en-masse (instead of freeing each individual allocation).
|
||||
MemAlloc_RegisterAllocation( m_pszAllocOwner, 0, GetSize(), GetSize(), 0 );
|
||||
}
|
||||
m_bRegisteredAllocation = true;
|
||||
|
||||
// Temp memorystack spew: very useful when we crash out of memory
|
||||
if ( IsGameConsole() && bSpewAllocations ) DevMsg( eDLL_T::COMMON, "CMemoryStack: %4.1fMB (%s)\n", GetSize()/(float)(1024*1024), m_pszAllocOwner );
|
||||
}
|
||||
|
||||
void CMemoryStack::RegisterDeallocation( bool bShouldSpewSize )
|
||||
{
|
||||
// 'physical' allocations on PS3 come from RSX local memory, so we don't count them here:
|
||||
if ( IsPS3() && m_bPhysical )
|
||||
return;
|
||||
|
||||
if ( GetSize() )
|
||||
{
|
||||
if ( !m_bRegisteredAllocation )
|
||||
Warning( eDLL_T::COMMON, "CMemoryStack: ERROR - mismatched RegisterAllocation/RegisterDeallocation!\n" );
|
||||
MemAlloc_RegisterDeallocation( m_pszAllocOwner, 0, GetSize(), GetSize(), 0 );
|
||||
}
|
||||
m_bRegisteredAllocation = false;
|
||||
|
||||
// Temp memorystack spew: very useful when we crash out of memory
|
||||
if ( bShouldSpewSize && IsGameConsole() && bSpewAllocations ) DevMsg( eDLL_T::COMMON, "CMemoryStack: %4.1fMB (%s)\n", GetSize()/(float)(1024*1024), m_pszAllocOwner );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit )
|
||||
{
|
||||
mark = AlignValue( mark, m_alignment );
|
||||
byte *pAllocPoint = m_pBase + mark;
|
||||
|
||||
Assert( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc );
|
||||
if ( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc )
|
||||
{
|
||||
m_pNextAlloc = pAllocPoint;
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
if ( bDecommit && !m_bPhysical )
|
||||
{
|
||||
CommitTo( MAX( m_pNextAlloc, (m_pBase + m_minCommit) ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::FreeAll( bool bDecommit )
|
||||
{
|
||||
if ( m_pBase && ( m_pBase < m_pCommitLimit ) )
|
||||
{
|
||||
FreeToAllocPoint( 0, bDecommit );
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::Access( void **ppRegion, unsigned *pBytes )
|
||||
{
|
||||
*ppRegion = m_pBase;
|
||||
*pBytes = ( m_pNextAlloc - m_pBase);
|
||||
}
|
||||
|
||||
const char* CMemoryStack::GetMemoryName() const
|
||||
{
|
||||
return m_pszAllocOwner;
|
||||
}
|
||||
|
||||
size_t CMemoryStack::GetAllocatedBytes() const
|
||||
{
|
||||
return GetUsed();
|
||||
}
|
||||
|
||||
size_t CMemoryStack::GetCommittedBytes() const
|
||||
{
|
||||
return GetSize();
|
||||
}
|
||||
|
||||
size_t CMemoryStack::GetReservedBytes() const
|
||||
{
|
||||
return GetMaxSize();
|
||||
}
|
||||
|
||||
//size_t CMemoryStack::GetHighestBytes() const
|
||||
//{
|
||||
// size_t highest = m_pHighestAllocLimit - m_pBase;
|
||||
// return highest;
|
||||
//}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
//void CMemoryStack::PrintContents() const
|
||||
//{
|
||||
// size_t highest = m_pHighestAllocLimit - m_pBase;
|
||||
// MEMORY_BASIC_INFORMATION info;
|
||||
// char moduleName[260];
|
||||
// strcpy( moduleName, "unknown module" );
|
||||
// // Because this code is statically linked into each DLL, this function and the PrintStatus
|
||||
// // function will be in the DLL that constructed the CMemoryStack object. We can then
|
||||
// // retrieve the DLL name to give slightly more verbose memory dumps.
|
||||
// if ( VirtualQuery( &PrintStatus, &info, sizeof( info ) ) == sizeof( info ) )
|
||||
// {
|
||||
// GetModuleFileNameA( (HMODULE) info.AllocationBase, moduleName, _countof( moduleName ) );
|
||||
// moduleName[ _countof( moduleName )-1 ] = 0;
|
||||
// }
|
||||
// DevMsg( eDLL_T::COMMON, "CMemoryStack %s in %s\n", m_pszAllocOwner, moduleName );
|
||||
// DevMsg( eDLL_T::COMMON, " Total used memory: %d KB\n", GetUsed() / 1024 );
|
||||
// DevMsg( eDLL_T::COMMON, " Total committed memory: %d KB\n", GetSize() / 1024 );
|
||||
// DevMsg( eDLL_T::COMMON, " Max committed memory: %u KB out of %d KB\n", (unsigned)highest / 1024, GetMaxSize() / 1024 );
|
||||
//}
|
244
r5dev/tier1/memstack.h
Normal file
244
r5dev/tier1/memstack.h
Normal file
@ -0,0 +1,244 @@
|
||||
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: A fast stack memory allocator that uses virtual memory if available
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef MEMSTACK_H
|
||||
#define MEMSTACK_H
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier1/utlvector.h"
|
||||
#include "public/imemalloc.h"
|
||||
|
||||
#if defined( _WIN32 ) || defined( _PS3 )
|
||||
#define MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
typedef unsigned MemoryStackMark_t;
|
||||
|
||||
class CMemoryStack : private IMemoryInfo
|
||||
{
|
||||
public:
|
||||
CMemoryStack();
|
||||
~CMemoryStack();
|
||||
|
||||
bool Init( const char *pszAllocOwner, unsigned maxSize = 0, unsigned commitIncrement = 0, unsigned initialCommit = 0, unsigned alignment = 16 );
|
||||
#ifdef _GAMECONSOLE
|
||||
bool InitPhysical( const char *pszAllocOwner, uint size, uint nBaseAddrAlignment, uint alignment = 16, uint32 nAdditionalFlags = 0 );
|
||||
#endif
|
||||
void Term();
|
||||
|
||||
int GetSize() const;
|
||||
int GetMaxSize() const ;
|
||||
int GetUsed() const;
|
||||
|
||||
void *Alloc( unsigned bytes, bool bClear = false ) RESTRICT;
|
||||
|
||||
MemoryStackMark_t GetCurrentAllocPoint() const;
|
||||
void FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit = true );
|
||||
void FreeAll( bool bDecommit = true );
|
||||
|
||||
void Access( void **ppRegion, unsigned *pBytes );
|
||||
|
||||
void PrintContents() const;
|
||||
|
||||
void *GetBase();
|
||||
const void *GetBase() const { return const_cast<CMemoryStack *>(this)->GetBase(); }
|
||||
|
||||
bool CommitSize( int nBytes );
|
||||
|
||||
void SetAllocOwner( const char *pszAllocOwner );
|
||||
|
||||
private:
|
||||
bool CommitTo( byte * ) RESTRICT;
|
||||
void RegisterAllocation();
|
||||
void RegisterDeallocation( bool bShouldSpew );
|
||||
|
||||
const char* GetMemoryName() const OVERRIDE; // User friendly name for this stack or pool
|
||||
size_t GetAllocatedBytes() const OVERRIDE; // Number of bytes currently allocated
|
||||
size_t GetCommittedBytes() const OVERRIDE; // Bytes committed -- may be greater than allocated.
|
||||
size_t GetReservedBytes() const OVERRIDE; // Bytes reserved -- may be greater than committed.
|
||||
size_t GetHighestBytes() const OVERRIDE; // The maximum number of bytes allocated or committed.
|
||||
|
||||
byte *m_pNextAlloc; // Current alloc point (m_pNextAlloc - m_pBase == allocated bytes)
|
||||
byte *m_pCommitLimit; // The current end of the committed memory. On systems without dynamic commit/decommit this is always m_pAllocLimit
|
||||
byte *m_pAllocLimit; // The top of the allocated address space (m_pBase + m_maxSize)
|
||||
// Track the highest alloc limit seen.
|
||||
byte *m_pHighestAllocLimit;
|
||||
|
||||
byte *m_pBase;
|
||||
bool m_bRegisteredAllocation;
|
||||
bool m_bPhysical;
|
||||
char *m_pszAllocOwner;
|
||||
|
||||
unsigned m_maxSize; // m_maxSize stores how big the stack can grow. It measures the reservation size.
|
||||
unsigned m_alignment;
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
unsigned m_commitIncrement;
|
||||
unsigned m_minCommit;
|
||||
#endif
|
||||
#if defined( MEMSTACK_VIRTUAL_MEMORY_AVAILABLE ) && defined( _PS3 )
|
||||
IVirtualMemorySection *m_pVirtualMemorySection;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Make the assignment operator and copy constructor private and unimplemented.
|
||||
CMemoryStack& operator=( const CMemoryStack& );
|
||||
CMemoryStack( const CMemoryStack& );
|
||||
};
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
FORCEINLINE void *CMemoryStack::Alloc( unsigned bytes, bool bClear ) RESTRICT
|
||||
{
|
||||
Assert( m_pBase );
|
||||
|
||||
bytes = MAX( bytes, m_alignment );
|
||||
bytes = AlignValue( bytes, m_alignment );
|
||||
|
||||
void *pResult = m_pNextAlloc;
|
||||
byte *pNextAlloc = m_pNextAlloc + bytes;
|
||||
|
||||
if ( pNextAlloc > m_pCommitLimit )
|
||||
{
|
||||
if ( !CommitTo( pNextAlloc ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( bClear )
|
||||
{
|
||||
memset( pResult, 0, bytes );
|
||||
}
|
||||
|
||||
m_pNextAlloc = pNextAlloc;
|
||||
m_pHighestAllocLimit = Max( m_pNextAlloc, m_pHighestAllocLimit );
|
||||
|
||||
return pResult;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
inline bool CMemoryStack::CommitSize( int nBytes )
|
||||
{
|
||||
if ( GetSize() != nBytes )
|
||||
{
|
||||
return CommitTo( m_pBase + nBytes );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
// How big can this memory stack grow? This is equivalent to how many
|
||||
// bytes are reserved.
|
||||
inline int CMemoryStack::GetMaxSize() const
|
||||
{
|
||||
return m_maxSize;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
inline int CMemoryStack::GetUsed() const
|
||||
{
|
||||
return ( m_pNextAlloc - m_pBase );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
inline void *CMemoryStack::GetBase()
|
||||
{
|
||||
return m_pBase;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
inline MemoryStackMark_t CMemoryStack::GetCurrentAllocPoint() const
|
||||
{
|
||||
return ( m_pNextAlloc - m_pBase );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The CUtlMemoryStack class:
|
||||
// A fixed memory class
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename T, typename I, size_t MAX_SIZE, size_t COMMIT_SIZE = 0, size_t INITIAL_COMMIT = 0 >
|
||||
class CUtlMemoryStack
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUtlMemoryStack( int nGrowSize = 0, int nInitSize = 0 ) { m_MemoryStack.Init( "CUtlMemoryStack", MAX_SIZE * sizeof(T), COMMIT_SIZE * sizeof(T), INITIAL_COMMIT * sizeof(T), 4 ); COMPILE_TIME_ASSERT( sizeof(T) % 4 == 0 ); }
|
||||
CUtlMemoryStack( T* pMemory, int numElements ) { Assert( 0 ); }
|
||||
|
||||
// Can we use this index?
|
||||
bool IsIdxValid( I i ) const { long x=i; return (x >= 0) && (x < m_nAllocated); }
|
||||
|
||||
// Specify the invalid ('null') index that we'll only return on failure
|
||||
static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT
|
||||
static I InvalidIndex() { return INVALID_INDEX; }
|
||||
|
||||
class Iterator_t
|
||||
{
|
||||
Iterator_t( I i ) : index( i ) {}
|
||||
I index;
|
||||
friend class CUtlMemoryStack<T,I,MAX_SIZE, COMMIT_SIZE, INITIAL_COMMIT>;
|
||||
public:
|
||||
bool operator==( const Iterator_t it ) const { return index == it.index; }
|
||||
bool operator!=( const Iterator_t it ) const { return index != it.index; }
|
||||
};
|
||||
Iterator_t First() const { return Iterator_t( m_nAllocated ? 0 : InvalidIndex() ); }
|
||||
Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( it.index < m_nAllocated ? it.index + 1 : InvalidIndex() ); }
|
||||
I GetIndex( const Iterator_t &it ) const { return it.index; }
|
||||
bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
|
||||
bool IsValidIterator( const Iterator_t &it ) const { long x=it.index; return x >= 0 && x < m_nAllocated; }
|
||||
Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
|
||||
|
||||
// Gets the base address
|
||||
T* Base() { return (T*)m_MemoryStack.GetBase(); }
|
||||
const T* Base() const { return (const T*)m_MemoryStack.GetBase(); }
|
||||
|
||||
// element access
|
||||
T& operator[]( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
|
||||
const T& operator[]( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
|
||||
T& Element( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
|
||||
const T& Element( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
|
||||
|
||||
// Attaches the buffer to external memory....
|
||||
void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
|
||||
|
||||
// Size
|
||||
int NumAllocated() const { return m_nAllocated; }
|
||||
int Count() const { return m_nAllocated; }
|
||||
|
||||
// Grows the memory, so that at least allocated + num elements are allocated
|
||||
void Grow( int num = 1 ) { Assert( num > 0 ); m_nAllocated += num; m_MemoryStack.Alloc( num * sizeof(T) ); }
|
||||
|
||||
// Makes sure we've got at least this much memory
|
||||
void EnsureCapacity( int num ) { Assert( num <= MAX_SIZE ); if ( m_nAllocated < num ) Grow( num - m_nAllocated ); }
|
||||
|
||||
// Memory deallocation
|
||||
void Purge() { m_MemoryStack.FreeAll(); m_nAllocated = 0; }
|
||||
|
||||
// is the memory externally allocated?
|
||||
bool IsExternallyAllocated() const { return false; }
|
||||
|
||||
// Set the size by which the memory grows
|
||||
void SetGrowSize( int size ) { Assert( 0 ); }
|
||||
|
||||
// Identify the owner of this memory stack's memory
|
||||
void SetAllocOwner( const char *pszAllocOwner ) { m_MemoryStack.SetAllocOwner( pszAllocOwner ); }
|
||||
|
||||
private:
|
||||
CMemoryStack m_MemoryStack;
|
||||
int m_nAllocated;
|
||||
};
|
||||
|
||||
#endif // MEMSTACK_H
|
Loading…
x
Reference in New Issue
Block a user