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.

708 lines
19 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #if defined( _WIN32 ) && !defined( _X360 )
  7. #define WIN_32_LEAN_AND_MEAN
  8. #include <windows.h>
  9. #define VA_COMMIT_FLAGS MEM_COMMIT
  10. #define VA_RESERVE_FLAGS MEM_RESERVE
  11. #elif defined( _X360 )
  12. #define VA_COMMIT_FLAGS (MEM_COMMIT|MEM_NOZERO|MEM_LARGE_PAGES)
  13. #define VA_RESERVE_FLAGS (MEM_RESERVE|MEM_LARGE_PAGES)
  14. #elif defined( _PS3 )
  15. #include "sys/memory.h"
  16. #include "sys/mempool.h"
  17. #include "sys/process.h"
  18. #include <sys/vm.h>
  19. #endif
  20. #include "tier0/dbg.h"
  21. #include "memstack.h"
  22. #include "utlmap.h"
  23. #include "tier0/memdbgon.h"
  24. #ifdef _WIN32
  25. #pragma warning(disable:4073)
  26. #pragma init_seg(lib)
  27. #endif
  28. static volatile bool bSpewAllocations = false; // TODO: Register CMemoryStacks with g_pMemAlloc, so it can spew a summary
  29. //-----------------------------------------------------------------------------
  30. MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMemoryStack);
  31. //-----------------------------------------------------------------------------
  32. void PrintStatus( void* p )
  33. {
  34. CMemoryStack* pMemoryStack = (CMemoryStack*)p;
  35. pMemoryStack->PrintContents();
  36. }
  37. CMemoryStack::CMemoryStack()
  38. : m_pNextAlloc( NULL )
  39. , m_pCommitLimit( NULL )
  40. , m_pAllocLimit( NULL )
  41. , m_pHighestAllocLimit( NULL )
  42. , m_pBase( NULL )
  43. , m_bRegisteredAllocation( false )
  44. , m_maxSize( 0 )
  45. , m_alignment( 16 )
  46. #ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  47. , m_commitIncrement( 0 )
  48. , m_minCommit( 0 )
  49. #ifdef _PS3
  50. , m_pVirtualMemorySection( NULL )
  51. #endif
  52. #endif
  53. {
  54. AddMemoryInfoCallback( this );
  55. m_pszAllocOwner = strdup( "CMemoryStack unattributed" );
  56. }
  57. //-------------------------------------
  58. CMemoryStack::~CMemoryStack()
  59. {
  60. if ( m_pBase )
  61. Term();
  62. RemoveMemoryInfoCallback( this );
  63. free( m_pszAllocOwner );
  64. }
  65. //-------------------------------------
  66. bool CMemoryStack::Init( const char *pszAllocOwner, unsigned maxSize, unsigned commitIncrement, unsigned initialCommit, unsigned alignment )
  67. {
  68. Assert( !m_pBase );
  69. m_bPhysical = false;
  70. m_maxSize = maxSize;
  71. m_alignment = AlignValue( alignment, 4 );
  72. Assert( m_alignment == alignment );
  73. Assert( m_maxSize > 0 );
  74. SetAllocOwner( pszAllocOwner );
  75. #ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  76. #ifdef _PS3
  77. // Memory can only be committed in page-size increments on PS3
  78. static const unsigned PS3_PAGE_SIZE = 64*1024;
  79. if ( commitSize < PS3_PAGE_SIZE )
  80. commitSize = PS3_PAGE_SIZE;
  81. #endif
  82. if ( commitIncrement != 0 )
  83. {
  84. m_commitIncrement = commitIncrement;
  85. }
  86. unsigned pageSize;
  87. #ifdef _PS3
  88. pageSize = PS3_PAGE_SIZE;
  89. #elif defined( _X360 )
  90. pageSize = 64 * 1024;
  91. #else
  92. SYSTEM_INFO sysInfo;
  93. GetSystemInfo( &sysInfo );
  94. Assert( !( sysInfo.dwPageSize & (sysInfo.dwPageSize-1)) );
  95. pageSize = sysInfo.dwPageSize;
  96. #endif
  97. if ( m_commitIncrement == 0 )
  98. {
  99. m_commitIncrement = pageSize;
  100. }
  101. else
  102. {
  103. m_commitIncrement = AlignValue( m_commitIncrement, pageSize );
  104. }
  105. m_maxSize = AlignValue( m_maxSize, m_commitIncrement );
  106. Assert( m_maxSize % pageSize == 0 && m_commitIncrement % pageSize == 0 && m_commitIncrement <= m_maxSize );
  107. #ifdef _WIN32
  108. m_pBase = (unsigned char *)VirtualAlloc( NULL, m_maxSize, VA_RESERVE_FLAGS, PAGE_NOACCESS );
  109. #else
  110. m_pVirtualMemorySection = g_pMemAlloc->AllocateVirtualMemorySection( m_maxSize );
  111. if ( !m_pVirtualMemorySection )
  112. {
  113. Warning( "AllocateVirtualMemorySection failed( size=%d )\n", m_maxSize );
  114. Assert( 0 );
  115. m_pBase = NULL;
  116. }
  117. else
  118. {
  119. m_pBase = ( byte* ) m_pVirtualMemorySection->GetBaseAddress();
  120. }
  121. #endif
  122. if ( !m_pBase )
  123. {
  124. #if !defined( NO_MALLOC_OVERRIDE )
  125. g_pMemAlloc->OutOfMemory();
  126. #endif
  127. return false;
  128. }
  129. m_pCommitLimit = m_pNextAlloc = m_pBase;
  130. if ( initialCommit )
  131. {
  132. initialCommit = AlignValue( initialCommit, m_commitIncrement );
  133. Assert( initialCommit <= m_maxSize );
  134. bool bInitialCommitSucceeded = false;
  135. #ifdef _WIN32
  136. bInitialCommitSucceeded = !!VirtualAlloc( m_pCommitLimit, initialCommit, VA_COMMIT_FLAGS, PAGE_READWRITE );
  137. #else
  138. m_pVirtualMemorySection->CommitPages( m_pCommitLimit, initialCommit );
  139. bInitialCommitSucceeded = true;
  140. #endif
  141. if ( !bInitialCommitSucceeded )
  142. {
  143. #if !defined( NO_MALLOC_OVERRIDE )
  144. g_pMemAlloc->OutOfMemory( initialCommit );
  145. #endif
  146. return false;
  147. }
  148. m_minCommit = initialCommit;
  149. m_pCommitLimit += initialCommit;
  150. RegisterAllocation();
  151. }
  152. #else
  153. m_pBase = (byte*)MemAlloc_AllocAligned( m_maxSize, alignment ? alignment : 1 );
  154. m_pNextAlloc = m_pBase;
  155. m_pCommitLimit = m_pBase + m_maxSize;
  156. #endif
  157. m_pHighestAllocLimit = m_pNextAlloc;
  158. m_pAllocLimit = m_pBase + m_maxSize;
  159. return ( m_pBase != NULL );
  160. }
  161. //-------------------------------------
  162. #ifdef _GAMECONSOLE
  163. bool CMemoryStack::InitPhysical( const char *pszAllocOwner, uint size, uint nBaseAddrAlignment, uint alignment, uint32 nFlags )
  164. {
  165. m_bPhysical = true;
  166. m_maxSize = m_commitIncrement = size;
  167. m_alignment = AlignValue( alignment, 4 );
  168. SetAllocOwner( pszAllocOwner );
  169. #ifdef _X360
  170. int flags = PAGE_READWRITE | nFlags;
  171. if ( size >= 16*1024*1024 )
  172. {
  173. flags |= MEM_16MB_PAGES;
  174. }
  175. else
  176. {
  177. flags |= MEM_LARGE_PAGES;
  178. }
  179. m_pBase = (unsigned char *)XPhysicalAlloc( m_maxSize, MAXULONG_PTR, nBaseAddrAlignment, flags );
  180. #elif defined (_PS3)
  181. m_pBase = (byte*)nFlags;
  182. m_pBase = (byte*)AlignValue( (uintp)m_pBase, m_alignment );
  183. #else
  184. #pragma error
  185. #endif
  186. Assert( m_pBase );
  187. m_pNextAlloc = m_pBase;
  188. m_pCommitLimit = m_pBase + m_maxSize;
  189. m_pAllocLimit = m_pBase + m_maxSize;
  190. m_pHighestAllocLimit = m_pNextAlloc;
  191. RegisterAllocation();
  192. return ( m_pBase != NULL );
  193. }
  194. #endif
  195. //-------------------------------------
  196. void CMemoryStack::Term()
  197. {
  198. FreeAll();
  199. if ( m_pBase )
  200. {
  201. #ifdef _GAMECONSOLE
  202. if ( m_bPhysical )
  203. {
  204. #if defined( _X360 )
  205. XPhysicalFree( m_pBase );
  206. #elif defined( _PS3 )
  207. #else
  208. #pragma error
  209. #endif
  210. m_pCommitLimit = m_pBase = NULL;
  211. m_maxSize = 0;
  212. RegisterDeallocation(true);
  213. m_bPhysical = false;
  214. return;
  215. }
  216. #endif // _GAMECONSOLE
  217. #ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  218. #if defined(_WIN32)
  219. VirtualFree( m_pBase, 0, MEM_RELEASE );
  220. #else
  221. m_pVirtualMemorySection->Release();
  222. m_pVirtualMemorySection = NULL;
  223. #endif
  224. #else
  225. MemAlloc_FreeAligned( m_pBase );
  226. #endif
  227. m_pBase = NULL;
  228. // Zero these variables to avoid getting misleading mem_dump
  229. // results when m_pBase is NULL.
  230. m_pNextAlloc = NULL;
  231. m_pCommitLimit = NULL;
  232. m_pHighestAllocLimit = NULL;
  233. m_maxSize = 0;
  234. RegisterDeallocation(true);
  235. }
  236. }
  237. //-------------------------------------
  238. int CMemoryStack::GetSize() const
  239. {
  240. if ( m_bPhysical )
  241. return m_maxSize;
  242. #ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  243. return m_pCommitLimit - m_pBase;
  244. #else
  245. return m_maxSize;
  246. #endif
  247. }
  248. //-------------------------------------
  249. bool CMemoryStack::CommitTo( byte *pNextAlloc ) RESTRICT
  250. {
  251. if ( m_bPhysical )
  252. {
  253. return NULL;
  254. }
  255. #ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  256. unsigned char * pNewCommitLimit = AlignValue( pNextAlloc, m_commitIncrement );
  257. ptrdiff_t commitIncrement = pNewCommitLimit - m_pCommitLimit;
  258. if( m_pCommitLimit + commitIncrement > m_pAllocLimit )
  259. {
  260. #if !defined( NO_MALLOC_OVERRIDE )
  261. g_pMemAlloc->OutOfMemory( commitIncrement );
  262. #endif
  263. return false;
  264. }
  265. if ( pNewCommitLimit > m_pCommitLimit )
  266. {
  267. RegisterDeallocation(false);
  268. bool bAllocationSucceeded = false;
  269. #ifdef _WIN32
  270. bAllocationSucceeded = !!VirtualAlloc( m_pCommitLimit, commitIncrement, VA_COMMIT_FLAGS, PAGE_READWRITE );
  271. #else
  272. bAllocationSucceeded = m_pVirtualMemorySection->CommitPages( m_pCommitLimit, commitIncrement );
  273. #endif
  274. if ( !bAllocationSucceeded )
  275. {
  276. #if !defined( NO_MALLOC_OVERRIDE )
  277. g_pMemAlloc->OutOfMemory( commitIncrement );
  278. #endif
  279. return false;
  280. }
  281. m_pCommitLimit = pNewCommitLimit;
  282. RegisterAllocation();
  283. }
  284. else if ( pNewCommitLimit < m_pCommitLimit )
  285. {
  286. if ( m_pNextAlloc > pNewCommitLimit )
  287. {
  288. Warning( "ATTEMPTED TO DECOMMIT OWNED MEMORY STACK SPACE\n" );
  289. pNewCommitLimit = AlignValue( m_pNextAlloc, m_commitIncrement );
  290. }
  291. if ( pNewCommitLimit < m_pCommitLimit )
  292. {
  293. RegisterDeallocation(false);
  294. ptrdiff_t decommitIncrement = m_pCommitLimit - pNewCommitLimit;
  295. #ifdef _WIN32
  296. VirtualFree( pNewCommitLimit, decommitIncrement, MEM_DECOMMIT );
  297. #else
  298. m_pVirtualMemorySection->DecommitPages( pNewCommitLimit, decommitIncrement );
  299. #endif
  300. m_pCommitLimit = pNewCommitLimit;
  301. RegisterAllocation();
  302. }
  303. }
  304. return true;
  305. #else
  306. return false;
  307. #endif
  308. }
  309. // Identify the owner of this memory stack's memory
  310. void CMemoryStack::SetAllocOwner( const char *pszAllocOwner )
  311. {
  312. if ( !pszAllocOwner || !Q_strcmp( m_pszAllocOwner, pszAllocOwner ) )
  313. return;
  314. free( m_pszAllocOwner );
  315. m_pszAllocOwner = strdup( pszAllocOwner );
  316. }
  317. void CMemoryStack::RegisterAllocation()
  318. {
  319. // 'physical' allocations on PS3 come from RSX local memory, so we don't count them here:
  320. if ( IsPS3() && m_bPhysical )
  321. return;
  322. if ( GetSize() )
  323. {
  324. if ( m_bRegisteredAllocation )
  325. Warning( "CMemoryStack: ERROR - mismatched RegisterAllocation/RegisterDeallocation!\n" );
  326. // NOTE: we deliberately don't use MemAlloc_RegisterExternalAllocation. CMemoryStack needs to bypass 'GetActualDbgInfo'
  327. // due to the way it allocates memory: there's just one representative memory address (m_pBase), it grows at unpredictable
  328. // times (in CommitTo, not every Alloc call) and it is freed en-masse (instead of freeing each individual allocation).
  329. MemAlloc_RegisterAllocation( m_pszAllocOwner, 0, GetSize(), GetSize(), 0 );
  330. }
  331. m_bRegisteredAllocation = true;
  332. // Temp memorystack spew: very useful when we crash out of memory
  333. if ( IsGameConsole() && bSpewAllocations ) Msg( "CMemoryStack: %4.1fMB (%s)\n", GetSize()/(float)(1024*1024), m_pszAllocOwner );
  334. }
  335. void CMemoryStack::RegisterDeallocation( bool bShouldSpewSize )
  336. {
  337. // 'physical' allocations on PS3 come from RSX local memory, so we don't count them here:
  338. if ( IsPS3() && m_bPhysical )
  339. return;
  340. if ( GetSize() )
  341. {
  342. if ( !m_bRegisteredAllocation )
  343. Warning( "CMemoryStack: ERROR - mismatched RegisterAllocation/RegisterDeallocation!\n" );
  344. MemAlloc_RegisterDeallocation( m_pszAllocOwner, 0, GetSize(), GetSize(), 0 );
  345. }
  346. m_bRegisteredAllocation = false;
  347. // Temp memorystack spew: very useful when we crash out of memory
  348. if ( bShouldSpewSize && IsGameConsole() && bSpewAllocations ) Msg( "CMemoryStack: %4.1fMB (%s)\n", GetSize()/(float)(1024*1024), m_pszAllocOwner );
  349. }
  350. //-------------------------------------
  351. void CMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit )
  352. {
  353. mark = AlignValue( mark, m_alignment );
  354. byte *pAllocPoint = m_pBase + mark;
  355. Assert( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc );
  356. if ( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc )
  357. {
  358. m_pNextAlloc = pAllocPoint;
  359. #ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  360. if ( bDecommit && !m_bPhysical )
  361. {
  362. CommitTo( MAX( m_pNextAlloc, (m_pBase + m_minCommit) ) );
  363. }
  364. #endif
  365. }
  366. }
  367. //-------------------------------------
  368. void CMemoryStack::FreeAll( bool bDecommit )
  369. {
  370. if ( m_pBase && ( m_pBase < m_pCommitLimit ) )
  371. {
  372. FreeToAllocPoint( 0, bDecommit );
  373. }
  374. }
  375. //-------------------------------------
  376. void CMemoryStack::Access( void **ppRegion, unsigned *pBytes )
  377. {
  378. *ppRegion = m_pBase;
  379. *pBytes = ( m_pNextAlloc - m_pBase);
  380. }
  381. const char* CMemoryStack::GetMemoryName() const
  382. {
  383. return m_pszAllocOwner;
  384. }
  385. size_t CMemoryStack::GetAllocatedBytes() const
  386. {
  387. return GetUsed();
  388. }
  389. size_t CMemoryStack::GetCommittedBytes() const
  390. {
  391. return GetSize();
  392. }
  393. size_t CMemoryStack::GetReservedBytes() const
  394. {
  395. return GetMaxSize();
  396. }
  397. size_t CMemoryStack::GetHighestBytes() const
  398. {
  399. size_t highest = m_pHighestAllocLimit - m_pBase;
  400. return highest;
  401. }
  402. //-------------------------------------
  403. void CMemoryStack::PrintContents() const
  404. {
  405. size_t highest = m_pHighestAllocLimit - m_pBase;
  406. #ifdef PLATFORM_WINDOWS_PC
  407. MEMORY_BASIC_INFORMATION info;
  408. char moduleName[260];
  409. strcpy( moduleName, "unknown module" );
  410. // Because this code is statically linked into each DLL, this function and the PrintStatus
  411. // function will be in the DLL that constructed the CMemoryStack object. We can then
  412. // retrieve the DLL name to give slightly more verbose memory dumps.
  413. if ( VirtualQuery( &PrintStatus, &info, sizeof( info ) ) == sizeof( info ) )
  414. {
  415. GetModuleFileName( (HMODULE) info.AllocationBase, moduleName, _countof( moduleName ) );
  416. moduleName[ _countof( moduleName )-1 ] = 0;
  417. }
  418. Msg( "CMemoryStack %s in %s\n", m_pszAllocOwner, moduleName );
  419. #else
  420. Msg( "CMemoryStack %s\n", m_pszAllocOwner );
  421. #endif
  422. Msg( " Total used memory: %d KB\n", GetUsed() / 1024 );
  423. Msg( " Total committed memory: %d KB\n", GetSize() / 1024 );
  424. Msg( " Max committed memory: %u KB out of %d KB\n", (unsigned)highest / 1024, GetMaxSize() / 1024 );
  425. }
  426. #ifdef _X360
  427. //-----------------------------------------------------------------------------
  428. //
  429. // A memory stack used for allocating physical memory on the 360 (can't commit/decommit)
  430. //
  431. //-----------------------------------------------------------------------------
  432. MEMALLOC_DEFINE_EXTERNAL_TRACKING(CPhysicalMemoryStack);
  433. //-----------------------------------------------------------------------------
  434. // Constructor, destructor
  435. //-----------------------------------------------------------------------------
  436. CPhysicalMemoryStack::CPhysicalMemoryStack() :
  437. m_nAlignment( 16 ), m_nAdditionalFlags( 0 ), m_nUsage( 0 ), m_nPeakUsage( 0 ), m_pLastAllocedChunk( NULL ),
  438. m_nFirstAvailableChunk( 0 ), m_nChunkSizeInBytes( 0 ), m_ExtraChunks( 32, 32 ), m_nFramePeakUsage( 0 )
  439. {
  440. m_InitialChunk.m_pBase = NULL;
  441. m_InitialChunk.m_pNextAlloc = NULL;
  442. m_InitialChunk.m_pAllocLimit = NULL;
  443. }
  444. CPhysicalMemoryStack::~CPhysicalMemoryStack()
  445. {
  446. Term();
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Init, shutdown
  450. //-----------------------------------------------------------------------------
  451. bool CPhysicalMemoryStack::Init( size_t nChunkSizeInBytes, size_t nAlignment, int nInitialChunkCount, uint32 nAdditionalFlags )
  452. {
  453. Assert( !m_InitialChunk.m_pBase );
  454. m_pLastAllocedChunk = NULL;
  455. m_nAdditionalFlags = nAdditionalFlags;
  456. m_nFirstAvailableChunk = 0;
  457. m_nUsage = 0;
  458. m_nFramePeakUsage = 0;
  459. m_nPeakUsage = 0;
  460. m_nAlignment = AlignValue( nAlignment, 4 );
  461. // Chunk size must be aligned to the 360 page size
  462. size_t nInitMemorySize = nChunkSizeInBytes * nInitialChunkCount;
  463. nChunkSizeInBytes = AlignValue( nChunkSizeInBytes, 64 * 1024 );
  464. m_nChunkSizeInBytes = nChunkSizeInBytes;
  465. // Fix up initial chunk count to get at least as much memory as requested
  466. // based on changes to the chunk size owing to page alignment issues
  467. nInitialChunkCount = ( nInitMemorySize + nChunkSizeInBytes - 1 ) / nChunkSizeInBytes;
  468. int nFlags = PAGE_READWRITE | nAdditionalFlags;
  469. int nAllocationSize = m_nChunkSizeInBytes * nInitialChunkCount;
  470. if ( nAllocationSize >= 16*1024*1024 )
  471. {
  472. nFlags |= MEM_16MB_PAGES;
  473. }
  474. else
  475. {
  476. nFlags |= MEM_LARGE_PAGES;
  477. }
  478. m_InitialChunk.m_pBase = (uint8*)XPhysicalAlloc( nAllocationSize, MAXULONG_PTR, 0, nFlags );
  479. if ( !m_InitialChunk.m_pBase )
  480. {
  481. m_InitialChunk.m_pNextAlloc = m_InitialChunk.m_pAllocLimit = NULL;
  482. g_pMemAlloc->OutOfMemory();
  483. return false;
  484. }
  485. m_InitialChunk.m_pNextAlloc = m_InitialChunk.m_pBase;
  486. m_InitialChunk.m_pAllocLimit = m_InitialChunk.m_pBase + nAllocationSize;
  487. MemAlloc_RegisterExternalAllocation( CPhysicalMemoryStack, m_InitialChunk.m_pBase, XPhysicalSize( m_InitialChunk.m_pBase ) );
  488. return true;
  489. }
  490. void CPhysicalMemoryStack::Term()
  491. {
  492. FreeAll();
  493. if ( m_InitialChunk.m_pBase )
  494. {
  495. MemAlloc_RegisterExternalDeallocation( CPhysicalMemoryStack, m_InitialChunk.m_pBase, XPhysicalSize( m_InitialChunk.m_pBase ) );
  496. XPhysicalFree( m_InitialChunk.m_pBase );
  497. m_InitialChunk.m_pBase = m_InitialChunk.m_pNextAlloc = m_InitialChunk.m_pAllocLimit = NULL;
  498. }
  499. }
  500. //-----------------------------------------------------------------------------
  501. // Returns the total allocation size
  502. //-----------------------------------------------------------------------------
  503. size_t CPhysicalMemoryStack::GetSize() const
  504. {
  505. size_t nBaseSize = (intp)m_InitialChunk.m_pAllocLimit - (intp)m_InitialChunk.m_pBase;
  506. return nBaseSize + m_nChunkSizeInBytes * m_ExtraChunks.Count();
  507. }
  508. //-----------------------------------------------------------------------------
  509. // Allocate from the 'overflow' buffers, only happens if the initial allocation
  510. // isn't good enough
  511. //-----------------------------------------------------------------------------
  512. void *CPhysicalMemoryStack::AllocFromOverflow( size_t nSizeInBytes )
  513. {
  514. // Completely full chunks are moved to the front and skipped
  515. int nCount = m_ExtraChunks.Count();
  516. for ( int i = m_nFirstAvailableChunk; i < nCount; ++i )
  517. {
  518. PhysicalChunk_t &chunk = m_ExtraChunks[i];
  519. // Here we can check if a chunk is full and move it to the head
  520. // of the list. We can't do it immediately *after* allocation
  521. // because something may later free up some of the memory
  522. if ( chunk.m_pNextAlloc == chunk.m_pAllocLimit )
  523. {
  524. if ( i > 0 )
  525. {
  526. m_ExtraChunks.FastRemove( i );
  527. m_ExtraChunks.InsertBefore( 0 );
  528. }
  529. ++m_nFirstAvailableChunk;
  530. continue;
  531. }
  532. void *pResult = chunk.m_pNextAlloc;
  533. uint8 *pNextAlloc = chunk.m_pNextAlloc + nSizeInBytes;
  534. if ( pNextAlloc > chunk.m_pAllocLimit )
  535. continue;
  536. chunk.m_pNextAlloc = pNextAlloc;
  537. m_pLastAllocedChunk = &chunk;
  538. return pResult;
  539. }
  540. // No extra chunks to use; add a new one
  541. int i = m_ExtraChunks.AddToTail();
  542. PhysicalChunk_t &chunk = m_ExtraChunks[i];
  543. int nFlags = PAGE_READWRITE | MEM_LARGE_PAGES | m_nAdditionalFlags;
  544. chunk.m_pBase = (uint8*)XPhysicalAlloc( m_nChunkSizeInBytes, MAXULONG_PTR, 0, nFlags );
  545. if ( !chunk.m_pBase )
  546. {
  547. chunk.m_pNextAlloc = chunk.m_pAllocLimit = NULL;
  548. m_pLastAllocedChunk = NULL;
  549. g_pMemAlloc->OutOfMemory();
  550. return NULL;
  551. }
  552. MemAlloc_RegisterExternalAllocation( CPhysicalMemoryStack, chunk.m_pBase, XPhysicalSize( chunk.m_pBase ) );
  553. m_pLastAllocedChunk = &chunk;
  554. chunk.m_pNextAlloc = chunk.m_pBase + nSizeInBytes;
  555. chunk.m_pAllocLimit = chunk.m_pBase + m_nChunkSizeInBytes;
  556. return chunk.m_pBase;
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Allows us to free a portion of the previous allocation
  560. //-----------------------------------------------------------------------------
  561. void CPhysicalMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bUnused )
  562. {
  563. mark = AlignValue( mark, m_nAlignment );
  564. uint8 *pAllocPoint = m_pLastAllocedChunk->m_pBase + mark;
  565. Assert( pAllocPoint >= m_pLastAllocedChunk->m_pBase && pAllocPoint <= m_pLastAllocedChunk->m_pNextAlloc );
  566. if ( pAllocPoint >= m_pLastAllocedChunk->m_pBase && pAllocPoint <= m_pLastAllocedChunk->m_pNextAlloc )
  567. {
  568. m_nUsage -= (intp)m_pLastAllocedChunk->m_pNextAlloc - (intp)pAllocPoint;
  569. m_pLastAllocedChunk->m_pNextAlloc = pAllocPoint;
  570. }
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Free overflow buffers, mark initial buffer as empty
  574. //-----------------------------------------------------------------------------
  575. void CPhysicalMemoryStack::FreeAll( bool bUnused )
  576. {
  577. m_nUsage = 0;
  578. m_nFramePeakUsage = 0;
  579. m_InitialChunk.m_pNextAlloc = m_InitialChunk.m_pBase;
  580. m_pLastAllocedChunk = NULL;
  581. m_nFirstAvailableChunk = 0;
  582. int nCount = m_ExtraChunks.Count();
  583. for ( int i = 0; i < nCount; ++i )
  584. {
  585. PhysicalChunk_t &chunk = m_ExtraChunks[i];
  586. MemAlloc_RegisterExternalDeallocation( CPhysicalMemoryStack, chunk.m_pBase, XPhysicalSize( chunk.m_pBase ) );
  587. XPhysicalFree( chunk.m_pBase );
  588. }
  589. m_ExtraChunks.RemoveAll();
  590. }
  591. //-------------------------------------
  592. void CPhysicalMemoryStack::PrintContents()
  593. {
  594. Msg( "Total used memory: %8d\n", GetUsed() );
  595. Msg( "Peak used memory: %8d\n", GetPeakUsed() );
  596. Msg( "Total allocated memory: %8d\n", GetSize() );
  597. }
  598. #endif // _X360