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.

330 lines
8.4 KiB

  1. //====== Copyright c 1996-2007, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "tier0/platform.h"
  9. #include "tier0/miniprofiler.h"
  10. #include "tier0/cache_hints.h"
  11. #include "tier0/dbg.h"
  12. #include "tier0/threadtools.h"
  13. #include <time.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. #ifdef _PS3
  17. #include "ps3/ps3_helpers.h"
  18. #endif
  19. #if defined( PLATFORM_WINDOWS_PC )
  20. #define WIN_32_LEAN_AND_MEAN
  21. #include <windows.h> // Currently needed for LARGE_INTEGER
  22. #endif
  23. // NOTE: This has to be the last file included!
  24. #include "tier0/memdbgon.h"
  25. #ifdef IS_WINDOWS_PC
  26. CTHREADLOCALPTR( CMiniProfiler ) s_pLastMiniProfilerTS;
  27. #else
  28. CMiniProfiler *s_pLastMiniProfilerTS;
  29. #endif
  30. static CLinkedMiniProfiler *s_pDummyList = NULL;
  31. class CRootMiniProfiler : public CLinkedMiniProfiler
  32. {
  33. public:
  34. CRootMiniProfiler( void ) : CLinkedMiniProfiler( "DummyRoot", &s_pDummyList )
  35. {
  36. s_pLastMiniProfilerTS = this;
  37. }
  38. };
  39. CRootMiniProfiler g_rootMiniProfiler;
  40. #if defined( STATIC_LINK ) || defined( _LINUX )
  41. // in static link scenario, we don't need any extra linkage specified where we define our variables
  42. #undef MINIPROFILER_DLL_LINKAGE
  43. #define MINIPROFILER_DLL_LINKAGE
  44. #else
  45. extern "C"
  46. {
  47. #endif
  48. MINIPROFILER_DLL_LINKAGE CMiniProfiler *g_pRootMiniProfiler = &g_rootMiniProfiler;
  49. MINIPROFILER_DLL_LINKAGE CLinkedMiniProfiler *g_pGlobalMiniProfilers = NULL;
  50. MINIPROFILER_DLL_LINKAGE CLinkedMiniProfiler *g_pAssertMiniProfilers = NULL;
  51. MINIPROFILER_DLL_LINKAGE CMiniProfiler *g_pLastMiniProfiler = &g_rootMiniProfiler;
  52. MINIPROFILER_DLL_LINKAGE uint32 g_nMiniProfilerFrame = 0;
  53. #if defined( STATIC_LINK ) || defined( _LINUX )
  54. #else
  55. }
  56. #endif
  57. int64 GetHardwareClockReliably()
  58. {
  59. int64 res = 0;
  60. #if ENABLE_MINI_PROFILER && IS_WINDOWS_PC
  61. QueryPerformanceCounter( ( LARGE_INTEGER* )&res );
  62. #endif
  63. return res;
  64. }
  65. CMiniProfiler* PushMiniProfilerTS( CMiniProfiler *pProfiler )
  66. {
  67. CMiniProfiler *pLast = s_pLastMiniProfilerTS;
  68. if ( !pLast )
  69. {
  70. pLast = &g_rootMiniProfiler;
  71. }
  72. s_pLastMiniProfilerTS = pProfiler;
  73. return pLast;
  74. }
  75. CThreadFastMutex g_ProfilerListMutex;
  76. //CInterlockedInt g_LinkedMiniProfilerIdCount;
  77. void AppendMiniProfilerToList( CLinkedMiniProfiler *pProfiler, CLinkedMiniProfiler **ppList )
  78. {
  79. #if ENABLE_MINI_PROFILER
  80. g_ProfilerListMutex.Lock();
  81. //pProfiler->m_nId = g_LinkedMiniProfilerIdCount++;
  82. if( IsDebug() )
  83. {
  84. int nProfilerCount = 0; NOTE_UNUSED( nProfilerCount );
  85. CLinkedMiniProfiler *pTest;
  86. for( pTest = *ppList; pTest; pTest = pTest->m_pNext )
  87. {
  88. nProfilerCount++;
  89. if( pTest == pProfiler )
  90. {
  91. break;
  92. }
  93. }
  94. if( pProfiler == pTest && !pProfiler->m_ppPrev )
  95. DebuggerBreak(); // the miniprofiler is not yet added to any list (pprev == 0) but it's already in this list (pTest == pProfiler)
  96. if( !pTest && pProfiler->m_ppPrev )
  97. DebuggerBreak(); // the profiler is not in this list, but it's already in some list (pNext!=0)
  98. }
  99. if( !pProfiler->m_ppPrev )
  100. {
  101. // the profiler is not yet in any list
  102. if ( ppList )
  103. {
  104. pProfiler->m_pNext = *ppList;
  105. pProfiler->m_ppPrev = ppList;
  106. if( pProfiler->m_pNext )
  107. {
  108. pProfiler->m_pNext->m_ppPrev = &pProfiler->m_pNext;
  109. }
  110. *ppList = pProfiler;
  111. }
  112. }
  113. else
  114. {
  115. if( !ppList )
  116. {
  117. // Warning: unhooking something that wasn't removed from the previous list?
  118. if( IsDebug() )
  119. {
  120. DebuggerBreak();
  121. }
  122. pProfiler->m_pNext = NULL;
  123. pProfiler->m_ppPrev = NULL;
  124. }
  125. }
  126. g_ProfilerListMutex.Unlock();
  127. #endif // ENABLE_MINI_PROFILER
  128. }
  129. void RemoveMiniProfilerFromList( CLinkedMiniProfiler *pProfiler )
  130. {
  131. #if ENABLE_MINI_PROFILER
  132. g_ProfilerListMutex.Lock();
  133. // We need to remove miniprofiler from the list properly. This is an issue because we unload DLLs sometimes.
  134. if ( pProfiler->m_ppPrev )
  135. {
  136. *pProfiler->m_ppPrev = pProfiler->m_pNext; // that's it: we just remove this object from the list by linking previous object with the next
  137. }
  138. if ( pProfiler->m_pNext )
  139. {
  140. pProfiler->m_pNext->m_ppPrev = pProfiler->m_ppPrev;
  141. }
  142. // unhook the profiler from the list completely, so that we don't try to do it twice
  143. pProfiler->m_ppPrev = NULL;
  144. pProfiler->m_pNext = NULL;
  145. g_ProfilerListMutex.Unlock();
  146. #endif // ENABLE_MINI_PROFILER
  147. }
  148. #if ENABLE_HARDWARE_PROFILER
  149. DLL_CLASS_EXPORT void CMiniProfiler::Publish(const char *szMessage, ...)
  150. {
  151. #ifdef _X360
  152. if(m_numCalls >= 100 || m_numTimeBaseTicks > 50) // 500 timebase ticks is 1 microsecond
  153. {
  154. char szBuf[256];
  155. va_list args;
  156. va_start(args, szMessage);
  157. vsnprintf(szBuf, sizeof(szBuf), szMessage, args);
  158. PIXAddNamedCounter(float(INT32(m_numTimeBaseTicks-m_numTimeBaseTicksInCallees))*0.02f, "Ex:%s,mcs", szBuf);
  159. PIXAddNamedCounter(float(INT32(m_numTimeBaseTicks))*0.02f, "%s,mcs", szBuf);
  160. if(m_numCalls)
  161. PIXAddNamedCounter((float)(64*INT32(m_numTimeBaseTicks)/INT32(m_numCalls)), "%s,ticks", szBuf);
  162. PIXAddNamedCounter((float)(INT32(m_numCalls)), "%s,calls", szBuf);
  163. }
  164. #endif
  165. Reset();
  166. }
  167. #endif
  168. void CLinkedMiniProfiler::Publish(uint nHistoryMax)
  169. {
  170. #if ENABLE_HARDWARE_PROFILER
  171. if(nHistoryMax != m_nHistoryMax)
  172. {
  173. PurgeHistory();
  174. delete[]m_pHistory;
  175. m_nHistoryMax = nHistoryMax;
  176. if(nHistoryMax)
  177. m_pHistory = new CMiniProfiler[nHistoryMax];
  178. else
  179. m_pHistory = NULL;
  180. m_nHistoryLength = 0;
  181. m_nFrameHistoryBegins = g_nMiniProfilerFrame;
  182. }
  183. else
  184. if(m_nHistoryLength >= nHistoryMax)
  185. {
  186. PurgeHistory();
  187. }
  188. if(m_pHistory)
  189. m_pHistory[m_nHistoryLength++] = *this;
  190. CMiniProfiler::Publish(m_szName);
  191. #endif
  192. }
  193. #if ENABLE_HARDWARE_PROFILER
  194. static char g_szFileName[128] = "";
  195. static FILE *g_pPurgeFile = NULL;
  196. #endif
  197. void CLinkedMiniProfiler::PurgeHistory()
  198. {
  199. #if ENABLE_HARDWARE_PROFILER
  200. if(m_nHistoryLength && g_pPurgeFile)
  201. {
  202. size_t len = (strlen(m_szName) + 3) & ~3;
  203. fwrite(&len, sizeof(len), 1, g_pPurgeFile);
  204. fwrite(m_szName, len, 1, g_pPurgeFile);
  205. fwrite(&m_nFrameHistoryBegins, sizeof(m_nFrameHistoryBegins), 1, g_pPurgeFile);
  206. fwrite(&m_nHistoryLength, sizeof(m_nHistoryLength), 1, g_pPurgeFile);
  207. fwrite(m_pHistory, sizeof(CMiniProfiler), m_nHistoryLength, g_pPurgeFile);
  208. m_nHistoryLength = 0; // reset the history, nothing else
  209. m_nFrameHistoryBegins = g_nMiniProfilerFrame;
  210. }
  211. #endif
  212. }
  213. extern "C"
  214. MINIPROFILER_DLL_LINKAGE void PublishAll( CLinkedMiniProfiler*pList, uint32 nHistoryMax )
  215. {
  216. #if ENABLE_HARDWARE_PROFILER
  217. for(CLinkedMiniProfiler *prof = pList; prof; prof = prof->m_pNext)
  218. prof->Publish(nHistoryMax);
  219. #endif
  220. }
  221. void MicroProfilerAddTS( CMicroProfiler *pProfiler, uint64 numTimeBaseTicks )
  222. {
  223. #if ENABLE_MICRO_PROFILER > 0
  224. ThreadInterlockedExchangeAdd64( ( int64* )&pProfiler->m_numTimeBaseTicks, numTimeBaseTicks );
  225. ThreadInterlockedIncrement( ( int32* )&pProfiler->m_numCalls );
  226. #endif
  227. }
  228. void PopMiniProfilerTS( CMiniProfiler *pProfiler )
  229. {
  230. s_pLastMiniProfilerTS = pProfiler;
  231. }
  232. static void GetPerformanceFrequency( int64 *pFreqOut )
  233. {
  234. #ifdef PLATFORM_POSIX
  235. *pFreqOut = 2000000000;
  236. #elif defined( _PS3 )
  237. *pFreqOut = 3200000000ll;
  238. #else
  239. QueryPerformanceFrequency( ( LARGE_INTEGER* ) pFreqOut );
  240. #endif
  241. }
  242. DLL_EXPORT void PublishAllMiniProfilers(int nHistoryMax)
  243. {
  244. #if ENABLE_HARDWARE_PROFILER
  245. if(nHistoryMax >= 0/*cv_phys_enable_PIX_counters.GetBool()*/)
  246. {
  247. if(nHistoryMax && !g_pPurgeFile)
  248. {
  249. if(!g_szFileName[0])
  250. {
  251. tm lt;
  252. Plat_GetLocalTime( &lt );
  253. //SYSTEMTIME st;
  254. //GetLocalTime(&st);
  255. //sprintf(g_szFileName, "D:\\mp%02d-%02d-%02d-%02d-%02d-%02d.dmp", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
  256. sprintf(g_szFileName, "miniprofile%02d%02d-%02d_%02d_%02d.prf", /*lt->tm_year+1900, */lt.tm_mon+1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec);
  257. }
  258. g_pPurgeFile = fopen(g_szFileName, "ab");
  259. if(g_pPurgeFile)
  260. {
  261. int nVersion = 0x0101;
  262. fwrite(&nVersion, 4, 1, g_pPurgeFile);
  263. #ifdef _X360
  264. int nFrequency = 49875; // ticks per millisecond
  265. #else
  266. // even though this is not correct on older computers, I think most modern computers have the multimedia clock that has the same frequency as the CPU
  267. int64 nActualFrequency = GetCPUInformation().m_Speed;
  268. int nFrequency = int((nActualFrequency+500) / 1000);
  269. #endif
  270. fwrite(&nFrequency, 4, 1, g_pPurgeFile);
  271. }
  272. }
  273. PublishAll(g_pPhysicsMiniProfilers,nHistoryMax);
  274. PublishAll(g_pOtherMiniProfilers,nHistoryMax);
  275. g_rootMiniProfiler.Reset();
  276. g_nMiniProfilerFrame ++;
  277. if(g_pPurgeFile)
  278. {
  279. if(nHistoryMax)
  280. fflush(g_pPurgeFile);
  281. else
  282. {
  283. Msg("Closing profile: '%s'\n", g_szFileName);
  284. fclose(g_pPurgeFile);
  285. g_pPurgeFile = NULL;
  286. g_szFileName[0] = '\0';
  287. }
  288. }
  289. }
  290. #endif
  291. }