Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //-----------------------------------------------------------------------------
  3. // NOTE! This should never be called directly from leaf code
  4. // Just use new,delete,malloc,free etc. They will call into this eventually
  5. //-----------------------------------------------------------------------------
  6. #include "pch_tier0.h"
  7. #if defined(_WIN32)
  8. #if !defined(_X360)
  9. #define WIN_32_LEAN_AND_MEAN
  10. #include <windows.h>
  11. #else
  12. #undef Verify
  13. #define _XBOX
  14. #include <xtl.h>
  15. #undef _XBOX
  16. #include "xbox/xbox_win32stubs.h"
  17. #endif
  18. #endif
  19. #include <malloc.h>
  20. #include <algorithm>
  21. #include "tier0/dbg.h"
  22. #include "tier0/memalloc.h"
  23. #include "tier0/threadtools.h"
  24. #include "tier0/tslist.h"
  25. #include "mem_helpers.h"
  26. #pragma pack(4)
  27. #ifdef _X360
  28. #define USE_PHYSICAL_SMALL_BLOCK_HEAP 1
  29. #endif
  30. // #define NO_SBH 1
  31. #define MIN_SBH_BLOCK 8
  32. #define MIN_SBH_ALIGN 8
  33. #define MAX_SBH_BLOCK 2048
  34. #define MAX_POOL_REGION (4*1024*1024)
  35. #if !defined(_X360)
  36. #define SBH_PAGE_SIZE (4*1024)
  37. #define COMMIT_SIZE (16*SBH_PAGE_SIZE)
  38. #else
  39. #define SBH_PAGE_SIZE (64*1024)
  40. #define COMMIT_SIZE (SBH_PAGE_SIZE)
  41. #endif
  42. #if _M_X64
  43. #define NUM_POOLS 34
  44. #else
  45. #define NUM_POOLS 42
  46. #endif
  47. // SBH not enabled for LINUX right now. Unlike on Windows, we can't globally hook malloc. Well,
  48. // we can and did in override_init_hook(), but that unfortunately causes all malloc functions
  49. // to get hooked - including the nVidia driver, etc. And these hooks appear to happen after
  50. // nVidia has alloc'd some memory and it crashes when they try to free that.
  51. // So we need things to work without this global hook - which means we rely on memdbgon.h / memdbgoff.h.
  52. // Unfortunately, that stuff always comes in source files after the headers are included, and
  53. // that means any alloc calls in the header files call the real libc functions. It's a mess.
  54. // I believe I've cleaned most of it up, and it appears to be working. However right now we are totally
  55. // gated on other performance issues, and the SBH doesn't give us any win, so I've disabled it for now.
  56. // Once those perf issues are worked out, it might make sense to do perf tests with SBH, libc, and tcmalloc.
  57. //
  58. //$ #if defined( _WIN32 ) || defined( _PS3 ) || defined( LINUX )
  59. #if defined( _WIN32 ) || defined( _PS3 )
  60. #define MEM_SBH_ENABLED 1
  61. #endif
  62. class ALIGN16 CSmallBlockPool
  63. {
  64. public:
  65. void Init( unsigned nBlockSize, byte *pBase, unsigned initialCommit = 0 );
  66. size_t GetBlockSize();
  67. bool IsOwner( void *p );
  68. void *Alloc();
  69. void Free( void *p );
  70. int CountFreeBlocks();
  71. int GetCommittedSize();
  72. int CountCommittedBlocks();
  73. int CountAllocatedBlocks();
  74. int Compact();
  75. private:
  76. typedef TSLNodeBase_t FreeBlock_t;
  77. class CFreeList : public CTSListBase
  78. {
  79. public:
  80. void Push( void *p ) { CTSListBase::Push( (TSLNodeBase_t *)p ); }
  81. };
  82. CFreeList m_FreeList;
  83. unsigned m_nBlockSize;
  84. CInterlockedPtr<byte> m_pNextAlloc;
  85. byte * m_pCommitLimit;
  86. byte * m_pAllocLimit;
  87. byte * m_pBase;
  88. CThreadFastMutex m_CommitMutex;
  89. } ALIGN16_POST;
  90. class ALIGN16 CSmallBlockHeap
  91. {
  92. public:
  93. CSmallBlockHeap();
  94. bool ShouldUse( size_t nBytes );
  95. bool IsOwner( void * p );
  96. void *Alloc( size_t nBytes );
  97. void *Realloc( void *p, size_t nBytes );
  98. void Free( void *p );
  99. size_t GetSize( void *p );
  100. void DumpStats( FILE *pFile = NULL );
  101. int Compact();
  102. private:
  103. CSmallBlockPool *FindPool( size_t nBytes );
  104. CSmallBlockPool *FindPool( void *p );
  105. CSmallBlockPool *m_PoolLookup[MAX_SBH_BLOCK >> 2];
  106. CSmallBlockPool m_Pools[NUM_POOLS];
  107. byte *m_pBase;
  108. byte *m_pLimit;
  109. } ALIGN16_POST;
  110. #ifdef USE_PHYSICAL_SMALL_BLOCK_HEAP
  111. #define BYTES_X360_SBH (32*1024*1024)
  112. #define PAGESIZE_X360_SBH (64*1024)
  113. class CX360SmallBlockPool
  114. {
  115. public:
  116. void Init( unsigned nBlockSize );
  117. size_t GetBlockSize();
  118. bool IsOwner( void *p );
  119. void *Alloc();
  120. void Free( void *p );
  121. int CountFreeBlocks();
  122. int GetCommittedSize();
  123. int CountCommittedBlocks();
  124. int CountAllocatedBlocks();
  125. static CX360SmallBlockPool *FindPool( void *p )
  126. {
  127. int index = (size_t)((byte *)p - gm_pPhysicalBase) / PAGESIZE_X360_SBH;
  128. if ( index < 0 || index >= ARRAYSIZE(gm_AddressToPool) )
  129. return NULL;
  130. return gm_AddressToPool[ index ];
  131. }
  132. private:
  133. friend class CX360SmallBlockHeap;
  134. typedef TSLNodeBase_t FreeBlock_t;
  135. class CFreeList : public CTSListBase
  136. {
  137. public:
  138. void Push( void *p ) { CTSListBase::Push( (TSLNodeBase_t *)p ); }
  139. };
  140. CFreeList m_FreeList;
  141. unsigned m_nBlockSize;
  142. unsigned m_CommittedSize;
  143. CInterlockedPtr<byte> m_pNextAlloc;
  144. byte * m_pCurBlockEnd;
  145. CThreadFastMutex m_CommitMutex;
  146. static CX360SmallBlockPool *gm_AddressToPool[BYTES_X360_SBH/PAGESIZE_X360_SBH];
  147. static byte *gm_pPhysicalBlock;
  148. static byte *gm_pPhysicalBase;
  149. static byte *gm_pPhysicalLimit;
  150. };
  151. class CX360SmallBlockHeap
  152. {
  153. public:
  154. CX360SmallBlockHeap();
  155. bool ShouldUse( size_t nBytes );
  156. bool IsOwner( void * p );
  157. void *Alloc( size_t nBytes );
  158. void *Realloc( void *p, size_t nBytes );
  159. void Free( void *p );
  160. size_t GetSize( void *p );
  161. void DumpStats( FILE *pFile = NULL );
  162. CSmallBlockHeap *GetStandardSBH();
  163. private:
  164. CX360SmallBlockPool *FindPool( size_t nBytes );
  165. CX360SmallBlockPool *FindPool( void *p );
  166. CX360SmallBlockPool *m_PoolLookup[MAX_SBH_BLOCK >> 2];
  167. CX360SmallBlockPool m_Pools[NUM_POOLS];
  168. };
  169. #endif
  170. class ALIGN16 CStdMemAlloc : public IMemAlloc
  171. {
  172. public:
  173. CStdMemAlloc()
  174. : m_pfnFailHandler( DefaultFailHandler ),
  175. m_sMemoryAllocFailed( (size_t)0 )
  176. {
  177. // Make sure that we return 64-bit addresses in 64-bit builds.
  178. ReserveBottomMemory();
  179. }
  180. // Release versions
  181. virtual void *Alloc( size_t nSize );
  182. virtual void *Realloc( void *pMem, size_t nSize );
  183. virtual void Free( void *pMem );
  184. virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize );
  185. // Debug versions
  186. virtual void *Alloc( size_t nSize, const char *pFileName, int nLine );
  187. virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine );
  188. virtual void Free( void *pMem, const char *pFileName, int nLine );
  189. virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine );
  190. // Returns size of a particular allocation
  191. virtual size_t GetSize( void *pMem );
  192. // Force file + line information for an allocation
  193. virtual void PushAllocDbgInfo( const char *pFileName, int nLine );
  194. virtual void PopAllocDbgInfo();
  195. virtual long CrtSetBreakAlloc( long lNewBreakAlloc );
  196. virtual int CrtSetReportMode( int nReportType, int nReportMode );
  197. virtual int CrtIsValidHeapPointer( const void *pMem );
  198. virtual int CrtIsValidPointer( const void *pMem, unsigned int size, int access );
  199. virtual int CrtCheckMemory( void );
  200. virtual int CrtSetDbgFlag( int nNewFlag );
  201. virtual void CrtMemCheckpoint( _CrtMemState *pState );
  202. void* CrtSetReportFile( int nRptType, void* hFile );
  203. void* CrtSetReportHook( void* pfnNewHook );
  204. int CrtDbgReport( int nRptType, const char * szFile,
  205. int nLine, const char * szModule, const char * pMsg );
  206. virtual int heapchk();
  207. virtual void DumpStats();
  208. virtual void DumpStatsFileBase( char const *pchFileBase );
  209. virtual void GlobalMemoryStatus( size_t *pUsedMemory, size_t *pFreeMemory );
  210. virtual bool IsDebugHeap() { return false; }
  211. virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) {}
  212. virtual void RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) {}
  213. virtual void RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) {}
  214. virtual int GetVersion() { return MEMALLOC_VERSION; }
  215. virtual void CompactHeap();
  216. virtual MemAllocFailHandler_t SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler );
  217. size_t CallAllocFailHandler( size_t nBytes ) { return (*m_pfnFailHandler)( nBytes); }
  218. virtual uint32 GetDebugInfoSize() { return 0; }
  219. virtual void SaveDebugInfo( void *pvDebugInfo ) { }
  220. virtual void RestoreDebugInfo( const void *pvDebugInfo ) {}
  221. virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) {}
  222. static size_t DefaultFailHandler( size_t );
  223. void DumpBlockStats( void *p ) {}
  224. #ifdef MEM_SBH_ENABLED
  225. CSmallBlockHeap m_SmallBlockHeap;
  226. #ifdef USE_PHYSICAL_SMALL_BLOCK_HEAP
  227. CX360SmallBlockHeap m_LargePageSmallBlockHeap;
  228. #endif
  229. #endif
  230. #if defined( _MEMTEST )
  231. virtual void SetStatsExtraInfo( const char *pMapName, const char *pComment );
  232. #endif
  233. virtual size_t MemoryAllocFailed();
  234. void SetCRTAllocFailed( size_t nMemSize );
  235. MemAllocFailHandler_t m_pfnFailHandler;
  236. size_t m_sMemoryAllocFailed;
  237. } ALIGN16_POST;