diff options
Diffstat (limited to 'tier0/memstd.h')
| -rw-r--r-- | tier0/memstd.h | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/tier0/memstd.h b/tier0/memstd.h new file mode 100644 index 0000000..59ea7f7 --- /dev/null +++ b/tier0/memstd.h @@ -0,0 +1,292 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//----------------------------------------------------------------------------- +// NOTE! This should never be called directly from leaf code +// Just use new,delete,malloc,free etc. They will call into this eventually +//----------------------------------------------------------------------------- +#include "pch_tier0.h" + +#if defined(_WIN32) +#if !defined(_X360) +#define WIN_32_LEAN_AND_MEAN +#include <windows.h> +#else +#undef Verify +#define _XBOX +#include <xtl.h> +#undef _XBOX +#include "xbox/xbox_win32stubs.h" +#endif +#endif + +#include <malloc.h> +#include <algorithm> +#include "tier0/dbg.h" +#include "tier0/memalloc.h" +#include "tier0/threadtools.h" +#include "tier0/tslist.h" +#include "mem_helpers.h" + +#pragma pack(4) + +#ifdef _X360 +#define USE_PHYSICAL_SMALL_BLOCK_HEAP 1 +#endif + + +// #define NO_SBH 1 + + +#define MIN_SBH_BLOCK 8 +#define MIN_SBH_ALIGN 8 +#define MAX_SBH_BLOCK 2048 +#define MAX_POOL_REGION (4*1024*1024) +#if !defined(_X360) +#define SBH_PAGE_SIZE (4*1024) +#define COMMIT_SIZE (16*SBH_PAGE_SIZE) +#else +#define SBH_PAGE_SIZE (64*1024) +#define COMMIT_SIZE (SBH_PAGE_SIZE) +#endif +#if _M_X64 +#define NUM_POOLS 34 +#else +#define NUM_POOLS 42 +#endif + +// SBH not enabled for LINUX right now. Unlike on Windows, we can't globally hook malloc. Well, +// we can and did in override_init_hook(), but that unfortunately causes all malloc functions +// to get hooked - including the nVidia driver, etc. And these hooks appear to happen after +// nVidia has alloc'd some memory and it crashes when they try to free that. +// So we need things to work without this global hook - which means we rely on memdbgon.h / memdbgoff.h. +// Unfortunately, that stuff always comes in source files after the headers are included, and +// that means any alloc calls in the header files call the real libc functions. It's a mess. +// I believe I've cleaned most of it up, and it appears to be working. However right now we are totally +// gated on other performance issues, and the SBH doesn't give us any win, so I've disabled it for now. +// Once those perf issues are worked out, it might make sense to do perf tests with SBH, libc, and tcmalloc. +// +//$ #if defined( _WIN32 ) || defined( _PS3 ) || defined( LINUX ) +#if defined( _WIN32 ) || defined( _PS3 ) +#define MEM_SBH_ENABLED 1 +#endif + +class ALIGN16 CSmallBlockPool +{ +public: + void Init( unsigned nBlockSize, byte *pBase, unsigned initialCommit = 0 ); + size_t GetBlockSize(); + bool IsOwner( void *p ); + void *Alloc(); + void Free( void *p ); + int CountFreeBlocks(); + int GetCommittedSize(); + int CountCommittedBlocks(); + int CountAllocatedBlocks(); + int Compact(); + +private: + + typedef TSLNodeBase_t FreeBlock_t; + class CFreeList : public CTSListBase + { + public: + void Push( void *p ) { CTSListBase::Push( (TSLNodeBase_t *)p ); } + }; + + CFreeList m_FreeList; + + unsigned m_nBlockSize; + + CInterlockedPtr<byte> m_pNextAlloc; + byte * m_pCommitLimit; + byte * m_pAllocLimit; + byte * m_pBase; + + CThreadFastMutex m_CommitMutex; +} ALIGN16_POST; + + +class ALIGN16 CSmallBlockHeap +{ +public: + CSmallBlockHeap(); + bool ShouldUse( size_t nBytes ); + bool IsOwner( void * p ); + void *Alloc( size_t nBytes ); + void *Realloc( void *p, size_t nBytes ); + void Free( void *p ); + size_t GetSize( void *p ); + void DumpStats( FILE *pFile = NULL ); + int Compact(); + +private: + CSmallBlockPool *FindPool( size_t nBytes ); + CSmallBlockPool *FindPool( void *p ); + + CSmallBlockPool *m_PoolLookup[MAX_SBH_BLOCK >> 2]; + CSmallBlockPool m_Pools[NUM_POOLS]; + byte *m_pBase; + byte *m_pLimit; +} ALIGN16_POST; + +#ifdef USE_PHYSICAL_SMALL_BLOCK_HEAP +#define BYTES_X360_SBH (32*1024*1024) +#define PAGESIZE_X360_SBH (64*1024) +class CX360SmallBlockPool +{ +public: + void Init( unsigned nBlockSize ); + size_t GetBlockSize(); + bool IsOwner( void *p ); + void *Alloc(); + void Free( void *p ); + int CountFreeBlocks(); + int GetCommittedSize(); + int CountCommittedBlocks(); + int CountAllocatedBlocks(); + + static CX360SmallBlockPool *FindPool( void *p ) + { + int index = (size_t)((byte *)p - gm_pPhysicalBase) / PAGESIZE_X360_SBH; + if ( index < 0 || index >= ARRAYSIZE(gm_AddressToPool) ) + return NULL; + return gm_AddressToPool[ index ]; + } + +private: + friend class CX360SmallBlockHeap; + + typedef TSLNodeBase_t FreeBlock_t; + class CFreeList : public CTSListBase + { + public: + void Push( void *p ) { CTSListBase::Push( (TSLNodeBase_t *)p ); } + }; + + CFreeList m_FreeList; + + unsigned m_nBlockSize; + unsigned m_CommittedSize; + + CInterlockedPtr<byte> m_pNextAlloc; + byte * m_pCurBlockEnd; + + CThreadFastMutex m_CommitMutex; + + static CX360SmallBlockPool *gm_AddressToPool[BYTES_X360_SBH/PAGESIZE_X360_SBH]; + + static byte *gm_pPhysicalBlock; + static byte *gm_pPhysicalBase; + static byte *gm_pPhysicalLimit; +}; + + +class CX360SmallBlockHeap +{ +public: + CX360SmallBlockHeap(); + bool ShouldUse( size_t nBytes ); + bool IsOwner( void * p ); + void *Alloc( size_t nBytes ); + void *Realloc( void *p, size_t nBytes ); + void Free( void *p ); + size_t GetSize( void *p ); + void DumpStats( FILE *pFile = NULL ); + + CSmallBlockHeap *GetStandardSBH(); + +private: + CX360SmallBlockPool *FindPool( size_t nBytes ); + CX360SmallBlockPool *FindPool( void *p ); + + CX360SmallBlockPool *m_PoolLookup[MAX_SBH_BLOCK >> 2]; + CX360SmallBlockPool m_Pools[NUM_POOLS]; +}; +#endif + + +class ALIGN16 CStdMemAlloc : public IMemAlloc +{ +public: + CStdMemAlloc() + : m_pfnFailHandler( DefaultFailHandler ), + m_sMemoryAllocFailed( (size_t)0 ) + { + // Make sure that we return 64-bit addresses in 64-bit builds. + ReserveBottomMemory(); + } + // Release versions + virtual void *Alloc( size_t nSize ); + virtual void *Realloc( void *pMem, size_t nSize ); + virtual void Free( void *pMem ); + virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize ); + + // Debug versions + virtual void *Alloc( size_t nSize, const char *pFileName, int nLine ); + virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine ); + virtual void Free( void *pMem, const char *pFileName, int nLine ); + virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine ); + + // Returns size of a particular allocation + virtual size_t GetSize( void *pMem ); + + // Force file + line information for an allocation + virtual void PushAllocDbgInfo( const char *pFileName, int nLine ); + virtual void PopAllocDbgInfo(); + + virtual long CrtSetBreakAlloc( long lNewBreakAlloc ); + virtual int CrtSetReportMode( int nReportType, int nReportMode ); + virtual int CrtIsValidHeapPointer( const void *pMem ); + virtual int CrtIsValidPointer( const void *pMem, unsigned int size, int access ); + virtual int CrtCheckMemory( void ); + virtual int CrtSetDbgFlag( int nNewFlag ); + virtual void CrtMemCheckpoint( _CrtMemState *pState ); + void* CrtSetReportFile( int nRptType, void* hFile ); + void* CrtSetReportHook( void* pfnNewHook ); + int CrtDbgReport( int nRptType, const char * szFile, + int nLine, const char * szModule, const char * pMsg ); + virtual int heapchk(); + + virtual void DumpStats(); + virtual void DumpStatsFileBase( char const *pchFileBase ); + virtual void GlobalMemoryStatus( size_t *pUsedMemory, size_t *pFreeMemory ); + + virtual bool IsDebugHeap() { return false; } + + virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) {} + virtual void RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) {} + virtual void RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) {} + + virtual int GetVersion() { return MEMALLOC_VERSION; } + + virtual void CompactHeap(); + + virtual MemAllocFailHandler_t SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler ); + size_t CallAllocFailHandler( size_t nBytes ) { return (*m_pfnFailHandler)( nBytes); } + + virtual uint32 GetDebugInfoSize() { return 0; } + virtual void SaveDebugInfo( void *pvDebugInfo ) { } + virtual void RestoreDebugInfo( const void *pvDebugInfo ) {} + virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) {} + + static size_t DefaultFailHandler( size_t ); + void DumpBlockStats( void *p ) {} +#ifdef MEM_SBH_ENABLED + CSmallBlockHeap m_SmallBlockHeap; +#ifdef USE_PHYSICAL_SMALL_BLOCK_HEAP + CX360SmallBlockHeap m_LargePageSmallBlockHeap; +#endif +#endif + +#if defined( _MEMTEST ) + virtual void SetStatsExtraInfo( const char *pMapName, const char *pComment ); +#endif + + virtual size_t MemoryAllocFailed(); + + void SetCRTAllocFailed( size_t nMemSize ); + + MemAllocFailHandler_t m_pfnFailHandler; + size_t m_sMemoryAllocFailed; +} ALIGN16_POST; + + |