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.

596 lines
14 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #ifndef FASTTIMER_H
  8. #define FASTTIMER_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include <assert.h>
  13. #include "tier0/platform.h"
  14. #ifdef _PS3
  15. #include "sys/sys_time.h"
  16. #else
  17. inline uint64 sys_time_get_timebase_frequency()
  18. {
  19. DebuggerBreak(); // Error("sys_time_get_timebase_frequency called on non-PS3 platform.");
  20. return 1; // this function should never ever be called.
  21. }
  22. #endif
  23. PLATFORM_INTERFACE uint64 g_ClockSpeed;
  24. PLATFORM_INTERFACE unsigned long g_dwClockSpeed;
  25. PLATFORM_INTERFACE double g_ClockSpeedMicrosecondsMultiplier;
  26. PLATFORM_INTERFACE double g_ClockSpeedMillisecondsMultiplier;
  27. PLATFORM_INTERFACE double g_ClockSpeedSecondsMultiplier;
  28. class CCycleCount
  29. {
  30. friend class CFastTimer;
  31. public:
  32. CCycleCount();
  33. CCycleCount( uint64 cycles );
  34. void Sample(); // Sample the clock. This takes about 34 clocks to execute (or 26,000 calls per millisecond on a P900).
  35. void Init(); // Set to zero.
  36. void Init( float initTimeMsec );
  37. void Init( double initTimeMsec ) { Init( (float)initTimeMsec ); }
  38. void Init( uint64 cycles );
  39. bool IsLessThan( CCycleCount const &other ) const; // Compare two counts.
  40. // Convert to other time representations. These functions are slow, so it's preferable to call them
  41. // during display rather than inside a timing block.
  42. unsigned long GetCycles() const;
  43. uint64 GetLongCycles() const;
  44. unsigned long GetMicroseconds() const;
  45. uint64 GetUlMicroseconds() const;
  46. double GetMicrosecondsF() const;
  47. void SetMicroseconds( unsigned long nMicroseconds );
  48. unsigned long GetMilliseconds() const;
  49. double GetMillisecondsF() const;
  50. double GetSeconds() const;
  51. CCycleCount& operator+=( CCycleCount const &other );
  52. // dest = rSrc1 + rSrc2
  53. static void Add( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ); // Add two samples together.
  54. // dest = rSrc1 - rSrc2
  55. static void Sub( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ); // Add two samples together.
  56. static uint64 GetTimestamp();
  57. uint64 m_Int64;
  58. };
  59. class CClockSpeedInit
  60. {
  61. public:
  62. CClockSpeedInit()
  63. {
  64. Init();
  65. }
  66. static void Init()
  67. {
  68. const CPUInformation& pi = GetCPUInformation();
  69. if ( IsX360() )
  70. {
  71. // cycle counter runs as doc'd at 1/64 Xbox 3.2GHz clock speed, thus 50 Mhz
  72. g_ClockSpeed = pi.m_Speed / 64L;
  73. }
  74. else if ( IsPS3() )
  75. {
  76. g_ClockSpeed = sys_time_get_timebase_frequency(); // CPU clock rate is totally unrelated to time base register frequency on PS3
  77. }
  78. else
  79. {
  80. g_ClockSpeed = pi.m_Speed;
  81. }
  82. g_dwClockSpeed = (unsigned long)g_ClockSpeed;
  83. g_ClockSpeedMicrosecondsMultiplier = 1000000.0 / (double)g_ClockSpeed;
  84. g_ClockSpeedMillisecondsMultiplier = 1000.0 / (double)g_ClockSpeed;
  85. g_ClockSpeedSecondsMultiplier = 1.0f / (double)g_ClockSpeed;
  86. }
  87. };
  88. class CFastTimer
  89. {
  90. public:
  91. // These functions are fast to call and should be called from your sampling code.
  92. void Start();
  93. void End();
  94. const CCycleCount & GetDuration() const; // Get the elapsed time between Start and End calls.
  95. CCycleCount GetDurationInProgress() const; // Call without ending. Not that cheap.
  96. // Return number of cycles per second on this processor.
  97. static inline unsigned long GetClockSpeed();
  98. private:
  99. CCycleCount m_Duration;
  100. #ifdef DEBUG_FASTTIMER
  101. bool m_bRunning; // Are we currently running?
  102. #endif
  103. };
  104. // This is a helper class that times whatever block of code it's in
  105. class CTimeScope
  106. {
  107. public:
  108. CTimeScope( CFastTimer *pTimer );
  109. ~CTimeScope();
  110. private:
  111. CFastTimer *m_pTimer;
  112. };
  113. inline CTimeScope::CTimeScope( CFastTimer *pTotal )
  114. {
  115. m_pTimer = pTotal;
  116. m_pTimer->Start();
  117. }
  118. inline CTimeScope::~CTimeScope()
  119. {
  120. m_pTimer->End();
  121. }
  122. // This is a helper class that times whatever block of code it's in and
  123. // adds the total (int microseconds) to a global counter.
  124. class CTimeAdder
  125. {
  126. public:
  127. CTimeAdder( CCycleCount *pTotal );
  128. ~CTimeAdder();
  129. void End();
  130. private:
  131. CCycleCount *m_pTotal;
  132. CFastTimer m_Timer;
  133. };
  134. inline CTimeAdder::CTimeAdder( CCycleCount *pTotal )
  135. {
  136. m_pTotal = pTotal;
  137. m_Timer.Start();
  138. }
  139. inline CTimeAdder::~CTimeAdder()
  140. {
  141. End();
  142. }
  143. inline void CTimeAdder::End()
  144. {
  145. if( m_pTotal )
  146. {
  147. m_Timer.End();
  148. *m_pTotal += m_Timer.GetDuration();
  149. m_pTotal = 0;
  150. }
  151. }
  152. // -------------------------------------------------------------------------- //
  153. // Simple tool to support timing a block of code, and reporting the results on
  154. // program exit or at each iteration
  155. //
  156. // Macros used because dbg.h uses this header, thus Msg() is unavailable
  157. // -------------------------------------------------------------------------- //
  158. #define PROFILE_SCOPE(name) \
  159. class C##name##ACC : public CAverageCycleCounter \
  160. { \
  161. public: \
  162. ~C##name##ACC() \
  163. { \
  164. Msg("%-48s: %6.3f avg (%8.1f total, %7.3f peak, %5d iters)\n", \
  165. #name, \
  166. GetAverageMilliseconds(), \
  167. GetTotalMilliseconds(), \
  168. GetPeakMilliseconds(), \
  169. GetIters() ); \
  170. } \
  171. }; \
  172. static C##name##ACC name##_ACC; \
  173. CAverageTimeMarker name##_ATM( &name##_ACC )
  174. #define TIME_SCOPE(name) \
  175. class CTimeScopeMsg_##name \
  176. { \
  177. public: \
  178. CTimeScopeMsg_##name() { m_Timer.Start(); } \
  179. ~CTimeScopeMsg_##name() \
  180. { \
  181. m_Timer.End(); \
  182. Msg( #name "time: %.4fms\n", m_Timer.GetDuration().GetMillisecondsF() ); \
  183. } \
  184. private: \
  185. CFastTimer m_Timer; \
  186. } name##_TSM;
  187. // -------------------------------------------------------------------------- //
  188. class CAverageCycleCounter
  189. {
  190. public:
  191. CAverageCycleCounter();
  192. void Init();
  193. void MarkIter( const CCycleCount &duration );
  194. unsigned GetIters() const;
  195. double GetAverageMilliseconds() const;
  196. double GetTotalMilliseconds() const;
  197. double GetPeakMilliseconds() const;
  198. private:
  199. unsigned m_nIters;
  200. CCycleCount m_Total;
  201. CCycleCount m_Peak;
  202. bool m_fReport;
  203. const tchar *m_pszName;
  204. };
  205. // -------------------------------------------------------------------------- //
  206. class CAverageTimeMarker
  207. {
  208. public:
  209. CAverageTimeMarker( CAverageCycleCounter *pCounter );
  210. ~CAverageTimeMarker();
  211. private:
  212. CAverageCycleCounter *m_pCounter;
  213. CFastTimer m_Timer;
  214. };
  215. // -------------------------------------------------------------------------- //
  216. // CCycleCount inlines.
  217. // -------------------------------------------------------------------------- //
  218. inline CCycleCount::CCycleCount()
  219. {
  220. Init( (uint64)0 );
  221. }
  222. inline CCycleCount::CCycleCount( uint64 cycles )
  223. {
  224. Init( cycles );
  225. }
  226. inline void CCycleCount::Init()
  227. {
  228. Init( (uint64)0 );
  229. }
  230. inline void CCycleCount::Init( float initTimeMsec )
  231. {
  232. if ( g_ClockSpeedMillisecondsMultiplier > 0 )
  233. Init( (uint64)(initTimeMsec / g_ClockSpeedMillisecondsMultiplier) );
  234. else
  235. Init( (uint64)0 );
  236. }
  237. inline void CCycleCount::Init( uint64 cycles )
  238. {
  239. m_Int64 = cycles;
  240. }
  241. inline void CCycleCount::Sample()
  242. {
  243. m_Int64 = Plat_Rdtsc();
  244. }
  245. inline CCycleCount& CCycleCount::operator+=( CCycleCount const &other )
  246. {
  247. m_Int64 += other.m_Int64;
  248. return *this;
  249. }
  250. inline void CCycleCount::Add( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest )
  251. {
  252. dest.m_Int64 = rSrc1.m_Int64 + rSrc2.m_Int64;
  253. }
  254. inline void CCycleCount::Sub( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest )
  255. {
  256. dest.m_Int64 = rSrc1.m_Int64 - rSrc2.m_Int64;
  257. }
  258. inline uint64 CCycleCount::GetTimestamp()
  259. {
  260. CCycleCount c;
  261. c.Sample();
  262. return c.GetLongCycles();
  263. }
  264. inline bool CCycleCount::IsLessThan(CCycleCount const &other) const
  265. {
  266. return m_Int64 < other.m_Int64;
  267. }
  268. inline unsigned long CCycleCount::GetCycles() const
  269. {
  270. return (unsigned long)m_Int64;
  271. }
  272. inline uint64 CCycleCount::GetLongCycles() const
  273. {
  274. return m_Int64;
  275. }
  276. inline unsigned long CCycleCount::GetMicroseconds() const
  277. {
  278. return (unsigned long)((m_Int64 * 1000000) / g_ClockSpeed);
  279. }
  280. inline uint64 CCycleCount::GetUlMicroseconds() const
  281. {
  282. return ((m_Int64 * 1000000) / g_ClockSpeed);
  283. }
  284. inline double CCycleCount::GetMicrosecondsF() const
  285. {
  286. return (double)( m_Int64 * g_ClockSpeedMicrosecondsMultiplier );
  287. }
  288. inline void CCycleCount::SetMicroseconds( unsigned long nMicroseconds )
  289. {
  290. m_Int64 = ((uint64)nMicroseconds * g_ClockSpeed) / 1000000;
  291. }
  292. inline unsigned long CCycleCount::GetMilliseconds() const
  293. {
  294. return (unsigned long)((m_Int64 * 1000) / g_ClockSpeed);
  295. }
  296. inline double CCycleCount::GetMillisecondsF() const
  297. {
  298. return (double)( m_Int64 * g_ClockSpeedMillisecondsMultiplier );
  299. }
  300. inline double CCycleCount::GetSeconds() const
  301. {
  302. return (double)( m_Int64 * g_ClockSpeedSecondsMultiplier );
  303. }
  304. // -------------------------------------------------------------------------- //
  305. // CFastTimer inlines.
  306. // -------------------------------------------------------------------------- //
  307. inline void CFastTimer::Start()
  308. {
  309. m_Duration.Sample();
  310. #ifdef DEBUG_FASTTIMER
  311. m_bRunning = true;
  312. #endif
  313. }
  314. inline void CFastTimer::End()
  315. {
  316. CCycleCount cnt;
  317. cnt.Sample();
  318. if ( IsX360() )
  319. {
  320. // have to handle rollover, hires timer is only accurate to 32 bits
  321. // more than one overflow should not have occurred, otherwise caller should use a slower timer
  322. if ( (uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64 )
  323. {
  324. // rollover occurred
  325. cnt.m_Int64 += 0x100000000LL;
  326. }
  327. }
  328. m_Duration.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64;
  329. #ifdef DEBUG_FASTTIMER
  330. m_bRunning = false;
  331. #endif
  332. }
  333. inline CCycleCount CFastTimer::GetDurationInProgress() const
  334. {
  335. CCycleCount cnt;
  336. cnt.Sample();
  337. if ( IsX360() )
  338. {
  339. // have to handle rollover, hires timer is only accurate to 32 bits
  340. // more than one overflow should not have occurred, otherwise caller should use a slower timer
  341. if ( (uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64 )
  342. {
  343. // rollover occurred
  344. cnt.m_Int64 += 0x100000000LL;
  345. }
  346. }
  347. CCycleCount result;
  348. result.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64;
  349. return result;
  350. }
  351. inline unsigned long CFastTimer::GetClockSpeed()
  352. {
  353. return g_dwClockSpeed;
  354. }
  355. inline CCycleCount const& CFastTimer::GetDuration() const
  356. {
  357. #ifdef DEBUG_FASTTIMER
  358. assert( !m_bRunning );
  359. #endif
  360. return m_Duration;
  361. }
  362. // -------------------------------------------------------------------------- //
  363. // CAverageCycleCounter inlines
  364. inline CAverageCycleCounter::CAverageCycleCounter()
  365. : m_nIters( 0 )
  366. {
  367. }
  368. inline void CAverageCycleCounter::Init()
  369. {
  370. m_Total.Init();
  371. m_Peak.Init();
  372. m_nIters = 0;
  373. }
  374. inline void CAverageCycleCounter::MarkIter( const CCycleCount &duration )
  375. {
  376. ++m_nIters;
  377. m_Total += duration;
  378. if ( m_Peak.IsLessThan( duration ) )
  379. m_Peak = duration;
  380. }
  381. inline unsigned CAverageCycleCounter::GetIters() const
  382. {
  383. return m_nIters;
  384. }
  385. inline double CAverageCycleCounter::GetAverageMilliseconds() const
  386. {
  387. if ( m_nIters )
  388. return (m_Total.GetMillisecondsF() / (double)m_nIters);
  389. else
  390. return 0;
  391. }
  392. inline double CAverageCycleCounter::GetTotalMilliseconds() const
  393. {
  394. return m_Total.GetMillisecondsF();
  395. }
  396. inline double CAverageCycleCounter::GetPeakMilliseconds() const
  397. {
  398. return m_Peak.GetMillisecondsF();
  399. }
  400. // -------------------------------------------------------------------------- //
  401. inline CAverageTimeMarker::CAverageTimeMarker( CAverageCycleCounter *pCounter )
  402. {
  403. m_pCounter = pCounter;
  404. m_Timer.Start();
  405. }
  406. inline CAverageTimeMarker::~CAverageTimeMarker()
  407. {
  408. m_Timer.End();
  409. m_pCounter->MarkIter( m_Timer.GetDuration() );
  410. }
  411. // CLimitTimer
  412. // Use this to time whether a desired interval of time has passed. It's extremely fast
  413. // to check while running. NOTE: CMicroSecOverage() and CMicroSecLeft() are not as fast to check.
  414. class CLimitTimer
  415. {
  416. public:
  417. CLimitTimer() {}
  418. CLimitTimer( uint64 cMicroSecDuration ) { SetLimit( cMicroSecDuration ); }
  419. void SetLimit( uint64 m_cMicroSecDuration );
  420. bool BLimitReached() const;
  421. int CMicroSecOverage() const;
  422. uint64 CMicroSecLeft() const;
  423. private:
  424. uint64 m_lCycleLimit;
  425. };
  426. //-----------------------------------------------------------------------------
  427. // Purpose: Initializes the limit timer with a period of time to measure.
  428. // Input : cMicroSecDuration - How long a time period to measure
  429. //-----------------------------------------------------------------------------
  430. inline void CLimitTimer::SetLimit( uint64 cMicroSecDuration )
  431. {
  432. uint64 dlCycles = ( ( uint64 ) cMicroSecDuration * ( uint64 ) g_dwClockSpeed ) / ( uint64 ) 1000000L;
  433. CCycleCount cycleCount;
  434. cycleCount.Sample();
  435. m_lCycleLimit = cycleCount.GetLongCycles() + dlCycles;
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose: Determines whether our specified time period has passed
  439. // Output: true if at least the specified time period has passed
  440. //-----------------------------------------------------------------------------
  441. inline bool CLimitTimer::BLimitReached() const
  442. {
  443. CCycleCount cycleCount;
  444. cycleCount.Sample();
  445. return ( cycleCount.GetLongCycles() >= m_lCycleLimit );
  446. }
  447. //-----------------------------------------------------------------------------
  448. // Purpose: If we're over our specified time period, return the amount of the overage.
  449. // Output: # of microseconds since we reached our specified time period.
  450. //-----------------------------------------------------------------------------
  451. inline int CLimitTimer::CMicroSecOverage() const
  452. {
  453. CCycleCount cycleCount;
  454. cycleCount.Sample();
  455. uint64 lcCycles = cycleCount.GetLongCycles();
  456. if ( lcCycles < m_lCycleLimit )
  457. return 0;
  458. return( ( int ) ( ( lcCycles - m_lCycleLimit ) * ( uint64 ) 1000000L / g_dwClockSpeed ) );
  459. }
  460. //-----------------------------------------------------------------------------
  461. // Purpose: If we're under our specified time period, return the amount under.
  462. // Output: # of microseconds until we reached our specified time period, 0 if we've passed it
  463. //-----------------------------------------------------------------------------
  464. inline uint64 CLimitTimer::CMicroSecLeft() const
  465. {
  466. CCycleCount cycleCount;
  467. cycleCount.Sample();
  468. uint64 lcCycles = cycleCount.GetLongCycles();
  469. if ( lcCycles >= m_lCycleLimit )
  470. return 0;
  471. return( ( uint64 ) ( ( m_lCycleLimit - lcCycles ) * ( uint64 ) 1000000L / g_dwClockSpeed ) );
  472. }
  473. #endif // FASTTIMER_H