Counter Strike : Global Offensive Source Code
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.

763 lines
24 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: This header should never be used directly from leaf code!!!
  4. // Instead, just add the file memoverride.cpp into your project and all this
  5. // will automagically be used
  6. //
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #ifndef TIER0_MEMALLOC_H
  10. #define TIER0_MEMALLOC_H
  11. #ifdef _WIN32
  12. #pragma once
  13. #endif
  14. // These memory debugging switches aren't relevant under Linux builds since memoverride.cpp
  15. // isn't built into Linux projects
  16. // [will] - Temporarily disabling for OSX until I can fix memory issues.
  17. #if !defined( LINUX ) && !defined( _OSX )
  18. // Define this in release to get memory tracking even in release builds
  19. //#define USE_MEM_DEBUG 1
  20. // Define this in release to get light memory debugging
  21. //#define USE_LIGHT_MEM_DEBUG
  22. // Define this to require -uselmd to turn light memory debugging on
  23. #define LIGHT_MEM_DEBUG_REQUIRES_CMD_LINE_SWITCH
  24. #endif
  25. #if defined( _MEMTEST )
  26. #if defined( _WIN32 ) || defined( _PS3 )
  27. #define USE_MEM_DEBUG 1
  28. #endif
  29. #endif
  30. #if defined( _PS3 )
  31. // Define STEAM_SHARES_GAME_ALLOCATOR to make Steam use the game's tier0 memory allocator.
  32. // This adds some memory to the game's Small Block Heap and Medium Block Heap, to compensate.
  33. // This configuration was disabled for Portal 2, as we could not sufficiently test it before ship.
  34. //#define STEAM_SHARES_GAME_ALLOCATOR
  35. #endif
  36. #if defined( STEAM_SHARES_GAME_ALLOCATOR )
  37. #define MBYTES_STEAM_SBH_USAGE 2
  38. #define MBYTES_STEAM_MBH_USAGE 4
  39. #else // STEAM_SHARES_GAME_ALLOCATOR
  40. #define MBYTES_STEAM_SBH_USAGE 0
  41. #define MBYTES_STEAM_MBH_USAGE 0
  42. #endif // STEAM_SHARES_GAME_ALLOCATOR
  43. // Undefine this if using a compiler lacking threadsafe RTTI (like vc6)
  44. #define MEM_DEBUG_CLASSNAME 1
  45. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  46. #include <stddef.h>
  47. #ifdef LINUX
  48. #undef offsetof
  49. #define offsetof(s,m) (size_t)&(((s *)0)->m)
  50. #endif
  51. #ifdef _PS3
  52. #define MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS 1
  53. #endif
  54. #include "tier0/mem.h"
  55. struct _CrtMemState;
  56. #define MEMALLOC_VERSION 1
  57. typedef size_t (*MemAllocFailHandler_t)( size_t );
  58. struct GenericMemoryStat_t
  59. {
  60. const char *name;
  61. int value;
  62. };
  63. // Virtual memory interface
  64. #include "tier0/memvirt.h"
  65. /// This interface class is used to let the mem_dump command retrieve
  66. /// information about memory allocations outside of the heap. It is currently
  67. /// used by CMemoryStack to report on its allocations.
  68. abstract_class IMemoryInfo
  69. {
  70. public:
  71. virtual const char* GetMemoryName() const = 0; // User friendly name for this stack or pool
  72. virtual size_t GetAllocatedBytes() const = 0; // Number of bytes currently allocated
  73. virtual size_t GetCommittedBytes() const = 0; // Bytes committed -- may be greater than allocated.
  74. virtual size_t GetReservedBytes() const = 0; // Bytes reserved -- may be greater than committed.
  75. virtual size_t GetHighestBytes() const = 0; // The maximum number of bytes allocated or committed.
  76. };
  77. // Add and remove callbacks used to get statistics on non-heap memory allocations.
  78. PLATFORM_INTERFACE void AddMemoryInfoCallback( IMemoryInfo* pMemoryInfo );
  79. PLATFORM_INTERFACE void RemoveMemoryInfoCallback( IMemoryInfo* pMemoryInfo );
  80. // Display the memory statistics from the callbacks controlled by the above functions.
  81. PLATFORM_INTERFACE void DumpMemoryInfoStats();
  82. //-----------------------------------------------------------------------------
  83. // NOTE! This should never be called directly from leaf code
  84. // Just use new,delete,malloc,free etc. They will call into this eventually
  85. //-----------------------------------------------------------------------------
  86. #define ASSERT_MEMALLOC_WILL_ALIGN( T ) COMPILE_TIME_ASSERT( __alignof( T ) <= 16 )
  87. abstract_class IMemAlloc
  88. {
  89. public:
  90. // Release versions
  91. virtual void *Alloc( size_t nSize ) = 0;
  92. public:
  93. virtual void *Realloc( void *pMem, size_t nSize ) = 0;
  94. virtual void Free( void *pMem ) = 0;
  95. virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize ) = 0;
  96. // Debug versions
  97. virtual void *Alloc( size_t nSize, const char *pFileName, int nLine ) = 0;
  98. public:
  99. virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine ) = 0;
  100. virtual void Free( void *pMem, const char *pFileName, int nLine ) = 0;
  101. virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine ) = 0;
  102. #ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  103. virtual void *AllocAlign( size_t nSize, size_t align ) = 0;
  104. virtual void *AllocAlign( size_t nSize, size_t align, const char *pFileName, int nLine ) = 0;
  105. virtual void *ReallocAlign( void *pMem, size_t nSize, size_t align ) = 0;
  106. #endif
  107. inline void *IndirectAlloc( size_t nSize ) { return Alloc( nSize ); }
  108. inline void *IndirectAlloc( size_t nSize, const char *pFileName, int nLine ) { return Alloc( nSize, pFileName, nLine ); }
  109. // Returns the size of a particular allocation (NOTE: may be larger than the size requested!)
  110. virtual size_t GetSize( void *pMem ) = 0;
  111. // Force file + line information for an allocation
  112. virtual void PushAllocDbgInfo( const char *pFileName, int nLine ) = 0;
  113. virtual void PopAllocDbgInfo() = 0;
  114. // FIXME: Remove when we have our own allocator
  115. // these methods of the Crt debug code is used in our codebase currently
  116. virtual int32 CrtSetBreakAlloc( int32 lNewBreakAlloc ) = 0;
  117. virtual int CrtSetReportMode( int nReportType, int nReportMode ) = 0;
  118. virtual int CrtIsValidHeapPointer( const void *pMem ) = 0;
  119. virtual int CrtIsValidPointer( const void *pMem, unsigned int size, int access ) = 0;
  120. virtual int CrtCheckMemory( void ) = 0;
  121. virtual int CrtSetDbgFlag( int nNewFlag ) = 0;
  122. virtual void CrtMemCheckpoint( _CrtMemState *pState ) = 0;
  123. // FIXME: Make a better stats interface
  124. virtual void DumpStats() = 0;
  125. enum DumpStatsFormat_t
  126. {
  127. FORMAT_TEXT,
  128. FORMAT_HTML
  129. };
  130. virtual void DumpStatsFileBase( char const *pchFileBase, DumpStatsFormat_t nFormat = FORMAT_TEXT ) = 0;
  131. virtual size_t ComputeMemoryUsedBy( char const *pchSubStr ) = 0;
  132. // FIXME: Remove when we have our own allocator
  133. virtual void* CrtSetReportFile( int nRptType, void* hFile ) = 0;
  134. virtual void* CrtSetReportHook( void* pfnNewHook ) = 0;
  135. virtual int CrtDbgReport( int nRptType, const char * szFile,
  136. int nLine, const char * szModule, const char * pMsg ) = 0;
  137. virtual int heapchk() = 0;
  138. virtual bool IsDebugHeap() = 0;
  139. virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) = 0;
  140. virtual void RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) = 0;
  141. virtual void RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) = 0;
  142. virtual int GetVersion() = 0;
  143. virtual void CompactHeap() = 0;
  144. // Function called when malloc fails or memory limits hit to attempt to free up memory (can come in any thread)
  145. virtual MemAllocFailHandler_t SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler ) = 0;
  146. virtual void DumpBlockStats( void * ) = 0;
  147. virtual void SetStatsExtraInfo( const char *pMapName, const char *pComment ) = 0;
  148. // Returns 0 if no failure, otherwise the size_t of the last requested chunk
  149. virtual size_t MemoryAllocFailed() = 0;
  150. virtual void CompactIncremental() = 0;
  151. virtual void OutOfMemory( size_t nBytesAttempted = 0 ) = 0;
  152. // Region-based allocations
  153. virtual void *RegionAlloc( int region, size_t nSize ) = 0;
  154. virtual void *RegionAlloc( int region, size_t nSize, const char *pFileName, int nLine ) = 0;
  155. // Replacement for ::GlobalMemoryStatus which accounts for unused memory in our system
  156. virtual void GlobalMemoryStatus( size_t *pUsedMemory, size_t *pFreeMemory ) = 0;
  157. // Obtain virtual memory manager interface
  158. virtual IVirtualMemorySection * AllocateVirtualMemorySection( size_t numMaxBytes ) = 0;
  159. // Request 'generic' memory stats (returns a list of N named values; caller should assume this list will change over time)
  160. virtual int GetGenericMemoryStats( GenericMemoryStat_t **ppMemoryStats ) = 0;
  161. virtual ~IMemAlloc() { };
  162. // handles storing allocation info for coroutines
  163. virtual uint32 GetDebugInfoSize() = 0;
  164. virtual void SaveDebugInfo( void *pvDebugInfo ) = 0;
  165. virtual void RestoreDebugInfo( const void *pvDebugInfo ) = 0;
  166. virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) = 0;
  167. };
  168. //-----------------------------------------------------------------------------
  169. // Singleton interface
  170. //-----------------------------------------------------------------------------
  171. #ifdef _PS3
  172. PLATFORM_INTERFACE IMemAlloc * g_pMemAllocInternalPS3;
  173. #ifndef PLATFORM_INTERFACE_MEM_ALLOC_INTERNAL_PS3_OVERRIDE
  174. #define g_pMemAlloc g_pMemAllocInternalPS3
  175. #else
  176. #define g_pMemAlloc PLATFORM_INTERFACE_MEM_ALLOC_INTERNAL_PS3_OVERRIDE
  177. #endif
  178. #else // !_PS3
  179. MEM_INTERFACE IMemAlloc *g_pMemAlloc;
  180. #endif
  181. //-----------------------------------------------------------------------------
  182. #ifdef MEMALLOC_REGIONS
  183. #ifndef MEMALLOC_REGION
  184. #define MEMALLOC_REGION 0
  185. #endif
  186. inline void *MemAlloc_Alloc( size_t nSize )
  187. {
  188. return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize );
  189. }
  190. inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine )
  191. {
  192. return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize, pFileName, nLine );
  193. }
  194. #else
  195. #undef MEMALLOC_REGION
  196. inline void *MemAlloc_Alloc( size_t nSize )
  197. {
  198. return g_pMemAlloc->IndirectAlloc( nSize );
  199. }
  200. inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine )
  201. {
  202. return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine );
  203. }
  204. #endif
  205. //-----------------------------------------------------------------------------
  206. #ifdef MEMALLOC_REGIONS
  207. #else
  208. #endif
  209. inline bool ValueIsPowerOfTwo( size_t value ) // don't clash with mathlib definition
  210. {
  211. return (value & ( value - 1 )) == 0;
  212. }
  213. inline void *MemAlloc_AllocAlignedUnattributed( size_t size, size_t align )
  214. {
  215. #ifndef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  216. unsigned char *pAlloc, *pResult;
  217. #endif
  218. if (!ValueIsPowerOfTwo(align))
  219. return NULL;
  220. #ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  221. return g_pMemAlloc->AllocAlign( size, align );
  222. #else
  223. align = (align > sizeof(void *) ? align : sizeof(void *)) - 1;
  224. if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size ) ) == (unsigned char*)NULL)
  225. return NULL;
  226. pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align );
  227. ((unsigned char**)(pResult))[-1] = pAlloc;
  228. return (void *)pResult;
  229. #endif
  230. }
  231. inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile, int nLine )
  232. {
  233. #ifndef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  234. unsigned char *pAlloc, *pResult;
  235. #endif
  236. if (!ValueIsPowerOfTwo(align))
  237. return NULL;
  238. #ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  239. return g_pMemAlloc->AllocAlign( size, align, pszFile, nLine );
  240. #else
  241. align = (align > sizeof(void *) ? align : sizeof(void *)) - 1;
  242. if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size, pszFile, nLine ) ) == (unsigned char*)NULL)
  243. return NULL;
  244. pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align );
  245. ((unsigned char**)(pResult))[-1] = pAlloc;
  246. return (void *)pResult;
  247. #endif
  248. }
  249. #ifdef USE_MEM_DEBUG
  250. #define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedFileLine( s, a, __FILE__, __LINE__ )
  251. #elif defined(USE_LIGHT_MEM_DEBUG)
  252. extern const char *g_pszModule;
  253. #define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedFileLine( s, a, ::g_pszModule, 0 )
  254. #else
  255. #define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedUnattributed( s, a )
  256. #endif
  257. inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align )
  258. {
  259. if ( !ValueIsPowerOfTwo( align ) )
  260. return NULL;
  261. // Don't change alignment between allocation + reallocation.
  262. if ( ( (size_t)ptr & ( align - 1 ) ) != 0 )
  263. return NULL;
  264. #ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  265. return g_pMemAlloc->ReallocAlign( ptr, size, align );
  266. #else
  267. if ( !ptr )
  268. return MemAlloc_AllocAligned( size, align );
  269. void *pAlloc, *pResult;
  270. // Figure out the actual allocation point
  271. pAlloc = ptr;
  272. pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *));
  273. pAlloc = *( (void **)pAlloc );
  274. // See if we have enough space
  275. size_t nOffset = (size_t)ptr - (size_t)pAlloc;
  276. size_t nOldSize = g_pMemAlloc->GetSize( pAlloc );
  277. if ( nOldSize >= size + nOffset )
  278. return ptr;
  279. pResult = MemAlloc_AllocAligned( size, align );
  280. memcpy( pResult, ptr, nOldSize - nOffset );
  281. g_pMemAlloc->Free( pAlloc );
  282. return pResult;
  283. #endif
  284. }
  285. inline void MemAlloc_FreeAligned( void *pMemBlock )
  286. {
  287. #ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  288. g_pMemAlloc->Free( pMemBlock );
  289. #else
  290. void *pAlloc;
  291. if ( pMemBlock == NULL )
  292. return;
  293. pAlloc = pMemBlock;
  294. // pAlloc points to the pointer to starting of the memory block
  295. pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *));
  296. // pAlloc is the pointer to the start of memory block
  297. pAlloc = *( (void **)pAlloc );
  298. g_pMemAlloc->Free( pAlloc );
  299. #endif
  300. }
  301. inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile, int nLine )
  302. {
  303. #ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  304. g_pMemAlloc->Free( pMemBlock, pszFile, nLine );
  305. #else
  306. void *pAlloc;
  307. if ( pMemBlock == NULL )
  308. return;
  309. pAlloc = pMemBlock;
  310. // pAlloc points to the pointer to starting of the memory block
  311. pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *));
  312. // pAlloc is the pointer to the start of memory block
  313. pAlloc = *( (void **)pAlloc );
  314. g_pMemAlloc->Free( pAlloc, pszFile, nLine );
  315. #endif
  316. }
  317. inline void MemAlloc_Free(void *pMemBlock)
  318. {
  319. g_pMemAlloc->Free(pMemBlock);
  320. }
  321. inline size_t MemAlloc_GetSizeAligned( void *pMemBlock )
  322. {
  323. #ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS
  324. return g_pMemAlloc->GetSize( pMemBlock );
  325. #else
  326. void *pAlloc;
  327. if ( pMemBlock == NULL )
  328. return 0;
  329. pAlloc = pMemBlock;
  330. // pAlloc points to the pointer to starting of the memory block
  331. pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *));
  332. // pAlloc is the pointer to the start of memory block
  333. pAlloc = *((void **)pAlloc );
  334. return g_pMemAlloc->GetSize( pAlloc ) - ( (byte *)pMemBlock - (byte *)pAlloc );
  335. #endif
  336. }
  337. struct aligned_tmp_t
  338. {
  339. // empty base class
  340. };
  341. // template here to allow adding alignment at levels of hierarchy that aren't the base
  342. template< int bytesAlignment = 16, class T = aligned_tmp_t >
  343. class CAlignedNewDelete : public T
  344. {
  345. public:
  346. void *operator new( size_t nSize )
  347. {
  348. return MemAlloc_AllocAligned( nSize, bytesAlignment );
  349. }
  350. void* operator new( size_t nSize, int nBlockUse, const char *pFileName, int nLine )
  351. {
  352. return MemAlloc_AllocAlignedFileLine( nSize, bytesAlignment, pFileName, nLine );
  353. }
  354. void operator delete(void *pData)
  355. {
  356. if ( pData )
  357. {
  358. MemAlloc_FreeAligned( pData );
  359. }
  360. }
  361. void operator delete( void* pData, int nBlockUse, const char *pFileName, int nLine )
  362. {
  363. if ( pData )
  364. {
  365. MemAlloc_FreeAligned( pData, pFileName, nLine );
  366. }
  367. }
  368. };
  369. //-----------------------------------------------------------------------------
  370. #if (defined(_DEBUG) || defined(USE_MEM_DEBUG))
  371. #define MEM_ALLOC_CREDIT_(tag) CMemAllocAttributeAlloction memAllocAttributeAlloction( tag, __LINE__ )
  372. #define MemAlloc_PushAllocDbgInfo( pszFile, line ) g_pMemAlloc->PushAllocDbgInfo( pszFile, line )
  373. #define MemAlloc_PopAllocDbgInfo() g_pMemAlloc->PopAllocDbgInfo()
  374. #define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime )
  375. #define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime )
  376. #else
  377. #define MEM_ALLOC_CREDIT_(tag) ((void)0)
  378. #define MemAlloc_PushAllocDbgInfo( pszFile, line ) ((void)0)
  379. #define MemAlloc_PopAllocDbgInfo() ((void)0)
  380. #define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
  381. #define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
  382. #endif
  383. //-----------------------------------------------------------------------------
  384. class CMemAllocAttributeAlloction
  385. {
  386. public:
  387. CMemAllocAttributeAlloction( const char *pszFile, int line )
  388. {
  389. MemAlloc_PushAllocDbgInfo( pszFile, line );
  390. }
  391. ~CMemAllocAttributeAlloction()
  392. {
  393. MemAlloc_PopAllocDbgInfo();
  394. }
  395. };
  396. #define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__)
  397. //-----------------------------------------------------------------------------
  398. #if defined(MSVC) && ( defined(_DEBUG) || defined(USE_MEM_DEBUG) )
  399. #pragma warning(disable:4290)
  400. #pragma warning(push)
  401. #include <typeinfo.h>
  402. // MEM_DEBUG_CLASSNAME is opt-in.
  403. // Note: typeid().name() is not threadsafe, so if the project needs to access it in multiple threads
  404. // simultaneously, it'll need a mutex.
  405. #if defined(_CPPRTTI) && defined(MEM_DEBUG_CLASSNAME)
  406. template <typename T> const char *MemAllocClassName( T *p )
  407. {
  408. static const char *pszName = typeid(*p).name(); // @TODO: support having debug heap ignore certain allocations, and ignore memory allocated here [5/7/2009 tom]
  409. return pszName;
  410. }
  411. #define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( MemAllocClassName( this ) )
  412. #define MEM_ALLOC_CLASSNAME(type) (typeid((type*)(0)).name())
  413. #else
  414. #define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( __FILE__ )
  415. #define MEM_ALLOC_CLASSNAME(type) (__FILE__)
  416. #endif
  417. // MEM_ALLOC_CREDIT_FUNCTION is used when no this pointer is available ( inside 'new' overloads, for example )
  418. #ifdef _MSC_VER
  419. #define MEM_ALLOC_CREDIT_FUNCTION() MEM_ALLOC_CREDIT_( __FUNCTION__ )
  420. #else
  421. #define MEM_ALLOC_CREDIT_FUNCTION() (__FILE__)
  422. #endif
  423. #pragma warning(pop)
  424. #else
  425. #define MEM_ALLOC_CREDIT_CLASS()
  426. #define MEM_ALLOC_CLASSNAME(type) NULL
  427. #define MEM_ALLOC_CREDIT_FUNCTION()
  428. #endif
  429. //-----------------------------------------------------------------------------
  430. #if (defined(_DEBUG) || defined(USE_MEM_DEBUG))
  431. struct MemAllocFileLine_t
  432. {
  433. const char *pszFile;
  434. int line;
  435. };
  436. #define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) \
  437. static CUtlMap<void *, MemAllocFileLine_t, int> s_##tag##Allocs( DefLessFunc( void *) ); \
  438. CUtlMap<void *, MemAllocFileLine_t, int> * g_p##tag##Allocs = &s_##tag##Allocs; \
  439. static CThreadFastMutex s_##tag##AllocsMutex; \
  440. CThreadFastMutex * g_p##tag##AllocsMutex = &s_##tag##AllocsMutex; \
  441. const char * g_psz##tag##Alloc = strcpy( (char *)MemAlloc_Alloc( strlen( #tag "Alloc" ) + 1, "intentional leak", 0 ), #tag "Alloc" );
  442. #define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag ) \
  443. extern CUtlMap<void *, MemAllocFileLine_t, int> * g_p##tag##Allocs; \
  444. extern CThreadFastMutex *g_p##tag##AllocsMutex; \
  445. extern const char * g_psz##tag##Alloc;
  446. #define MemAlloc_RegisterExternalAllocation( tag, p, size ) \
  447. if ( !p ) \
  448. ; \
  449. else \
  450. { \
  451. AUTO_LOCK_FM( *g_p##tag##AllocsMutex ); \
  452. MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \
  453. g_pMemAlloc->GetActualDbgInfo( fileLine.pszFile, fileLine.line ); \
  454. if ( fileLine.pszFile != g_psz##tag##Alloc ) \
  455. { \
  456. g_p##tag##Allocs->Insert( p, fileLine ); \
  457. } \
  458. \
  459. MemAlloc_RegisterAllocation( fileLine.pszFile, fileLine.line, size, size, 0); \
  460. }
  461. #define MemAlloc_RegisterExternalDeallocation( tag, p, size ) \
  462. if ( !p ) \
  463. ; \
  464. else \
  465. { \
  466. AUTO_LOCK_FM( *g_p##tag##AllocsMutex ); \
  467. MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \
  468. CUtlMap<void *, MemAllocFileLine_t, int>::IndexType_t iRecordedFileLine = g_p##tag##Allocs->Find( p ); \
  469. if ( iRecordedFileLine != g_p##tag##Allocs->InvalidIndex() ) \
  470. { \
  471. fileLine = (*g_p##tag##Allocs)[iRecordedFileLine]; \
  472. g_p##tag##Allocs->RemoveAt( iRecordedFileLine ); \
  473. } \
  474. \
  475. MemAlloc_RegisterDeallocation( fileLine.pszFile, fileLine.line, size, size, 0); \
  476. }
  477. #else
  478. #define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag )
  479. #define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag )
  480. #define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0)
  481. #define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0)
  482. #endif
  483. //-----------------------------------------------------------------------------
  484. #elif defined( POSIX )
  485. #if defined( OSX )
  486. inline void *memalign(size_t alignment, size_t size) {void *pTmp=NULL; posix_memalign(&pTmp, alignment, size); return pTmp;}
  487. #endif
  488. inline void *_aligned_malloc( size_t nSize, size_t align ) { return memalign( align, nSize ); }
  489. inline void _aligned_free( void *ptr ) { free( ptr ); }
  490. inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName = NULL, int nLine = 0 ) { return malloc( nSize ); }
  491. inline void MemAlloc_Free( void *ptr, const char *pFileName = NULL, int nLine = 0 ) { free( ptr ); }
  492. inline void *MemAlloc_AllocAligned( size_t size, size_t align ) { return memalign( align, size ); }
  493. inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile = NULL, int nLine = 0 ) { return memalign( align, size ); }
  494. inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile = NULL, int nLine = 0 ) { free( pMemBlock ); }
  495. #if defined( OSX )
  496. inline size_t _msize( void *ptr ) { return malloc_size( ptr ); }
  497. #else
  498. inline size_t _msize( void *ptr ) { return malloc_usable_size( ptr ); }
  499. #endif
  500. inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align )
  501. {
  502. void *ptr_new_aligned = memalign( align, size );
  503. if( ptr_new_aligned )
  504. {
  505. size_t old_size = _msize( ptr );
  506. size_t copy_size = ( size < old_size ) ? size : old_size;
  507. memcpy( ptr_new_aligned, ptr, copy_size );
  508. free( ptr );
  509. }
  510. return ptr_new_aligned;
  511. }
  512. #endif // !STEAM && !NO_MALLOC_OVERRIDE
  513. //-----------------------------------------------------------------------------
  514. #if !defined(STEAM) && defined(NO_MALLOC_OVERRIDE)
  515. #include <malloc.h>
  516. #define MEM_ALLOC_CREDIT_(tag) ((void)0)
  517. #define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__)
  518. #define MEM_ALLOC_CREDIT_FUNCTION()
  519. #define MEM_ALLOC_CREDIT_CLASS()
  520. #define MEM_ALLOC_CLASSNAME(type) NULL
  521. #define MemAlloc_PushAllocDbgInfo( pszFile, line )
  522. #define MemAlloc_PopAllocDbgInfo()
  523. #define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
  524. #define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
  525. #define MemAlloc_DumpStats() ((void)0)
  526. #define MemAlloc_CompactHeap() ((void)0)
  527. #define MemAlloc_OutOfMemory() ((void)0)
  528. #define MemAlloc_CompactIncremental() ((void)0)
  529. #define MemAlloc_DumpStatsFileBase( _filename ) ((void)0)
  530. inline bool MemAlloc_CrtCheckMemory() { return true; }
  531. inline void MemAlloc_GlobalMemoryStatus( size_t *pusedMemory, size_t *pfreeMemory )
  532. {
  533. *pusedMemory = 0;
  534. *pfreeMemory = 0;
  535. }
  536. #define MemAlloc_MemoryAllocFailed() 1
  537. #define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag )
  538. #define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0)
  539. #define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0)
  540. #endif // !STEAM && NO_MALLOC_OVERRIDE
  541. //-----------------------------------------------------------------------------
  542. // linux memory tracking via hooks.
  543. #if defined( POSIX ) && !defined( _PS3 )
  544. PLATFORM_INTERFACE void MemoryLogMessage( char const *s ); // throw a message into the memory log
  545. PLATFORM_INTERFACE void EnableMemoryLogging( bool bOnOff );
  546. PLATFORM_INTERFACE void DumpMemoryLog( int nThresh );
  547. PLATFORM_INTERFACE void DumpMemorySummary( void );
  548. PLATFORM_INTERFACE void SetMemoryMark( void );
  549. PLATFORM_INTERFACE void DumpChangedMemory( int nThresh );
  550. // ApproximateProcessMemoryUsage returns the approximate memory footprint of this process.
  551. PLATFORM_INTERFACE size_t ApproximateProcessMemoryUsage( void );
  552. #else
  553. inline void MemoryLogMessage( char const * )
  554. {
  555. }
  556. inline void EnableMemoryLogging( bool )
  557. {
  558. }
  559. inline void DumpMemoryLog( int )
  560. {
  561. }
  562. inline void DumpMemorySummary( void )
  563. {
  564. }
  565. inline void SetMemoryMark( void )
  566. {
  567. }
  568. inline void DumpChangedMemory( int )
  569. {
  570. }
  571. inline size_t ApproximateProcessMemoryUsage( void )
  572. {
  573. return 0;
  574. }
  575. #endif
  576. #endif /* TIER0_MEMALLOC_H */