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.

364 lines
11 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: A fast stack memory allocator that uses virtual memory if available
  4. //
  5. //===========================================================================//
  6. #ifndef MEMSTACK_H
  7. #define MEMSTACK_H
  8. #if defined( _WIN32 )
  9. #pragma once
  10. #endif
  11. #include "tier1/utlvector.h"
  12. #if defined( _WIN32 ) || defined( _PS3 )
  13. #define MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  14. #endif
  15. //-----------------------------------------------------------------------------
  16. typedef unsigned MemoryStackMark_t;
  17. class CMemoryStack : private IMemoryInfo
  18. {
  19. public:
  20. CMemoryStack();
  21. ~CMemoryStack();
  22. bool Init( const char *pszAllocOwner, unsigned maxSize = 0, unsigned commitIncrement = 0, unsigned initialCommit = 0, unsigned alignment = 16 );
  23. #ifdef _GAMECONSOLE
  24. bool InitPhysical( const char *pszAllocOwner, uint size, uint nBaseAddrAlignment, uint alignment = 16, uint32 nAdditionalFlags = 0 );
  25. #endif
  26. void Term();
  27. int GetSize() const;
  28. int GetMaxSize() const ;
  29. int GetUsed() const;
  30. void *Alloc( unsigned bytes, bool bClear = false ) RESTRICT;
  31. MemoryStackMark_t GetCurrentAllocPoint() const;
  32. void FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit = true );
  33. void FreeAll( bool bDecommit = true );
  34. void Access( void **ppRegion, unsigned *pBytes );
  35. void PrintContents() const;
  36. void *GetBase();
  37. const void *GetBase() const { return const_cast<CMemoryStack *>(this)->GetBase(); }
  38. bool CommitSize( int nBytes );
  39. void SetAllocOwner( const char *pszAllocOwner );
  40. private:
  41. bool CommitTo( byte * ) RESTRICT;
  42. void RegisterAllocation();
  43. void RegisterDeallocation( bool bShouldSpew );
  44. byte *m_pNextAlloc; // Current alloc point (m_pNextAlloc - m_pBase == allocated bytes)
  45. byte *m_pCommitLimit; // The current end of the committed memory. On systems without dynamic commit/decommit this is always m_pAllocLimit
  46. byte *m_pAllocLimit; // The top of the allocated address space (m_pBase + m_maxSize)
  47. // Track the highest alloc limit seen.
  48. byte *m_pHighestAllocLimit;
  49. const char* GetMemoryName() const OVERRIDE; // User friendly name for this stack or pool
  50. size_t GetAllocatedBytes() const OVERRIDE; // Number of bytes currently allocated
  51. size_t GetCommittedBytes() const OVERRIDE; // Bytes committed -- may be greater than allocated.
  52. size_t GetReservedBytes() const OVERRIDE; // Bytes reserved -- may be greater than committed.
  53. size_t GetHighestBytes() const OVERRIDE; // The maximum number of bytes allocated or committed.
  54. byte *m_pBase;
  55. bool m_bRegisteredAllocation;
  56. bool m_bPhysical;
  57. char *m_pszAllocOwner;
  58. unsigned m_maxSize; // m_maxSize stores how big the stack can grow. It measures the reservation size.
  59. unsigned m_alignment;
  60. #ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  61. unsigned m_commitIncrement;
  62. unsigned m_minCommit;
  63. #endif
  64. #if defined( MEMSTACK_VIRTUAL_MEMORY_AVAILABLE ) && defined( _PS3 )
  65. IVirtualMemorySection *m_pVirtualMemorySection;
  66. #endif
  67. private:
  68. // Make the assignment operator and copy constructor private and unimplemented.
  69. CMemoryStack& operator=( const CMemoryStack& );
  70. CMemoryStack( const CMemoryStack& );
  71. };
  72. //-------------------------------------
  73. FORCEINLINE void *CMemoryStack::Alloc( unsigned bytes, bool bClear ) RESTRICT
  74. {
  75. Assert( m_pBase );
  76. bytes = MAX( bytes, m_alignment );
  77. bytes = AlignValue( bytes, m_alignment );
  78. void *pResult = m_pNextAlloc;
  79. byte *pNextAlloc = m_pNextAlloc + bytes;
  80. if ( pNextAlloc > m_pCommitLimit )
  81. {
  82. if ( !CommitTo( pNextAlloc ) )
  83. {
  84. return NULL;
  85. }
  86. }
  87. if ( bClear )
  88. {
  89. memset( pResult, 0, bytes );
  90. }
  91. m_pNextAlloc = pNextAlloc;
  92. m_pHighestAllocLimit = Max( m_pNextAlloc, m_pHighestAllocLimit );
  93. return pResult;
  94. }
  95. //-------------------------------------
  96. inline bool CMemoryStack::CommitSize( int nBytes )
  97. {
  98. if ( GetSize() != nBytes )
  99. {
  100. return CommitTo( m_pBase + nBytes );
  101. }
  102. return true;
  103. }
  104. //-------------------------------------
  105. // How big can this memory stack grow? This is equivalent to how many
  106. // bytes are reserved.
  107. inline int CMemoryStack::GetMaxSize() const
  108. {
  109. return m_maxSize;
  110. }
  111. //-------------------------------------
  112. inline int CMemoryStack::GetUsed() const
  113. {
  114. return ( m_pNextAlloc - m_pBase );
  115. }
  116. //-------------------------------------
  117. inline void *CMemoryStack::GetBase()
  118. {
  119. return m_pBase;
  120. }
  121. //-------------------------------------
  122. inline MemoryStackMark_t CMemoryStack::GetCurrentAllocPoint() const
  123. {
  124. return ( m_pNextAlloc - m_pBase );
  125. }
  126. //-----------------------------------------------------------------------------
  127. // The CUtlMemoryStack class:
  128. // A fixed memory class
  129. //-----------------------------------------------------------------------------
  130. template< typename T, typename I, size_t MAX_SIZE, size_t COMMIT_SIZE = 0, size_t INITIAL_COMMIT = 0 >
  131. class CUtlMemoryStack
  132. {
  133. public:
  134. // constructor, destructor
  135. CUtlMemoryStack( int nGrowSize = 0, int nInitSize = 0 ) { m_MemoryStack.Init( "CUtlMemoryStack", MAX_SIZE * sizeof(T), COMMIT_SIZE * sizeof(T), INITIAL_COMMIT * sizeof(T), 4 ); COMPILE_TIME_ASSERT( sizeof(T) % 4 == 0 ); }
  136. CUtlMemoryStack( T* pMemory, int numElements ) { Assert( 0 ); }
  137. // Can we use this index?
  138. bool IsIdxValid( I i ) const { long x=i; return (x >= 0) && (x < m_nAllocated); }
  139. // Specify the invalid ('null') index that we'll only return on failure
  140. static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT
  141. static I InvalidIndex() { return INVALID_INDEX; }
  142. class Iterator_t
  143. {
  144. Iterator_t( I i ) : index( i ) {}
  145. I index;
  146. friend class CUtlMemoryStack<T,I,MAX_SIZE, COMMIT_SIZE, INITIAL_COMMIT>;
  147. public:
  148. bool operator==( const Iterator_t it ) const { return index == it.index; }
  149. bool operator!=( const Iterator_t it ) const { return index != it.index; }
  150. };
  151. Iterator_t First() const { return Iterator_t( m_nAllocated ? 0 : InvalidIndex() ); }
  152. Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( it.index < m_nAllocated ? it.index + 1 : InvalidIndex() ); }
  153. I GetIndex( const Iterator_t &it ) const { return it.index; }
  154. bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
  155. bool IsValidIterator( const Iterator_t &it ) const { long x=it.index; return x >= 0 && x < m_nAllocated; }
  156. Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
  157. // Gets the base address
  158. T* Base() { return (T*)m_MemoryStack.GetBase(); }
  159. const T* Base() const { return (const T*)m_MemoryStack.GetBase(); }
  160. // element access
  161. T& operator[]( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
  162. const T& operator[]( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
  163. T& Element( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
  164. const T& Element( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
  165. // Attaches the buffer to external memory....
  166. void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
  167. // Size
  168. int NumAllocated() const { return m_nAllocated; }
  169. int Count() const { return m_nAllocated; }
  170. // Grows the memory, so that at least allocated + num elements are allocated
  171. void Grow( int num = 1 ) { Assert( num > 0 ); m_nAllocated += num; m_MemoryStack.Alloc( num * sizeof(T) ); }
  172. // Makes sure we've got at least this much memory
  173. void EnsureCapacity( int num ) { Assert( num <= MAX_SIZE ); if ( m_nAllocated < num ) Grow( num - m_nAllocated ); }
  174. // Memory deallocation
  175. void Purge() { m_MemoryStack.FreeAll(); m_nAllocated = 0; }
  176. // is the memory externally allocated?
  177. bool IsExternallyAllocated() const { return false; }
  178. // Set the size by which the memory grows
  179. void SetGrowSize( int size ) { Assert( 0 ); }
  180. // Identify the owner of this memory stack's memory
  181. void SetAllocOwner( const char *pszAllocOwner ) { m_MemoryStack.SetAllocOwner( pszAllocOwner ); }
  182. private:
  183. CMemoryStack m_MemoryStack;
  184. int m_nAllocated;
  185. };
  186. #ifdef _X360
  187. //-----------------------------------------------------------------------------
  188. // A memory stack used for allocating physical memory on the 360
  189. // Usage pattern anticipates we usually never go over the initial allocation
  190. // When we do so, we're ok with slightly slower allocation
  191. //-----------------------------------------------------------------------------
  192. class CPhysicalMemoryStack
  193. {
  194. public:
  195. CPhysicalMemoryStack();
  196. ~CPhysicalMemoryStack();
  197. // The physical memory stack is allocated in chunks. We will initially
  198. // allocate nInitChunkCount chunks, which will always be in memory.
  199. // When FreeAll() is called, it will free down to the initial chunk count
  200. // but not below it.
  201. bool Init( size_t nChunkSizeInBytes, size_t nAlignment, int nInitialChunkCount, uint32 nAdditionalFlags );
  202. void Term();
  203. size_t GetSize() const;
  204. size_t GetPeakUsed() const;
  205. size_t GetUsed() const;
  206. size_t GetFramePeakUsed() const;
  207. MemoryStackMark_t GetCurrentAllocPoint() const;
  208. void FreeToAllocPoint( MemoryStackMark_t mark, bool bUnused = true ); // bUnused is for interface compat with CMemoryStack
  209. void *Alloc( size_t nSizeInBytes, bool bClear = false ) RESTRICT;
  210. void FreeAll( bool bUnused = true ); // bUnused is for interface compat with CMemoryStack
  211. void PrintContents();
  212. private:
  213. void *AllocFromOverflow( size_t nSizeInBytes );
  214. struct PhysicalChunk_t
  215. {
  216. uint8 *m_pBase;
  217. uint8 *m_pNextAlloc;
  218. uint8 *m_pAllocLimit;
  219. };
  220. PhysicalChunk_t m_InitialChunk;
  221. CUtlVector< PhysicalChunk_t > m_ExtraChunks;
  222. size_t m_nUsage;
  223. size_t m_nFramePeakUsage;
  224. size_t m_nPeakUsage;
  225. size_t m_nAlignment;
  226. size_t m_nChunkSizeInBytes;
  227. int m_nFirstAvailableChunk;
  228. int m_nAdditionalFlags;
  229. PhysicalChunk_t *m_pLastAllocedChunk;
  230. };
  231. //-------------------------------------
  232. FORCEINLINE void *CPhysicalMemoryStack::Alloc( size_t nSizeInBytes, bool bClear ) RESTRICT
  233. {
  234. if ( nSizeInBytes )
  235. {
  236. nSizeInBytes = AlignValue( nSizeInBytes, m_nAlignment );
  237. }
  238. else
  239. {
  240. nSizeInBytes = m_nAlignment;
  241. }
  242. // Can't do an allocation bigger than the chunk size
  243. Assert( nSizeInBytes <= m_nChunkSizeInBytes );
  244. void *pResult = m_InitialChunk.m_pNextAlloc;
  245. uint8 *pNextAlloc = m_InitialChunk.m_pNextAlloc + nSizeInBytes;
  246. if ( pNextAlloc <= m_InitialChunk.m_pAllocLimit )
  247. {
  248. m_InitialChunk.m_pNextAlloc = pNextAlloc;
  249. m_pLastAllocedChunk = &m_InitialChunk;
  250. }
  251. else
  252. {
  253. pResult = AllocFromOverflow( nSizeInBytes );
  254. }
  255. m_nUsage += nSizeInBytes;
  256. m_nFramePeakUsage = MAX( m_nUsage, m_nFramePeakUsage );
  257. m_nPeakUsage = MAX( m_nUsage, m_nPeakUsage );
  258. if ( bClear )
  259. {
  260. memset( pResult, 0, nSizeInBytes );
  261. }
  262. return pResult;
  263. }
  264. //-------------------------------------
  265. inline size_t CPhysicalMemoryStack::GetPeakUsed() const
  266. {
  267. return m_nPeakUsage;
  268. }
  269. //-------------------------------------
  270. inline size_t CPhysicalMemoryStack::GetUsed() const
  271. {
  272. return m_nUsage;
  273. }
  274. inline size_t CPhysicalMemoryStack::GetFramePeakUsed() const
  275. {
  276. return m_nFramePeakUsage;
  277. }
  278. inline MemoryStackMark_t CPhysicalMemoryStack::GetCurrentAllocPoint() const
  279. {
  280. Assert( m_pLastAllocedChunk );
  281. return ( m_pLastAllocedChunk->m_pNextAlloc - m_pLastAllocedChunk->m_pBase );
  282. }
  283. #endif // _X360
  284. #endif // MEMSTACK_H