You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
8.4 KiB
292 lines
8.4 KiB
//========= 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; |
|
|
|
|
|
|