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.

966 lines
40 KiB

  1. //========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Tools for grabbing/dumping the stack at runtime
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef TIER0_STACKSTATS_H
  8. #define TIER0_STACKSTATS_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "tier0/stacktools.h"
  13. #include "tier0/threadtools.h"
  14. #if defined ENABLE_RUNTIME_STACK_TRANSLATION
  15. #define ENABLE_STACK_STATS_GATHERING //uncomment to enable the gathering class
  16. #endif
  17. #if defined ENABLE_STACK_STATS_GATHERING
  18. #include "tier0/valve_off.h"
  19. # include <map> //needed for CCallStackStatsGatherer
  20. # include <vector>
  21. #include "tier0/valve_on.h"
  22. #define CDefaultStatsGathererAllocator std::allocator
  23. #else
  24. template<class _Ty> class CNullStatsGathererAllocator { CNullStatsGathererAllocator( void ) { } };
  25. #define CDefaultStatsGathererAllocator CNullStatsGathererAllocator
  26. #endif
  27. typedef size_t (*FN_DescribeStruct)( uint8 *, size_t );
  28. class CCallStackStatsGatherer_Standardized_t;
  29. struct CCallStackStatsGatherer_FunctionTable_t
  30. {
  31. void (*pfn_GetDumpInfo)( void *, const char *&, size_t &, size_t &, void *&, size_t &, CCallStackStatsGatherer_Standardized_t *&, size_t & );
  32. void (*pfn_PushSubTree)( void *, const CCallStackStatsGatherer_Standardized_t &, const CCallStackStorage & );
  33. void (*pfn_PopSubTree)( void * );
  34. size_t (*pfn_DescribeCallStackStatStruct)( uint8 *, size_t );
  35. void (*pfn_SyncMutexes)( void *, bool );
  36. void *(*pfn_GetEntry)( void *, uint32 );
  37. void (*pfn_ApplyTreeAccessLock)( void *, bool );
  38. void (*pfn_LockEntry)( void *, uint32, bool );
  39. };
  40. //templatized classes are fun, can't really use a base pointer effectively, so we'll have a translator struct and store pointers to instances of the translator function
  41. class CCallStackStatsGatherer_Standardized_t
  42. {
  43. public:
  44. CCallStackStatsGatherer_Standardized_t( void ) {};
  45. CCallStackStatsGatherer_Standardized_t( void *pThis, const CCallStackStatsGatherer_FunctionTable_t &FnTable ) : pGatherer( pThis ), pFunctionTable( &FnTable ) {};
  46. //go ahead and create some helper functions that are likely to be used by helper code
  47. void PushSubTree( const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack = CCallStackStorage() ) const
  48. {
  49. pFunctionTable->pfn_PushSubTree( pGatherer, SubTree, PushStack );
  50. }
  51. inline void PopSubTree( void ) const
  52. {
  53. pFunctionTable->pfn_PopSubTree( pGatherer );
  54. }
  55. void *pGatherer;
  56. const CCallStackStatsGatherer_FunctionTable_t *pFunctionTable;
  57. };
  58. //Designed to be called by an instance of CCallStackStatsGatherer to dump it's data
  59. PLATFORM_INTERFACE bool _CCallStackStatsGatherer_Internal_DumpStatsToFile( const char *szFileName, const CCallStackStatsGatherer_Standardized_t &StatsGatherer, bool bAllowMemoryAllocations );
  60. template <class STATSTRUCT>
  61. class CCallStackStatsGatherer_StructAccessor_Base
  62. {
  63. public:
  64. CCallStackStatsGatherer_StructAccessor_Base( const CCallStackStatsGatherer_Standardized_t &Gatherer, int iEntryIndex ) : m_Gatherer( Gatherer ), m_iEntryIndex( iEntryIndex ) {};
  65. protected:
  66. uint32 m_iEntryIndex; //index of the stat entry we want in the vector. Stored as index as the vector base address can change.
  67. CCallStackStatsGatherer_Standardized_t m_Gatherer; //so we can lock the vector memory in place while manipulating the values
  68. };
  69. class CCallStackStatsGatherer_StatMutexBase
  70. {
  71. public:
  72. void LockEntry( uint32 iEntryIndex, bool bLock ) {} //true to increase lock refcount, false to decrease
  73. };
  74. template <uint32 SHAREDENTRYMUTEXES> //must be a power of 2
  75. class CCallStackStatsGatherer_StatMutexPool
  76. {
  77. public:
  78. void LockEntry( uint32 iEntryIndex, bool bLock )
  79. {
  80. #if defined( ENABLE_STACK_STATS_GATHERING )
  81. COMPILE_TIME_ASSERT( (SHAREDENTRYMUTEXES & (SHAREDENTRYMUTEXES - 1)) == 0 ); //must be a power of 2
  82. if( bLock )
  83. {
  84. m_IndividualEntryMutexes[iEntryIndex & (SHAREDENTRYMUTEXES - 1)].Lock();
  85. }
  86. else
  87. {
  88. m_IndividualEntryMutexes[iEntryIndex & (SHAREDENTRYMUTEXES - 1)].Unlock();
  89. }
  90. #endif
  91. }
  92. protected:
  93. CThreadFastMutex m_IndividualEntryMutexes[SHAREDENTRYMUTEXES];
  94. };
  95. //STATSTRUCT - The structure you'll use to track whatever it is you're tracking.
  96. //CAPTUREDCALLSTACKLENGTH - The maximum length of your stack trace that we'll use to distinguish entries
  97. //STACKACQUISITIONFUNCTION - The function to use to gather the current call stack. GetCallStack() is safe, GetCallStack_Fast() is faster, but has special requirements
  98. //STATMUTEXHANDLER - If you want automatic mutex management for your individual entries, supply a handler here.
  99. // You'll need to not only call GetEntry(), but lock/unlock the entry while accessing it.
  100. //TEMPLATIZEDMEMORYALLOCATOR - We'll need to allocate memory, supply an allocator if you want to manage that
  101. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION = GetCallStack, typename STATMUTEXHANDLER = CCallStackStatsGatherer_StatMutexPool<4>, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR = CDefaultStatsGathererAllocator>
  102. class CCallStackStatsGatherer : public STATMUTEXHANDLER
  103. {
  104. public:
  105. #if !defined( ENABLE_STACK_STATS_GATHERING )
  106. CCallStackStatsGatherer( void )
  107. {
  108. for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i )
  109. m_SingleCallStack[i] = NULL;
  110. }
  111. #endif
  112. CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH] ); //get the entry using some callstack grabbed a while ago. Assumes ALL invalid entries have been nullified
  113. CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ); //same as above, but does the work of nullifying invalid entries
  114. CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) );
  115. CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( uint32 iEntryIndex );
  116. //get the entry index for the caller's current call stack. Pre-nullified entries count as valid entries (and save re-nullification work)
  117. uint32 GetEntryIndex( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ); //index is unchanging, safe to keep and use later (designed for exactly that purpose)
  118. uint32 GetEntryIndex( const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) );
  119. typedef void *(&StackReference)[CAPTUREDCALLSTACKLENGTH];
  120. StackReference GetCallStackForIndex( uint32 iEntryIndex )
  121. {
  122. #if defined( ENABLE_STACK_STATS_GATHERING )
  123. return m_StatEntries[iEntryIndex].m_CallStack;
  124. #else
  125. return m_SingleCallStack;
  126. #endif
  127. }
  128. void GetCallStackForIndex( uint32 iEntryIndex, void *CallStackOut[CAPTUREDCALLSTACKLENGTH] );
  129. size_t NumEntries( void ) const;
  130. bool DumpToFile( const char *szFileName, bool bAllowMemoryAllocations = true );
  131. static const CCallStackStatsGatherer_FunctionTable_t &GetFunctionTable( void );
  132. static void GetDumpInfo( void *pThis, const char *&szStructName, size_t &iCapturedStackLength, size_t &iEntrySizeWithStack, void *&pEntries, size_t &iEntryCount, CCallStackStatsGatherer_Standardized_t *&pSubTrees, size_t &iSubTreeCount );
  133. static void PushSubTree( void *pParent, const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack );
  134. void PushSubTree( CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) );
  135. static void PopSubTree( void *pParent );
  136. static void SyncMutexes( void *pParent, bool bLock ); //true for lock, false for unlock
  137. static void *GetEntry( void *pParent, uint32 iEntryIndex );
  138. static void ApplyTreeAccessLock( void *pParent, bool bLock );
  139. static void LockEntry( void *pParent, uint32 iEntryIndex, bool bLock );
  140. void Reset( void );
  141. CCallStackStatsGatherer_Standardized_t Standardized( void );
  142. operator CCallStackStatsGatherer_Standardized_t( void );
  143. const static FN_GetCallStack StackFunction; //publish the requested acquisition function so you can easily key all your stack gathering to the class instance
  144. const static size_t CapturedCallStackLength;
  145. private:
  146. #pragma pack(push)
  147. #pragma pack(1)
  148. struct StackAndStats_t
  149. {
  150. void *m_CallStack[CAPTUREDCALLSTACKLENGTH];
  151. STATSTRUCT m_Stats;
  152. };
  153. #pragma pack(pop)
  154. typedef CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR> ThisCast;
  155. #if defined( ENABLE_STACK_STATS_GATHERING )
  156. struct IndexMapKey_t
  157. {
  158. IndexMapKey_t( void * const CallStack[CAPTUREDCALLSTACKLENGTH] )
  159. {
  160. m_Hash = 0;
  161. for( int i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i )
  162. {
  163. m_CallStack[i] = CallStack[i];
  164. m_Hash += (uintp)CallStack[i];
  165. }
  166. }
  167. bool operator<( const IndexMapKey_t &key ) const
  168. {
  169. if( m_Hash != key.m_Hash )
  170. return m_Hash < key.m_Hash;
  171. //only here if there's a hash match. Do a full check. Extremely likely to be the exact same call stack. But not 100% guaranteed.
  172. for( int i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i )
  173. {
  174. if( m_CallStack[i] == key.m_CallStack[i] )
  175. {
  176. continue;
  177. }
  178. return m_CallStack[i] < key.m_CallStack[i];
  179. }
  180. return false; //exact same call stack
  181. }
  182. uintp m_Hash;
  183. void *m_CallStack[CAPTUREDCALLSTACKLENGTH];
  184. };
  185. void KeepSubTree( CCallStackStatsGatherer_Standardized_t &SubTree )
  186. {
  187. AUTO_LOCK_FM( m_SubTreeMutex );
  188. for( StoredSubTreeVector_t::iterator treeIter = m_StoredSubTrees.begin(); treeIter != m_StoredSubTrees.end(); ++treeIter )
  189. {
  190. if( SubTree.pGatherer == treeIter->pGatherer )
  191. return;
  192. }
  193. //Warning( "Storing subtree\n" );
  194. m_StoredSubTrees.push_back( SubTree );
  195. }
  196. uint32 PatchInSubTrees( void * const CallStackIn[CAPTUREDCALLSTACKLENGTH], void *CallStackOut[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries )
  197. {
  198. if( iValidEntries > CAPTUREDCALLSTACKLENGTH )
  199. {
  200. iValidEntries = CAPTUREDCALLSTACKLENGTH;
  201. }
  202. AUTO_LOCK_FM( m_SubTreeMutex );
  203. if( m_PushedSubTrees.size() == 0 )
  204. {
  205. memcpy( CallStackOut, CallStackIn, sizeof( void * ) * iValidEntries );
  206. return iValidEntries;
  207. }
  208. unsigned long iThreadID = ThreadGetCurrentId();
  209. PushedSubTreeVector_t::reverse_iterator treeIter;
  210. for( treeIter = m_PushedSubTrees.rbegin(); treeIter != m_PushedSubTrees.rend(); ++treeIter )
  211. {
  212. if( treeIter->iThreadID == iThreadID )
  213. {
  214. break;
  215. }
  216. }
  217. if( treeIter == m_PushedSubTrees.rend() )
  218. {
  219. memcpy( CallStackOut, CallStackIn, sizeof( void * ) * iValidEntries );
  220. return iValidEntries;
  221. }
  222. //char szTemp[4096];
  223. //TranslateStackInfo( CallStackIn, CAPTUREDCALLSTACKLENGTH, szTemp, sizeof( szTemp ), "\n\t" );
  224. //Warning( "Attempting to link trees:\n=======================ONE=======================\n\t%s\n", szTemp );
  225. //TranslateStackInfo( treeIter->Stack, CAPTUREDCALLSTACKLENGTH, szTemp, sizeof( szTemp ), "\n\t" );
  226. //Warning( "=======================TWO=======================\n\t%s\n", szTemp );
  227. void *pMatchAddress = treeIter->Stack[1]; //while the first entry is where the actual push was made. The second entry is the first that is matchable in most cases
  228. uint32 i;
  229. for( i = 0; i < iValidEntries; ++i )
  230. {
  231. if( CallStackIn[i] == pMatchAddress )
  232. {
  233. //TranslateStackInfo( CallStackIn, i, szTemp, sizeof( szTemp ), "\n\t" );
  234. //Warning( "======================MATCH======================\n\t%s\n", szTemp );
  235. CallStackOut[i] = treeIter->tree.pGatherer; //tag this entry as leading into the sub-tree
  236. KeepSubTree( treeIter->tree ); //store the sub-tree forever
  237. return i + 1;
  238. }
  239. CallStackOut[i] = CallStackIn[i];
  240. }
  241. return iValidEntries;
  242. //Warning( "=======================END=======================\n" );
  243. }
  244. struct StatIndex_t
  245. {
  246. StatIndex_t( void ) : m_Index((unsigned int)-1) {};
  247. unsigned int m_Index;
  248. };
  249. typedef std::vector<StackAndStats_t, TEMPLATIZEDMEMORYALLOCATOR<StackAndStats_t> > StatVector_t;
  250. typedef std::map< IndexMapKey_t, StatIndex_t, std::less<IndexMapKey_t>, TEMPLATIZEDMEMORYALLOCATOR<std::pair<const IndexMapKey_t, StatIndex_t> > > IndexMap_t;
  251. typedef typename IndexMap_t::iterator IndexMapIter_t;
  252. typedef typename IndexMap_t::value_type IndexMapEntry_t;
  253. StatVector_t m_StatEntries;
  254. IndexMap_t m_IndexMap;
  255. struct PushedSubTree_t
  256. {
  257. unsigned long iThreadID;
  258. CCallStackStatsGatherer_Standardized_t tree;
  259. void *Stack[CAPTUREDCALLSTACKLENGTH];
  260. };
  261. typedef std::vector<PushedSubTree_t, TEMPLATIZEDMEMORYALLOCATOR<PushedSubTree_t> > PushedSubTreeVector_t;
  262. PushedSubTreeVector_t m_PushedSubTrees;
  263. typedef std::vector<CCallStackStatsGatherer_Standardized_t, TEMPLATIZEDMEMORYALLOCATOR<CCallStackStatsGatherer_Standardized_t> > StoredSubTreeVector_t;
  264. StoredSubTreeVector_t m_StoredSubTrees;
  265. CThreadFastMutex m_IndexMapMutex;
  266. CThreadFastMutex m_SubTreeMutex;
  267. //only for locking the memory in place, locked for write when the entry addresses might change.
  268. //Locked for read when you've claimed you're manipulating a value.
  269. //You're on your own for making sure two threads don't access the same index simultaneously
  270. CThreadRWLock m_StatEntryLock;
  271. #else //#if defined( ENABLE_STACK_STATS_GATHERING )
  272. STATSTRUCT m_SingleEntry; //the class is disabled, we'll always return this same struct
  273. void *m_SingleCallStack[CAPTUREDCALLSTACKLENGTH];
  274. static size_t NULL_DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) { return 0; }
  275. #endif //#if defined( ENABLE_STACK_STATS_GATHERING )
  276. };
  277. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  278. const FN_GetCallStack CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::StackFunction = STACKACQUISITIONFUNCTION;
  279. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  280. const size_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::CapturedCallStackLength = CAPTUREDCALLSTACKLENGTH;
  281. #if defined( ENABLE_STACK_STATS_GATHERING )
  282. class CallStackStatStructDescFuncs;
  283. PLATFORM_INTERFACE size_t _CCallStackStatsGatherer_Write_FieldDescriptions( CallStackStatStructDescFuncs *pFieldDescriptions, uint8 *pWriteBuffer, size_t iWriteBufferSize );
  284. //PLATFORM_INTERFACE size_t _CCallStackStatsGatherer_Write_FieldMergeScript( CallStackStatStructDescFuncs *pFieldDescriptions, CallStackStatStructDescFuncs::MergeScript_Language scriptMergeLanguage, uint8 *pWriteBuffer, size_t iWriteBufferSize );
  285. #define DECLARE_CALLSTACKSTATSTRUCT() static const char *STATSTRUCTSTRINGNAME;\
  286. static size_t DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength );
  287. #define BEGIN_STATSTRUCTDESCRIPTION( className ) const char *className::STATSTRUCTSTRINGNAME = #className;\
  288. size_t className::DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) {\
  289. size_t iWroteBytes = 0;
  290. #define END_STATSTRUCTDESCRIPTION() return iWroteBytes; }
  291. #define DECLARE_CALLSTACKSTATSTRUCT_FIELDDESCRIPTION() static CallStackStatStructDescFuncs *GetStatStructFieldDescriptions( void );
  292. #define BEGIN_STATSTRUCTFIELDDESCRIPTION( className ) CallStackStatStructDescFuncs * className::GetStatStructFieldDescriptions( void ) {\
  293. typedef className ThisStruct;\
  294. CallStackStatStructDescFuncs *_pHeadLinkage = NULL;\
  295. CallStackStatStructDescFuncs **_pLinkageHelperVar = &_pHeadLinkage;
  296. #define _DEFINE_STATSTRUCTFIELD_VARNAME( varName, fieldName, fieldStruct, fieldParmsInParentheses ) static fieldStruct varName##_desc##fieldParmsInParentheses;\
  297. varName##_desc.m_szFieldName = #fieldName;\
  298. varName##_desc.m_iFieldOffset = (size_t)(&((ThisStruct *)NULL)->fieldName);\
  299. varName##_desc.m_pNext = NULL;\
  300. *_pLinkageHelperVar = &varName##_desc;\
  301. _pLinkageHelperVar = &varName##_desc.m_pNext;
  302. #define DEFINE_STATSTRUCTFIELD( fieldName, fieldStruct, fieldParmsInParentheses ) _DEFINE_STATSTRUCTFIELD_VARNAME( fieldName, fieldName, fieldStruct, fieldParmsInParentheses )
  303. #define DEFINE_STATSTRUCTFIELD_ARRAYENTRY( arrayName, arrayIndex, fieldStruct, fieldParmsInParentheses ) _DEFINE_STATSTRUCTFIELD_VARNAME( arrayName##_##arrayIndex, arrayName##[##arrayIndex##], fieldStruct, fieldParmsInParentheses )
  304. #define END_STATSTRUCTFIELDDESCRIPTION() static CallStackStatStructDescFuncs *s_pHeadStruct = _pHeadLinkage;\
  305. return s_pHeadStruct; }
  306. #define WRITE_STATSTRUCT_FIELDDESCRIPTION() iWroteBytes += _CCallStackStatsGatherer_Write_FieldDescriptions( GetStatStructFieldDescriptions(), pDescribeWriteBuffer + iWroteBytes, iDescribeMaxLength - iWroteBytes );
  307. //#define WRITE_STATSTRUCT_FIELDMERGESCRIPT( scriptMergeLanguage ) iWroteBytes += _CCallStackStatsGatherer_Write_FieldMergeScript( GetStatStructFieldDescriptions(), CallStackStatStructDescFuncs::scriptMergeLanguage, pDescribeWriteBuffer + iWroteBytes, iDescribeMaxLength - iWroteBytes );
  308. #else //#if defined( ENABLE_STACK_STATS_GATHERING )
  309. #define DECLARE_CALLSTACKSTATSTRUCT()
  310. #define BEGIN_STATSTRUCTDESCRIPTION( className )
  311. #define END_STATSTRUCTDESCRIPTION()
  312. #define DECLARE_CALLSTACKSTATSTRUCT_FIELDDESCRIPTION()
  313. #define BEGIN_STATSTRUCTFIELDDESCRIPTION( className )
  314. #define DEFINE_STATSTRUCTFIELD( fieldName, fieldStruct, fieldParmsInParentheses )
  315. #define END_STATSTRUCTFIELDDESCRIPTION()
  316. #define WRITE_STATSTRUCT_FIELDDESCRIPTION()
  317. //#define WRITE_STATSTRUCT_FIELDMERGESCRIPT( scriptMergeLanguage )
  318. #endif //#if defined( ENABLE_STACK_STATS_GATHERING )
  319. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  320. CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH] ) //get the entry using some callstack grabbed a while ago. Assumes ALL invalid entries have been nullified
  321. {
  322. #if defined( ENABLE_STACK_STATS_GATHERING )
  323. return GetEntry( GetEntryIndex( CallStack ) );
  324. #else
  325. return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 );
  326. #endif
  327. }
  328. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  329. CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ) //same as above, but does the work of nullifying invalid entries
  330. {
  331. #if defined( ENABLE_STACK_STATS_GATHERING )
  332. void *CleanedCallStack[CAPTUREDCALLSTACKLENGTH];
  333. size_t i;
  334. for( i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i )
  335. {
  336. CleanedCallStack[i] = CallStack[i];
  337. }
  338. for( ; i < CAPTUREDCALLSTACKLENGTH; ++i )
  339. {
  340. CleanedCallStack[i] = NULL;
  341. }
  342. return GetEntry( GetEntryIndex( CleanedCallStack ) );
  343. #else
  344. return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 );
  345. #endif
  346. }
  347. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  348. CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( const CCallStackStorage &PushStack )
  349. {
  350. #if defined( ENABLE_STACK_STATS_GATHERING )
  351. COMPILE_TIME_ASSERT( CAPTUREDCALLSTACKLENGTH <= ARRAYSIZE( PushStack.pStack ) );
  352. return GetEntry( GetEntryIndex( PushStack.pStack, PushStack.iValidEntries ) );
  353. #else
  354. return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 );
  355. #endif
  356. }
  357. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  358. uint32 CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntryIndex( const CCallStackStorage &PushStack )
  359. {
  360. #if defined( ENABLE_STACK_STATS_GATHERING )
  361. COMPILE_TIME_ASSERT( CAPTUREDCALLSTACKLENGTH <= ARRAYSIZE( PushStack.pStack ) );
  362. return GetEntryIndex( PushStack.pStack, PushStack.iValidEntries );
  363. #else
  364. return 0;
  365. #endif
  366. }
  367. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  368. CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( uint32 iEntryIndex )
  369. {
  370. #if defined( ENABLE_STACK_STATS_GATHERING )
  371. return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), iEntryIndex );
  372. #else
  373. return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 );
  374. #endif
  375. }
  376. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  377. uint32 CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntryIndex( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ) //index is unchanging, safe to keep and use later (designed for exactly that purpose)
  378. {
  379. #if defined( ENABLE_STACK_STATS_GATHERING )
  380. AUTO_LOCK_FM( m_IndexMapMutex );
  381. std::pair<IndexMapIter_t, bool> indexMapIter;
  382. void *PatchedStack[CAPTUREDCALLSTACKLENGTH];
  383. //if we have a sub-tree. We'll be splicing it into the original call stack as if it were a return address. Then patching that when we interpret the results later
  384. //A stack with a sub-tree along the line is treated as distinctly different than one without a sub-tree
  385. iValidEntries = PatchInSubTrees( CallStack, PatchedStack, iValidEntries );
  386. Assert( iValidEntries <= CAPTUREDCALLSTACKLENGTH );
  387. for( int i = iValidEntries; i < CAPTUREDCALLSTACKLENGTH; ++i )
  388. {
  389. PatchedStack[i] = NULL;
  390. }
  391. indexMapIter = m_IndexMap.insert( IndexMapEntry_t( IndexMapKey_t( PatchedStack ), StatIndex_t() ) );
  392. if( indexMapIter.first->second.m_Index == -1 )
  393. {
  394. m_StatEntryLock.LockForWrite();
  395. indexMapIter.first->second.m_Index = (unsigned int)m_StatEntries.size();
  396. m_StatEntries.push_back( StackAndStats_t() );
  397. memcpy( m_StatEntries[indexMapIter.first->second.m_Index].m_CallStack, PatchedStack, sizeof( void * ) * CAPTUREDCALLSTACKLENGTH );
  398. m_StatEntryLock.UnlockWrite();
  399. }
  400. return indexMapIter.first->second.m_Index;
  401. #else
  402. return 0;
  403. #endif
  404. }
  405. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  406. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetCallStackForIndex( uint32 iEntryIndex, void *CallStackOut[CAPTUREDCALLSTACKLENGTH] )
  407. {
  408. #if defined( ENABLE_STACK_STATS_GATHERING )
  409. m_StatEntryLock.LockForRead();
  410. for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i )
  411. {
  412. CallStackOut[i] = m_StatEntries[iEntryIndex].m_CallStack[i];
  413. }
  414. m_StatEntryLock.UnlockRead();
  415. #else
  416. for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i )
  417. CallStackOut[i] = NULL;
  418. #endif
  419. }
  420. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  421. size_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::NumEntries( void ) const
  422. {
  423. #if defined( ENABLE_STACK_STATS_GATHERING )
  424. return m_StatEntries.size();
  425. #else
  426. return 0;
  427. #endif
  428. }
  429. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  430. bool CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::DumpToFile( const char *szFileName, bool bAllowMemoryAllocations )
  431. {
  432. #if defined( ENABLE_STACK_STATS_GATHERING )
  433. CCallStackStatsGatherer_Standardized_t StandardThis = Standardized();
  434. SyncMutexes( this, true );
  435. bool bRetVal = _CCallStackStatsGatherer_Internal_DumpStatsToFile( szFileName, StandardThis, bAllowMemoryAllocations );
  436. SyncMutexes( this, false );
  437. return bRetVal;
  438. #else
  439. return false;
  440. #endif
  441. }
  442. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  443. const CCallStackStatsGatherer_FunctionTable_t &CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetFunctionTable( void )
  444. {
  445. static CCallStackStatsGatherer_FunctionTable_t retVal =
  446. { GetDumpInfo,
  447. PushSubTree,
  448. PopSubTree,
  449. #if defined( ENABLE_STACK_STATS_GATHERING )
  450. STATSTRUCT::DescribeCallStackStatStruct,
  451. #else
  452. NULL_DescribeCallStackStatStruct,
  453. #endif
  454. SyncMutexes,
  455. GetEntry,
  456. ApplyTreeAccessLock,
  457. LockEntry };
  458. return retVal;
  459. }
  460. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  461. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetDumpInfo( void *pThis, const char *&szStructName, size_t &iCapturedStackLength, size_t &iEntrySizeWithStack, void *&pEntries, size_t &iEntryCount, CCallStackStatsGatherer_Standardized_t *&pSubTrees, size_t &iSubTreeCount )
  462. {
  463. ThisCast *pThisCast = (ThisCast *)pThis;
  464. iCapturedStackLength = CAPTUREDCALLSTACKLENGTH;
  465. iEntrySizeWithStack = sizeof( CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::StackAndStats_t );
  466. #if defined( ENABLE_STACK_STATS_GATHERING )
  467. szStructName = STATSTRUCT::STATSTRUCTSTRINGNAME;
  468. iEntryCount = pThisCast->m_StatEntries.size();
  469. pEntries = iEntryCount > 0 ? &pThisCast->m_StatEntries[0] : NULL;
  470. iSubTreeCount = pThisCast->m_StoredSubTrees.size();
  471. pSubTrees = iSubTreeCount > 0 ? &pThisCast->m_StoredSubTrees[0] : NULL;
  472. #else
  473. szStructName = "";
  474. iEntryCount = 0;
  475. pEntries = NULL;
  476. iSubTreeCount = 0;
  477. pSubTrees = NULL;
  478. #endif
  479. }
  480. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  481. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PushSubTree( void *pParent, const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack )
  482. {
  483. #if defined( ENABLE_STACK_STATS_GATHERING )
  484. ThisCast *pParentCast = (ThisCast *)pParent;
  485. PushedSubTree_t pushVal;
  486. pushVal.iThreadID = ThreadGetCurrentId();
  487. pushVal.tree = SubTree;
  488. memcpy( pushVal.Stack, PushStack.pStack, MIN( CAPTUREDCALLSTACKLENGTH, PushStack.iValidEntries ) * sizeof( void * ) );
  489. for( int i = PushStack.iValidEntries; i < CAPTUREDCALLSTACKLENGTH; ++i )
  490. {
  491. pushVal.Stack[i] = NULL;
  492. }
  493. pParentCast->m_SubTreeMutex.Lock();
  494. pParentCast->m_PushedSubTrees.push_back( pushVal );
  495. pParentCast->m_SubTreeMutex.Unlock();
  496. #endif
  497. }
  498. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  499. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PushSubTree( CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStorage &PushStack )
  500. {
  501. #if defined( ENABLE_STACK_STATS_GATHERING )
  502. CCallStackStatsGatherer_Standardized_t StandardThis = Standardized();
  503. Parent.PushSubTree( StandardThis, PushStack );
  504. #endif
  505. }
  506. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  507. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PopSubTree( void *pParent )
  508. {
  509. #if defined( ENABLE_STACK_STATS_GATHERING )
  510. ThisCast *pParentCast = (ThisCast *)pParent;
  511. pParentCast->m_SubTreeMutex.Lock();
  512. unsigned long iThreadID = ThreadGetCurrentId();
  513. for( PushedSubTreeVector_t::reverse_iterator treeIter = pParentCast->m_PushedSubTrees.rbegin(); treeIter != pParentCast->m_PushedSubTrees.rend(); ++treeIter )
  514. {
  515. if( treeIter->iThreadID == iThreadID )
  516. {
  517. ++treeIter; //[24.4.1/1] &*(reverse_iterator(i)) == &*(i - 1)
  518. PushedSubTreeVector_t::iterator eraseIter = treeIter.base();
  519. pParentCast->m_PushedSubTrees.erase(eraseIter);
  520. break;
  521. }
  522. }
  523. pParentCast->m_SubTreeMutex.Unlock();
  524. #endif
  525. }
  526. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  527. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::SyncMutexes( void *pParent, bool bLock ) //true for lock, false for unlock
  528. {
  529. #if defined( ENABLE_STACK_STATS_GATHERING )
  530. ThisCast *pParentCast = (ThisCast *)pParent;
  531. if( bLock )
  532. {
  533. pParentCast->m_IndexMapMutex.Lock();
  534. pParentCast->m_SubTreeMutex.Lock();
  535. for( StoredSubTreeVector_t::iterator treeIter = pParentCast->m_StoredSubTrees.begin(); treeIter != pParentCast->m_StoredSubTrees.end(); ++treeIter )
  536. {
  537. treeIter->pFunctionTable->pfn_SyncMutexes( treeIter->pGatherer, true );
  538. }
  539. }
  540. else
  541. {
  542. for( StoredSubTreeVector_t::iterator treeIter = pParentCast->m_StoredSubTrees.begin(); treeIter != pParentCast->m_StoredSubTrees.end(); ++treeIter )
  543. {
  544. treeIter->pFunctionTable->pfn_SyncMutexes( treeIter->pGatherer, false );
  545. }
  546. pParentCast->m_IndexMapMutex.Unlock();
  547. pParentCast->m_SubTreeMutex.Unlock();
  548. }
  549. #endif
  550. }
  551. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  552. void *CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void *pParent, uint32 iEntryIndex )
  553. {
  554. ThisCast *pParentCast = (ThisCast *)pParent;
  555. #if defined( ENABLE_STACK_STATS_GATHERING )
  556. return &pParentCast->m_StatEntries[iEntryIndex].m_Stats;
  557. #else
  558. return &pParentCast->m_SingleEntry;
  559. #endif
  560. }
  561. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  562. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::ApplyTreeAccessLock( void *pParent, bool bLock )
  563. {
  564. #if defined( ENABLE_STACK_STATS_GATHERING )
  565. ThisCast *pParentCast = (ThisCast *)pParent;
  566. if( bLock )
  567. {
  568. pParentCast->m_StatEntryLock.LockForRead();
  569. }
  570. else
  571. {
  572. pParentCast->m_StatEntryLock.UnlockRead();
  573. }
  574. #endif
  575. }
  576. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  577. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::LockEntry( void *pParent, uint32 iEntryIndex, bool bLock )
  578. {
  579. #if defined( ENABLE_STACK_STATS_GATHERING )
  580. ThisCast *pParentCast = (ThisCast *)pParent;
  581. pParentCast->STATMUTEXHANDLER::LockEntry( iEntryIndex, bLock );
  582. #endif
  583. }
  584. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  585. void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::Reset( void )
  586. {
  587. #if defined( ENABLE_STACK_STATS_GATHERING )
  588. m_StatEntryLock.LockForWrite();
  589. m_IndexMapMutex.Lock();
  590. m_SubTreeMutex.Lock();
  591. m_StatEntries.clear();
  592. m_IndexMap.clear();
  593. m_StoredSubTrees.clear();
  594. m_SubTreeMutex.Unlock();
  595. m_IndexMapMutex.Unlock();
  596. m_StatEntryLock.UnlockWrite();
  597. #endif
  598. }
  599. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  600. CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::operator CCallStackStatsGatherer_Standardized_t( void )
  601. {
  602. return CCallStackStatsGatherer_Standardized_t( this, GetFunctionTable() );
  603. }
  604. template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR>
  605. CCallStackStatsGatherer_Standardized_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::Standardized( void )
  606. {
  607. return CCallStackStatsGatherer_Standardized_t( this, GetFunctionTable() );
  608. }
  609. class PLATFORM_CLASS CallStackStatStructDescFuncs
  610. {
  611. public:
  612. //description file format
  613. //1 byte version per entry. Assuming that the field will get more descriptive over time, reserving this now.
  614. virtual size_t DescribeField( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) = 0;
  615. enum MergeScript_Language
  616. {
  617. SSMSL_Squirrel, //Only support squirrel for now, theoretically expandable to any vscript supported language
  618. };
  619. #if 0 //embedded script handling not ready yet
  620. //this is expected to write a piece of script code into the body of a function that will merge two values of this type
  621. //The function will have two parameters, "mergeTo", and "mergeFrom". Both are tables with your field defined by name
  622. //So, an example to merge an integer count defined as "foo" in the stack struct would look like this "mergeTo.foo += mergeFrom.foo\n"
  623. virtual size_t DescribeMergeOperation( MergeScript_Language scriptLanguage, uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) = 0;
  624. #endif
  625. //reserve your description field versions here to avoid stomping others
  626. enum DescribeFieldVersions_t
  627. {
  628. DFV_BasicStatStructFieldTypes_t, //Format: 1 byte BasicStatStructFieldTypes_t type, 4 byte field offset, null terminated string field name
  629. };
  630. const char *m_szFieldName;
  631. size_t m_iFieldOffset;
  632. CallStackStatStructDescFuncs *m_pNext; //needed for how the description macros are laid out. Couldn't figure out a way to store the static struct instances as a static array
  633. };
  634. enum StatStructDescription_LumpID
  635. {
  636. SSDLID_UNKNOWN,
  637. SSDLID_STATICINTERPRETER,
  638. SSDLID_FIELDDESC,
  639. SSDLID_EMBEDDEDSCRIPT,
  640. SSDLID_COUNT,
  641. SSDLID_FORCE_UINT32 = 0xFFFFFFFF,
  642. };
  643. enum BasicStatStructFieldTypes_t
  644. {
  645. BSSFT_UNKNOWN,
  646. BSSFT_BOOL,
  647. BSSFT_INT8,
  648. BSSFT_UINT8,
  649. BSSFT_INT16,
  650. BSSFT_UINT16,
  651. BSSFT_INT32,
  652. BSSFT_UINT32,
  653. BSSFT_INT64,
  654. BSSFT_UINT64,
  655. BSSFT_FLOAT,
  656. BSSFT_DOUBLE,
  657. BSSFT_VECTOR2D,
  658. BSSFT_VECTOR3D,
  659. BSSFT_VECTOR4D,
  660. BSSFT_COUNT,
  661. };
  662. #define BSSFT_INT (sizeof( int ) == sizeof( int32 ) ? BSSFT_INT32 : BSSFT_INT64)
  663. #define BSSFT_UINT (sizeof( unsigned int ) == sizeof( uint32 ) ? BSSFT_UINT32 : BSSFT_UINT64)
  664. #define BSSFT_SIZE_T (sizeof( size_t ) == sizeof( uint32 ) ? BSSFT_UINT32 : BSSFT_UINT64)
  665. enum BasicStatStructFieldCombineMethods_t
  666. {
  667. BSSFCM_UNKNOWN,
  668. BSSFCM_CUSTOM, //rely on some outside handler
  669. BSSFCM_ADD, //add the values
  670. //BSSFCM_SUBTRACT, //what would subtract even mean? which one from which?
  671. BSSFCM_MAX, //keep max value
  672. BSSFCM_MIN, //keep min value
  673. BSSFCM_AND, // &= , Non-integer behavior undefined
  674. BSSFCM_OR, // |= , Non-integer behavior undefined
  675. BSSFCM_XOR, // ^= , Non-integer behavior undefined
  676. /*BSSFCM_LIST, //keep a list of each value (probably complicated)*/
  677. BSSFCM_COUNT,
  678. };
  679. class PLATFORM_CLASS BasicStatStructFieldDesc : public CallStackStatStructDescFuncs
  680. {
  681. public:
  682. BasicStatStructFieldDesc( BasicStatStructFieldTypes_t type, BasicStatStructFieldCombineMethods_t combineMethod ) : m_Type(type), m_Combine(combineMethod) {};
  683. size_t DescribeField( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength );
  684. #if 0 //embedded script handling not ready yet
  685. size_t DescribeMergeOperation( MergeScript_Language scriptLanguage, uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength );
  686. #endif
  687. BasicStatStructFieldTypes_t m_Type;
  688. BasicStatStructFieldCombineMethods_t m_Combine;
  689. };
  690. //struct is locked in place while you're holding onto one of these. Get a base, then create one of these from it
  691. template <class STATSTRUCT>
  692. class CCallStackStatsGatherer_StructAccessor_AutoLock : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>
  693. {
  694. public:
  695. CCallStackStatsGatherer_StructAccessor_AutoLock( CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> &copyFrom )
  696. : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( copyFrom )
  697. {
  698. this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, true );
  699. this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, true );
  700. this->m_pStruct = (STATSTRUCT *)this->m_Gatherer.pFunctionTable->pfn_GetEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex );
  701. }
  702. ~CCallStackStatsGatherer_StructAccessor_AutoLock( void )
  703. {
  704. this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, false );
  705. this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, false );
  706. }
  707. STATSTRUCT *operator->()
  708. {
  709. return this->m_pStruct;
  710. }
  711. STATSTRUCT *GetStruct( void ) //do not hold this pointer outside the lock period
  712. {
  713. return this->m_pStruct;
  714. }
  715. protected:
  716. STATSTRUCT *m_pStruct;
  717. };
  718. //struct is locked in place only between Lock() and paired Unlock() calls. Get a base, then create one of these from it.
  719. //It's safe to hold onto this for an extended period of time. The entry index is unchanging in the gatherer tree.
  720. template <class STATSTRUCT>
  721. class CCallStackStatsGatherer_StructAccessor_Manual : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>
  722. {
  723. public:
  724. CCallStackStatsGatherer_StructAccessor_Manual( CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> &copyFrom )
  725. : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( copyFrom ), m_pStruct( NULL )
  726. { }
  727. STATSTRUCT *operator->()
  728. {
  729. return this->m_pStruct; //NULL while entry is not locked.
  730. }
  731. STATSTRUCT *GetStruct( void ) //do not hold this pointer outside the lock period
  732. {
  733. return this->m_pStruct; //NULL while entry is not locked.
  734. }
  735. void Lock( void )
  736. {
  737. this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, true );
  738. this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, true );
  739. this->m_pStruct = (STATSTRUCT *)this->m_Gatherer.pFunctionTable->pfn_GetEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex );
  740. }
  741. void Unlock( void )
  742. {
  743. this->m_pStruct = NULL;
  744. this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, false );
  745. this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, false );
  746. }
  747. protected:
  748. STATSTRUCT *m_pStruct;
  749. };
  750. class CCallStackStats_PushSubTree_AutoPop
  751. {
  752. public:
  753. CCallStackStats_PushSubTree_AutoPop( const CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStatsGatherer_Standardized_t &Child, const CCallStackStorage &PushStack = CCallStackStorage() )
  754. : m_PopFrom( Parent )
  755. {
  756. Parent.pFunctionTable->pfn_PushSubTree( Parent.pGatherer, Child, PushStack );
  757. }
  758. ~CCallStackStats_PushSubTree_AutoPop( void )
  759. {
  760. m_PopFrom.PopSubTree();
  761. }
  762. CCallStackStatsGatherer_Standardized_t m_PopFrom;
  763. };
  764. #endif //#ifndef TIER0_STACKTOOLS_H