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.

277 lines
7.3 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // ZONE MEMORY ALLOCATION
  6. //
  7. // There is never any space between memblocks, and there will never be two
  8. // contiguous free memblocks.
  9. //
  10. // The rover can be left pointing at a non-empty block
  11. //
  12. // The zone calls are pretty much only used for small strings and structures,
  13. // all big things are allocated on the hunk.
  14. //===========================================================================//
  15. #include "basetypes.h"
  16. #include "zone.h"
  17. #include "host.h"
  18. #include "tier1/strtools.h"
  19. #include "tier1/utldict.h"
  20. #include "tier0/icommandline.h"
  21. #include "memstack.h"
  22. #include "datacache/idatacache.h"
  23. #include "sys_dll.h"
  24. #include "tier3/tier3.h"
  25. #include "tier0/memalloc.h"
  26. // NOTE: This has to be the last file included!
  27. #include "tier0/memdbgon.h"
  28. #define KB (1024)
  29. #define MB (1024*1024)
  30. #define MINIMUM_WIN_MEMORY (48*MB) // FIXME: copy from sys_dll.cpp, find a common header at some point
  31. // PORTAL 2 SHIPPING CHANGE
  32. // We're sacrificing a little perf (~1% in pathological case) for 12 MB of memory back on X360
  33. // #ifdef _X360
  34. // #define HUNK_USE_16MB_PAGE
  35. // #endif
  36. CMemoryStack g_HunkMemoryStack;
  37. #ifdef HUNK_USE_16MB_PAGE
  38. CMemoryStack g_HunkOverflow;
  39. static bool g_bWarnedOverflow;
  40. #define SIZE_PHYSICAL_HUNK (16*MB)
  41. #endif
  42. const int HUNK_COMMIT_FLOOR = ( IsGameConsole() ? 4/*18*/ : 40 )*MB;
  43. const char *CHunkAllocCredit::s_DbgInfoStack[ DBG_INFO_STACK_DEPTH ];
  44. int CHunkAllocCredit::s_DbgInfoStackDepth = -1;
  45. #if !defined( _CERT )
  46. ConVar hunk_track_allocation_types( "hunk_track_allocation_types", "1", FCVAR_CHEAT );
  47. #else
  48. ConVar hunk_track_allocation_types( "hunk_track_allocation_types", "0", FCVAR_CHEAT );
  49. #endif
  50. CUtlDict<int, int> g_HunkAllocationsByName;
  51. struct hunkalloc_t { int index, size; };
  52. int HunkAllocSortFunc( const void *a, const void *b )
  53. {
  54. const hunkalloc_t *A = (const hunkalloc_t *)a, *B = (const hunkalloc_t *)b;
  55. return ( A->size > B->size ) ? -1 : +1;
  56. }
  57. CON_COMMAND_F( hunk_print_allocations, "", FCVAR_CLIENTCMD_CAN_EXECUTE )
  58. {
  59. Msg( "Hunk allocations:\n");
  60. hunkalloc_t *items = new hunkalloc_t[ g_HunkAllocationsByName.Count() ];
  61. int numItems = 0, total = 0;
  62. for ( int i = g_HunkAllocationsByName.First(); i != g_HunkAllocationsByName.InvalidIndex(); i = g_HunkAllocationsByName.Next( i ) )
  63. {
  64. if ( !g_HunkAllocationsByName.Element( i ) )
  65. continue;
  66. hunkalloc_t item = { i, g_HunkAllocationsByName.Element( i ) };
  67. items[numItems++] = item;
  68. total += item.size;
  69. }
  70. qsort( items, numItems, sizeof( hunkalloc_t ), HunkAllocSortFunc );
  71. Msg( " %55s:%10d\n", "TOTAL:", total );
  72. for ( int i = 0; i < numItems; i++ )
  73. {
  74. Msg( " %55s:%10d\n", g_HunkAllocationsByName.GetElementName( items[i].index ), items[i].size );
  75. }
  76. delete [] items;
  77. #if defined( _X360 )
  78. xBudgetInfo_t budgetInfo;
  79. budgetInfo.BSPSize = total;
  80. XBX_rBudgetInfo( &budgetInfo );
  81. #endif
  82. }
  83. static int GetTargetCacheSize()
  84. {
  85. int nMemLimit = host_parms.memsize - Hunk_Size();
  86. if ( nMemLimit < 0x100000 )
  87. {
  88. nMemLimit = 0x100000;
  89. }
  90. return nMemLimit;
  91. }
  92. /*
  93. ===================
  94. Hunk_AllocName
  95. ===================
  96. */
  97. void *Hunk_AllocName(int size, const char *name, bool bClear)
  98. {
  99. if ( hunk_track_allocation_types.GetBool() )
  100. {
  101. MEM_ALLOC_CREDIT();
  102. if ( !name )
  103. {
  104. name = "unknown";
  105. }
  106. int i = g_HunkAllocationsByName.Find( name );
  107. if ( i == g_HunkAllocationsByName.InvalidIndex() )
  108. {
  109. i = g_HunkAllocationsByName.Insert( name );
  110. g_HunkAllocationsByName[i] = size;
  111. }
  112. else
  113. {
  114. g_HunkAllocationsByName[i] += size;
  115. }
  116. }
  117. void *p = g_HunkMemoryStack.Alloc( size, bClear );
  118. #ifdef _GAMECONSOLE
  119. int overflowAmt = g_HunkMemoryStack.GetCurrentAllocPoint() - HUNK_COMMIT_FLOOR;
  120. if ( ( overflowAmt > 0 ) && ( overflowAmt <= size ) )
  121. Warning( "HUNK OVERFLOW! Map BSP data consuming %d bytes more memory than expected...\n", overflowAmt );
  122. #endif
  123. if ( p )
  124. return p;
  125. #ifdef HUNK_USE_16MB_PAGE
  126. if ( !g_bWarnedOverflow )
  127. {
  128. g_bWarnedOverflow = true;
  129. DevMsg( "Note: Hunk base page exhausted\n" );
  130. }
  131. p = g_HunkOverflow.Alloc( size, bClear );
  132. if ( p )
  133. return p;
  134. #endif
  135. Error( "Engine hunk overflow!\n" );
  136. return NULL;
  137. }
  138. /*
  139. ===================
  140. Hunk_Alloc
  141. ===================
  142. */
  143. int Hunk_LowMark(void)
  144. {
  145. return (int)( g_HunkMemoryStack.GetCurrentAllocPoint() );
  146. }
  147. void Hunk_FreeToLowMark(int mark)
  148. {
  149. Assert( mark < g_HunkMemoryStack.GetSize() );
  150. #ifdef HUNK_USE_16MB_PAGE
  151. g_HunkOverflow.FreeAll( false );
  152. g_bWarnedOverflow = false;
  153. #endif
  154. g_HunkMemoryStack.FreeToAllocPoint( mark, false );
  155. g_HunkAllocationsByName.RemoveAll();
  156. }
  157. int Hunk_MallocSize()
  158. {
  159. #ifdef HUNK_USE_16MB_PAGE
  160. return g_HunkMemoryStack.GetSize() + g_HunkOverflow.GetSize();
  161. #else
  162. return g_HunkMemoryStack.GetSize();
  163. #endif
  164. }
  165. int Hunk_Size()
  166. {
  167. #ifdef HUNK_USE_16MB_PAGE
  168. return g_HunkMemoryStack.GetUsed() + g_HunkOverflow.GetUsed();
  169. #else
  170. return g_HunkMemoryStack.GetUsed();
  171. #endif
  172. }
  173. void Hunk_Print()
  174. {
  175. #ifdef HUNK_USE_16MB_PAGE
  176. Msg( "Total used memory: %d (%d/%d)\n", Hunk_Size(), g_HunkMemoryStack.GetUsed(), g_HunkOverflow.GetUsed() );
  177. Msg( "Total committed memory: %d (%d/%d)\n", Hunk_MallocSize(), g_HunkMemoryStack.GetSize(), g_HunkOverflow.GetSize() );
  178. #else
  179. Msg( "Total used memory: %d\n", Hunk_Size() );
  180. Msg( "Total committed memory: %d\n", Hunk_MallocSize() );
  181. #endif
  182. }
  183. void Hunk_OnMapStart( int nEstimatedBytes )
  184. {
  185. int nToCommit = MAX( nEstimatedBytes, HUNK_COMMIT_FLOOR );
  186. #ifndef HUNK_USE_16MB_PAGE
  187. CMemoryStack *pStack = &g_HunkMemoryStack;
  188. #else
  189. CMemoryStack *pStack = &g_HunkOverflow;
  190. nToCommit -= SIZE_PHYSICAL_HUNK;
  191. #endif
  192. if ( developer.GetBool() )
  193. {
  194. DevMsg( "Hunk_OnMapStart: %d\n", nToCommit );
  195. }
  196. if ( nToCommit > 0 )
  197. {
  198. pStack->CommitSize( nToCommit );
  199. }
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose:
  203. //-----------------------------------------------------------------------------
  204. void Memory_Init( void )
  205. {
  206. MEM_ALLOC_CREDIT();
  207. #ifdef PLATFORM_64BITS
  208. // Seems to need to be larger to not get exhausted on
  209. // 64-bit. Perhaps because of larger pointer sizes.
  210. int nMaxBytes = 128*MB;
  211. #else
  212. int nMaxBytes = 64*MB;
  213. #endif
  214. const int commitIncrement = 64*KB;
  215. #ifndef HUNK_USE_16MB_PAGE
  216. const int nInitialCommit = MIN( HUNK_COMMIT_FLOOR, nMaxBytes );
  217. while ( !g_HunkMemoryStack.Init( "g_HunkMemoryStack", nMaxBytes, commitIncrement, nInitialCommit ) )
  218. {
  219. Warning( "Unable to allocate %d MB of memory, trying %d MB instead\n", nMaxBytes, nMaxBytes/2 );
  220. nMaxBytes /= 2;
  221. if ( nMaxBytes < MINIMUM_WIN_MEMORY )
  222. {
  223. Error( "Failed to allocate minimum memory requirement for game (%d MB)\n", MINIMUM_WIN_MEMORY/MB);
  224. }
  225. }
  226. #else
  227. if ( !g_HunkMemoryStack.InitPhysical( "g_HunkMemoryStack", SIZE_PHYSICAL_HUNK, 4096 ) || !g_HunkOverflow.Init( "g_HunkOverflow", nMaxBytes - SIZE_PHYSICAL_HUNK, commitIncrement, (SIZE_PHYSICAL_HUNK < HUNK_COMMIT_FLOOR ) ? HUNK_COMMIT_FLOOR - SIZE_PHYSICAL_HUNK : 0 ) )
  228. {
  229. Error( "Failed to allocate minimum memory requirement for game (%d MB)\n", nMaxBytes );
  230. }
  231. #endif
  232. g_pDataCache->SetSize( GetTargetCacheSize() );
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Purpose:
  236. //-----------------------------------------------------------------------------
  237. void Memory_Shutdown( void )
  238. {
  239. g_HunkMemoryStack.FreeAll();
  240. // This disconnects the engine data cache
  241. g_pDataCache->SetSize( 0 );
  242. }