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.

391 lines
13 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #ifndef DATACACHE_H
  7. #define DATACACHE_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "datamanager.h"
  12. #include "utlhash.h"
  13. #include "mempool.h"
  14. #include "tier0/tslist.h"
  15. #include "datacache_common.h"
  16. #include "tier3/tier3.h"
  17. //-----------------------------------------------------------------------------
  18. //
  19. // Data Cache class declarations
  20. //
  21. //-----------------------------------------------------------------------------
  22. class CDataCache;
  23. class CDataCacheSection;
  24. //-----------------------------------------------------------------------------
  25. struct DataCacheItemData_t
  26. {
  27. const void * pItemData;
  28. unsigned size;
  29. DataCacheClientID_t clientId;
  30. CDataCacheSection * pSection;
  31. };
  32. //-------------------------------------
  33. #define DC_NO_NEXT_LOCKED ((DataCacheItem_t *)-1)
  34. #define DC_MAX_THREADS_FRAMELOCKED 6
  35. struct DataCacheItem_t : DataCacheItemData_t
  36. {
  37. DataCacheItem_t( const DataCacheItemData_t &data )
  38. : DataCacheItemData_t( data ),
  39. hLRU( INVALID_MEMHANDLE )
  40. {
  41. memset( pNextFrameLocked, 0xff, sizeof(pNextFrameLocked) );
  42. }
  43. static DataCacheItem_t *CreateResource( const DataCacheItemData_t &data ) { return new DataCacheItem_t(data); }
  44. static unsigned int EstimatedSize( const DataCacheItemData_t &data ) { return data.size; }
  45. void DestroyResource();
  46. DataCacheItem_t *GetData() { return this; }
  47. unsigned int Size() { return size; }
  48. memhandle_t hLRU;
  49. DataCacheItem_t *pNextFrameLocked[DC_MAX_THREADS_FRAMELOCKED];
  50. DECLARE_FIXEDSIZE_ALLOCATOR_MT(DataCacheItem_t);
  51. };
  52. //-------------------------------------
  53. typedef CDataManager<DataCacheItem_t, DataCacheItemData_t, DataCacheItem_t *, CThreadFastMutex> CDataCacheLRU;
  54. //-----------------------------------------------------------------------------
  55. // CDataCacheSection
  56. //
  57. // Purpose: Implements a sub-section of the global cache. Subsections are
  58. // areas of the cache with thier own memory constraints and common
  59. // management.
  60. //-----------------------------------------------------------------------------
  61. class CDataCacheSection : public IDataCacheSection
  62. {
  63. public:
  64. CDataCacheSection( CDataCache *pSharedCache, IDataCacheClient *pClient, const char *pszName );
  65. ~CDataCacheSection();
  66. IDataCache *GetSharedCache();
  67. IDataCacheClient *GetClient() { return m_pClient; }
  68. const char *GetName() { return szName; }
  69. //--------------------------------------------------------
  70. // IDataCacheSection methods
  71. //--------------------------------------------------------
  72. virtual void SetLimits( const DataCacheLimits_t &limits );
  73. const DataCacheLimits_t &GetLimits();
  74. virtual void SetOptions( unsigned options );
  75. virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL );
  76. inline unsigned GetNumBytes() { return m_status.nBytes; }
  77. inline unsigned GetNumItems() { return m_status.nItems; }
  78. inline unsigned GetNumBytesLocked() { return m_status.nBytesLocked; }
  79. inline unsigned GetNumItemsLocked() { return m_status.nItemsLocked; }
  80. inline unsigned GetNumBytesUnlocked() { return m_status.nBytes - m_status.nBytesLocked; }
  81. inline unsigned GetNumItemsUnlocked() { return m_status.nItems - m_status.nItemsLocked; }
  82. virtual void EnsureCapacity( unsigned nBytes, unsigned nItems = 1 );
  83. //--------------------------------------------------------
  84. virtual bool Add( DataCacheClientID_t clientId, const void *pItemData, unsigned size, DataCacheHandle_t *pHandle );
  85. virtual bool AddEx( DataCacheClientID_t clientId, const void *pItemData, unsigned size, unsigned flags, DataCacheHandle_t *pHandle );
  86. virtual DataCacheHandle_t Find( DataCacheClientID_t clientId );
  87. virtual DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, const void **ppItemData = NULL, unsigned *pItemSize = NULL, bool bNotify = false );
  88. virtual bool IsPresent( DataCacheHandle_t handle );
  89. //--------------------------------------------------------
  90. virtual void *Lock( DataCacheHandle_t handle );
  91. virtual int Unlock( DataCacheHandle_t handle );
  92. virtual void *Get( DataCacheHandle_t handle, bool bFrameLock = false );
  93. virtual void *GetNoTouch( DataCacheHandle_t handle, bool bFrameLock = false );
  94. virtual void GetAndLockMultiple( void **ppData, int nCount, DataCacheHandle_t *pHandles );
  95. virtual void LockMutex();
  96. virtual void UnlockMutex();
  97. //--------------------------------------------------------
  98. virtual int BeginFrameLocking();
  99. virtual bool IsFrameLocking();
  100. virtual void *FrameLock( DataCacheHandle_t handle );
  101. virtual int EndFrameLocking();
  102. //--------------------------------------------------------
  103. virtual int GetLockCount( DataCacheHandle_t handle );
  104. virtual int BreakLock( DataCacheHandle_t handle );
  105. //--------------------------------------------------------
  106. virtual int *GetFrameUnlockCounterPtr();
  107. int m_nFrameUnlockCounter;
  108. //--------------------------------------------------------
  109. virtual bool Touch( DataCacheHandle_t handle );
  110. virtual bool Age( DataCacheHandle_t handle );
  111. //--------------------------------------------------------
  112. virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true );
  113. virtual unsigned Purge( unsigned nBytes );
  114. unsigned PurgeItems( unsigned nItems );
  115. //--------------------------------------------------------
  116. virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT );
  117. virtual void UpdateSize( DataCacheHandle_t handle, unsigned int nNewSize );
  118. virtual unsigned int GetOptions();
  119. private:
  120. friend void DataCacheItem_t::DestroyResource();
  121. virtual void OnAdd( DataCacheClientID_t clientId, DataCacheHandle_t hCacheItem ) {}
  122. virtual DataCacheHandle_t DoFind( DataCacheClientID_t clientId );
  123. virtual void OnRemove( DataCacheClientID_t clientId ) {}
  124. memhandle_t GetFirstUnlockedItem();
  125. memhandle_t GetFirstLockedItem();
  126. memhandle_t GetNextItem( memhandle_t );
  127. DataCacheItem_t *AccessItem( memhandle_t hCurrent );
  128. bool DiscardItem( memhandle_t hItem, DataCacheNotificationType_t type );
  129. bool DiscardItemData( DataCacheItem_t *pItem, DataCacheNotificationType_t type );
  130. void NoteAdd( int size );
  131. void NoteRemove( int size );
  132. void NoteLock( int size );
  133. void NoteUnlock( int size );
  134. void NoteSizeChanged( int oldSize, int newSize );
  135. // for debugging only, under user cvar enabling, causes datacache stress flushing
  136. void ForceFlushDebug( bool bFlush );
  137. struct FrameLock_t
  138. {
  139. int m_iLock;
  140. DataCacheItem_t *m_pFirst;
  141. int m_iThread;
  142. };
  143. //typedef CThreadLocal<FrameLock_t *> CThreadFrameLock;
  144. CDataCacheLRU & m_LRU;
  145. FrameLock_t * m_FrameLocks[MAX_THREADS_SUPPORTED];
  146. DataCacheStatus_t m_status;
  147. DataCacheLimits_t m_limits;
  148. IDataCacheClient * m_pClient;
  149. unsigned m_options;
  150. CDataCache * m_pSharedCache;
  151. char szName[DC_MAX_CLIENT_NAME + 1];
  152. CTSSimpleList<FrameLock_t> m_FreeFrameLocks;
  153. protected:
  154. CThreadFastMutex & m_mutex;
  155. };
  156. //-----------------------------------------------------------------------------
  157. // CDataCacheSectionFastFind
  158. //
  159. // Purpose: A section variant that allows clients to have cache support tracking
  160. // efficiently (a true cache, not just an LRU)
  161. //-----------------------------------------------------------------------------
  162. class CDataCacheSectionFastFind : public CDataCacheSection
  163. {
  164. public:
  165. CDataCacheSectionFastFind(CDataCache *pSharedCache, IDataCacheClient *pClient, const char *pszName )
  166. : CDataCacheSection( pSharedCache, pClient, pszName )
  167. {
  168. m_Handles.Init( 1024 );
  169. }
  170. private:
  171. virtual DataCacheHandle_t DoFind( DataCacheClientID_t clientId );
  172. virtual void OnAdd( DataCacheClientID_t clientId, DataCacheHandle_t hCacheItem );
  173. virtual void OnRemove( DataCacheClientID_t clientId );
  174. CUtlHashFast<DataCacheHandle_t> m_Handles;
  175. };
  176. //-----------------------------------------------------------------------------
  177. // CDataCache
  178. //
  179. // Purpose: The global shared cache. Manages sections and overall budgets.
  180. //
  181. //-----------------------------------------------------------------------------
  182. class CDataCache : public CTier3AppSystem< IDataCache >
  183. {
  184. typedef CTier3AppSystem< IDataCache > BaseClass;
  185. public:
  186. CDataCache();
  187. //--------------------------------------------------------
  188. // IAppSystem methods
  189. //--------------------------------------------------------
  190. virtual bool Connect( CreateInterfaceFn factory );
  191. virtual void Disconnect();
  192. virtual void *QueryInterface( const char *pInterfaceName );
  193. virtual InitReturnVal_t Init();
  194. virtual void Shutdown();
  195. //--------------------------------------------------------
  196. // IDataCache methods
  197. //--------------------------------------------------------
  198. virtual void SetSize( int nMaxBytes );
  199. virtual void SetOptions( unsigned options );
  200. virtual void SetSectionLimits( const char *pszSectionName, const DataCacheLimits_t &limits );
  201. virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL );
  202. //--------------------------------------------------------
  203. virtual IDataCacheSection *AddSection( IDataCacheClient *pClient, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false );
  204. virtual void RemoveSection( const char *pszClientName, bool bCallFlush = true );
  205. virtual IDataCacheSection *FindSection( const char *pszClientName );
  206. //--------------------------------------------------------
  207. void EnsureCapacity( unsigned nBytes );
  208. virtual unsigned Purge( unsigned nBytes );
  209. virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true );
  210. //--------------------------------------------------------
  211. virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT, const char *pszSection = NULL );
  212. //--------------------------------------------------------
  213. inline unsigned GetNumBytes() { return m_status.nBytes; }
  214. inline unsigned GetNumItems() { return m_status.nItems; }
  215. inline unsigned GetNumBytesLocked() { return m_status.nBytesLocked; }
  216. inline unsigned GetNumItemsLocked() { return m_status.nItemsLocked; }
  217. inline unsigned GetNumBytesUnlocked() { return m_status.nBytes - m_status.nBytesLocked; }
  218. inline unsigned GetNumItemsUnlocked() { return m_status.nItems - m_status.nItemsLocked; }
  219. virtual int GetSectionCount( void );
  220. virtual const char *GetSectionName( int iIndex );
  221. private:
  222. //-----------------------------------------------------
  223. friend class CDataCacheSection;
  224. //-----------------------------------------------------
  225. DataCacheItem_t *AccessItem( memhandle_t hCurrent );
  226. bool IsInFlush() { return m_bInFlush; }
  227. int FindSectionIndex( const char *pszSection );
  228. // Utilities used by the data cache report
  229. void OutputItemReport( memhandle_t hItem, void *pXboxData = NULL );
  230. static bool SortMemhandlesBySizeLessFunc( const memhandle_t& lhs, const memhandle_t& rhs );
  231. //-----------------------------------------------------
  232. CDataCacheLRU m_LRU;
  233. DataCacheStatus_t m_status;
  234. CUtlVector<CDataCacheSection *> m_Sections;
  235. bool m_bInFlush;
  236. CThreadFastMutex & m_mutex;
  237. };
  238. //---------------------------------------------------------
  239. extern CDataCache g_DataCache;
  240. //-----------------------------------------------------------------------------
  241. inline DataCacheItem_t *CDataCache::AccessItem( memhandle_t hCurrent )
  242. {
  243. return m_LRU.GetResource_NoLockNoLRUTouch( hCurrent );
  244. }
  245. //-----------------------------------------------------------------------------
  246. inline IDataCache *CDataCacheSection::GetSharedCache()
  247. {
  248. return m_pSharedCache;
  249. }
  250. inline DataCacheItem_t *CDataCacheSection::AccessItem( memhandle_t hCurrent )
  251. {
  252. return m_pSharedCache->AccessItem( hCurrent );
  253. }
  254. // Note: if status updates are moved out of a mutexed section, will need to change these to use interlocked instructions
  255. inline void CDataCacheSection::NoteSizeChanged( int oldSize, int newSize )
  256. {
  257. int nBytes = ( newSize - oldSize );
  258. m_status.nBytes += nBytes;
  259. m_status.nBytesLocked += nBytes;
  260. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, nBytes );
  261. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, nBytes );
  262. }
  263. inline void CDataCacheSection::NoteAdd( int size )
  264. {
  265. m_status.nBytes += size;
  266. m_status.nItems++;
  267. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, size );
  268. ThreadInterlockedIncrement( &m_pSharedCache->m_status.nItems );
  269. }
  270. inline void CDataCacheSection::NoteRemove( int size )
  271. {
  272. m_status.nBytes -= size;
  273. m_status.nItems--;
  274. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, -size );
  275. ThreadInterlockedDecrement( &m_pSharedCache->m_status.nItems );
  276. }
  277. inline void CDataCacheSection::NoteLock( int size )
  278. {
  279. m_status.nBytesLocked += size;
  280. m_status.nItemsLocked++;
  281. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, size );
  282. ThreadInterlockedIncrement( &m_pSharedCache->m_status.nItemsLocked );
  283. }
  284. inline void CDataCacheSection::NoteUnlock( int size )
  285. {
  286. m_status.nBytesLocked -= size;
  287. m_status.nItemsLocked--;
  288. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, -size );
  289. ThreadInterlockedDecrement( &m_pSharedCache->m_status.nItemsLocked );
  290. // something has been unlocked, assume cached pointers are now invalid
  291. m_nFrameUnlockCounter++;
  292. }
  293. //-----------------------------------------------------------------------------
  294. #endif // DATACACHE_H