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.

345 lines
7.8 KiB

  1. //========= Copyright (c) Valve Corporation, All rights reserved. ============
  2. //
  3. // this is even smaller profiler than miniprofiler: there is no linking or bookkeeping
  4. // of any kind, it's just to throw in quick profilers that don't mess with code speed
  5. // even in CERT builds
  6. //
  7. #ifndef TIER0MICROPROFILERHDR
  8. #define TIER0MICROPROFILERHDR
  9. #include "platform.h"
  10. // define this to 1 to enable microprofiler; 2 to enable miniprofiler
  11. #ifndef ENABLE_MICRO_PROFILER
  12. #define ENABLE_MICRO_PROFILER 1
  13. #endif
  14. class CMicroProfiler;
  15. PLATFORM_INTERFACE void MicroProfilerAddTS( CMicroProfiler *pProfiler, uint64 numTimeBaseTicks );
  16. PLATFORM_INTERFACE int64 GetHardwareClockReliably();
  17. #ifdef IS_WINDOWS_PC
  18. #include <intrin.h> // get __rdtsc
  19. #endif
  20. #if defined(_LINUX) || defined( OSX )
  21. inline unsigned long long GetTimebaseRegister( void )
  22. {
  23. #ifdef PLATFORM_64BITS
  24. unsigned long long Low, High;
  25. __asm__ __volatile__ ( "rdtsc" : "=a" (Low), "=d" (High) );
  26. return ( High << 32 ) | ( Low & 0xffffffff );
  27. #else
  28. unsigned long long Val;
  29. __asm__ __volatile__ ( "rdtsc" : "=A" (Val) );
  30. return Val;
  31. #endif
  32. }
  33. #else
  34. // Warning: THere's a hardware bug with 64-bit MFTB on PS3 (not sure about X360): sometimes it returns incorrect results (when low word overflows, the high word doesn't increment for some time)
  35. inline int64 GetTimebaseRegister()
  36. {
  37. #if defined( _X360 )
  38. return __mftb32(); // X360: ~64 CPU ticks resolution
  39. #elif defined( _PS3 )
  40. // The timebase frequency on PS/3 is 79.8 MHz, see sys_time_get_timebase_frequency()
  41. // this works out to 40.10025 clock ticks per timebase tick
  42. return __mftb();
  43. #elif defined( OSX )
  44. return GetTimebaseRegister();
  45. #else
  46. return __rdtsc();
  47. #endif
  48. }
  49. #endif
  50. #if ENABLE_MICRO_PROFILER > 0
  51. class CMicroProfilerSample
  52. {
  53. int64 m_nTimeBaseBegin; // time base is kept here instead of using -= and += for better reliability and to avoid a cache miss at the beginning of the profiled section
  54. public:
  55. CMicroProfilerSample()
  56. {
  57. m_nTimeBaseBegin = GetTimebaseRegister();
  58. }
  59. int64 GetElapsed()const
  60. {
  61. return GetTimebaseRegister() - m_nTimeBaseBegin;
  62. }
  63. };
  64. #ifdef IS_WINDOWS_PC
  65. class CMicroProfilerQpcSample
  66. {
  67. int64 m_nTimeBaseBegin; // time base is kept here instead of using -= and += for better reliability and to avoid a cache miss at the beginning of the profiled section
  68. public:
  69. CMicroProfilerQpcSample()
  70. {
  71. m_nTimeBaseBegin = GetHardwareClockReliably();
  72. }
  73. int64 GetElapsed()const
  74. {
  75. return GetHardwareClockReliably() - m_nTimeBaseBegin;
  76. }
  77. };
  78. #else
  79. typedef CMicroProfilerSample CMicroProfilerQpcSample;
  80. #endif
  81. class CMicroProfiler
  82. {
  83. public:
  84. uint64 m_numTimeBaseTicks; // this will be totally screwed between Begin() and End()
  85. uint64 m_numCalls;
  86. public:
  87. CMicroProfiler()
  88. {
  89. Reset();
  90. }
  91. CMicroProfiler( const CMicroProfiler &other )
  92. {
  93. m_numTimeBaseTicks = other.m_numTimeBaseTicks;
  94. m_numCalls = other.m_numCalls;
  95. }
  96. CMicroProfiler &operator=( const CMicroProfiler &other )
  97. {
  98. m_numTimeBaseTicks = other.m_numTimeBaseTicks;
  99. m_numCalls = other.m_numCalls;
  100. return *this;
  101. }
  102. void Begin()
  103. {
  104. m_numTimeBaseTicks -= GetTimebaseRegister();
  105. }
  106. void End()
  107. {
  108. m_numTimeBaseTicks += GetTimebaseRegister();
  109. m_numCalls ++;
  110. }
  111. void End( uint64 nCalls )
  112. {
  113. m_numTimeBaseTicks += GetTimebaseRegister();
  114. m_numCalls += nCalls;
  115. }
  116. void Add( uint64 numTimeBaseTicks, uint64 numCalls = 1)
  117. {
  118. m_numTimeBaseTicks += numTimeBaseTicks;
  119. m_numCalls += numCalls;
  120. }
  121. void AddTS( uint64 numTimeBaseTicks )
  122. {
  123. MicroProfilerAddTS( this, numTimeBaseTicks );
  124. }
  125. void Add(const CMicroProfilerSample &sample)
  126. {
  127. Add( sample.GetElapsed() );
  128. }
  129. void Add( const CMicroProfiler& profiler)
  130. {
  131. Add( profiler.m_numTimeBaseTicks, profiler.m_numCalls );
  132. }
  133. void Reset()
  134. {
  135. m_numTimeBaseTicks = 0;
  136. m_numCalls = 0;
  137. }
  138. void Damp( int shift = 1 )
  139. {
  140. m_numTimeBaseTicks >>= shift;
  141. m_numCalls >>= shift;
  142. }
  143. uint64 GetNumCalls() const
  144. {
  145. return m_numCalls;
  146. }
  147. uint64 GetNumTimeBaseTicks() const
  148. {
  149. return m_numTimeBaseTicks;
  150. }
  151. float GetAverageMilliseconds() const
  152. {
  153. return m_numCalls ? GetTotalMilliseconds() / m_numCalls : 0;
  154. }
  155. float GetTotalMilliseconds() const
  156. {
  157. return TimeBaseTicksToMilliseconds( m_numTimeBaseTicks );
  158. }
  159. static float TimeBaseTicksToMilliseconds( uint64 numTimeBaseTicks )
  160. {
  161. #if defined( _X360 ) || defined( _PS3 )
  162. return numTimeBaseTicks / 79800.0 ;
  163. #else
  164. return numTimeBaseTicks / ( GetCPUInformation().m_Speed * 0.001f );
  165. #endif
  166. }
  167. float GetAverageTicks() const
  168. {
  169. #if defined( _X360 ) || defined( _PS3 )
  170. return m_numTimeBaseTicks * 40.1f / m_numCalls; // timebase register is 79.8 MHz on these platforms
  171. #else
  172. return float( m_numTimeBaseTicks / m_numCalls );
  173. #endif
  174. }
  175. friend const CMicroProfiler operator + ( const CMicroProfiler &left, const CMicroProfiler &right );
  176. void Accumulate( const CMicroProfiler &other )
  177. {
  178. m_numCalls += other.m_numCalls;
  179. m_numTimeBaseTicks += other.m_numTimeBaseTicks;
  180. }
  181. };
  182. inline const CMicroProfiler operator + ( const CMicroProfiler &left, const CMicroProfiler &right )
  183. {
  184. CMicroProfiler result;
  185. result.m_numCalls = left.m_numCalls + right.m_numCalls;
  186. result.m_numTimeBaseTicks = left.m_numTimeBaseTicks + right.m_numTimeBaseTicks;
  187. return result;
  188. }
  189. class CMicroProfilerGuard: public CMicroProfilerSample
  190. {
  191. CMicroProfiler *m_pProfiler;
  192. public:
  193. CMicroProfilerGuard( CMicroProfiler *pProfiler )
  194. {
  195. m_pProfiler = pProfiler;
  196. }
  197. ~CMicroProfilerGuard()
  198. {
  199. m_pProfiler->Add( GetElapsed() );
  200. }
  201. };
  202. class CMicroProfilerGuardWithCount: public CMicroProfilerSample
  203. {
  204. CMicroProfiler *m_pProfiler;
  205. uint m_nCount;
  206. public:
  207. CMicroProfilerGuardWithCount( CMicroProfiler *pProfiler, uint nCount )
  208. {
  209. m_nCount = nCount;
  210. m_pProfiler = pProfiler;
  211. }
  212. void OverrideCount( uint nCount ) { m_nCount = nCount; }
  213. ~CMicroProfilerGuardWithCount( )
  214. {
  215. m_pProfiler->Add( GetElapsed( ), m_nCount );
  216. }
  217. };
  218. // thread-safe variant of the same profiler
  219. class CMicroProfilerGuardTS: public CMicroProfilerSample
  220. {
  221. CMicroProfiler *m_pProfiler;
  222. public:
  223. CMicroProfilerGuardTS( CMicroProfiler *pProfiler )
  224. {
  225. m_pProfiler = pProfiler;
  226. }
  227. ~CMicroProfilerGuardTS()
  228. {
  229. m_pProfiler->AddTS( GetElapsed() );
  230. }
  231. };
  232. #define MICRO_PROFILER_NAME_0(LINE) localAutoMpg##LINE
  233. #define MICRO_PROFILER_NAME(LINE) MICRO_PROFILER_NAME_0(LINE)
  234. #define MICRO_PROFILE( MP ) CMicroProfilerGuard MICRO_PROFILER_NAME(__LINE__)( &( MP ) )
  235. #define MICRO_PROFILE_TS( MP ) CMicroProfilerGuardTS MICRO_PROFILER_NAME(__LINE__)( &( MP ) )
  236. #else
  237. class CMicroProfilerSample
  238. {public:
  239. CMicroProfilerSample(){}
  240. int GetElapsed()const{ return 0;}
  241. };
  242. typedef CMicroProfilerSample CMicroProfilerQpcSample;
  243. class CMicroProfiler
  244. { public:
  245. CMicroProfiler(){}
  246. CMicroProfiler &operator=( const CMicroProfiler &other ) { return *this; }
  247. void Begin(){}
  248. void End(){}
  249. void End( uint32 ){}
  250. void Add( uint64 numTimeBaseTicks, int numCalls = 1){}
  251. void AddTS( uint64 numTimeBaseTicks ) {}
  252. void Add( const CMicroProfilerSample &sample){}
  253. void Add( const CMicroProfiler& profiler) {}
  254. void Reset(){}
  255. void Damp(int shift = 1){}
  256. uint64 GetNumCalls() const { return 0; }
  257. uint64 GetNumTimeBaseTicks() const { return 0; }
  258. int64 GetNumTimeBaseTicksExclusive() const { return 0; }
  259. float GetAverageMilliseconds()const { return 0; }
  260. float GetTotalMilliseconds()const { return 0; }
  261. static float TimeBaseTicksToMilliseconds( uint64 numTimeBaseTicks ) { return 0; }
  262. float GetAverageTicks() const { return 0; }
  263. friend const CMicroProfiler operator + ( const CMicroProfiler &left, const CMicroProfiler &right );
  264. };
  265. inline const CMicroProfiler operator + ( const CMicroProfiler &left, const CMicroProfiler &right ) { return left; }
  266. class CMicroProfilerGuard: public CMicroProfilerSample
  267. {
  268. public:
  269. CMicroProfilerGuard( CMicroProfiler *pProfiler ){}
  270. ~CMicroProfilerGuard(){}
  271. };
  272. class CMicroProfilerGuardTS: public CMicroProfilerSample
  273. {
  274. public:
  275. CMicroProfilerGuardTS( CMicroProfiler *pProfiler ){}
  276. ~CMicroProfilerGuardTS(){}
  277. };
  278. #define MICRO_PROFILE( MP )
  279. #endif
  280. #endif