00001 #include "MercuryTimer.h" 00002 #include "MercuryLog.h" 00003 #include "MercuryUtil.h" 00004 00005 #ifndef WIN32 00006 #include <sys/time.h> 00007 #else 00008 #include <windows.h> 00009 #endif 00010 00011 #define RESOLUTION 1000000 00012 00013 MercuryTimer::MercuryTimer() 00014 { 00015 m_pTime = 0; 00016 m_paused = false; 00017 Touch(); 00018 } 00019 00020 MercuryTimer::~MercuryTimer() 00021 { 00022 } 00023 00024 double MercuryTimer::Peek() 00025 { 00026 return (double(m_secs) + (double(m_usecs) / RESOLUTION)) - m_pTime; 00027 } 00028 00029 double MercuryTimer::Age() 00030 { 00031 MercuryTimer current; 00032 if (!m_paused) 00033 return (current - *this).Peek(); 00034 else 00035 { 00036 m_pTime += (current - *this).Peek(); 00037 return 0; 00038 } 00039 } 00040 00041 void MercuryTimer::Touch() 00042 { 00043 uint64_t usecs = GetTimeMicroseconds(); 00044 //We should probably check for clock wraparound 00045 00046 m_secs = unsigned(usecs / RESOLUTION); 00047 m_usecs = unsigned(usecs % RESOLUTION); 00048 } 00049 00050 #ifndef WIN32 00051 int64_t GetMicrosecondsSinceEpoch() 00052 { 00053 #if !defined (_EE) 00054 struct timeval tv; 00055 gettimeofday( &tv, 0 ); 00056 00057 return int64_t(tv.tv_sec) * RESOLUTION + int64_t(tv.tv_usec); 00058 #else 00059 return 0; 00060 #endif 00061 } 00062 #endif 00063 00064 MercuryTimer MercuryTimer::operator-(const MercuryTimer& t) 00065 { 00066 MercuryTimer tmp; 00067 tmp.m_secs = m_secs - t.m_secs; 00068 tmp.m_usecs = m_usecs - t.m_usecs; 00069 00070 if (tmp.m_usecs < 0) 00071 { 00072 tmp.m_secs--; 00073 tmp.m_usecs += RESOLUTION; 00074 } 00075 00076 return tmp; 00077 } 00078 00079 MercuryTimer MercuryTimer::operator+(const MercuryTimer& t) 00080 { 00081 MercuryTimer tmp; 00082 tmp.m_secs = m_secs + t.m_secs; 00083 tmp.m_usecs = m_usecs + t.m_usecs; 00084 00085 if ((tmp.m_usecs/RESOLUTION) >= 1) 00086 { 00087 tmp.m_secs++; 00088 tmp.m_usecs -= RESOLUTION; 00089 } 00090 00091 return tmp; 00092 } 00093 00094 void MercuryTimer::operator=(const MercuryTimer& t) 00095 { 00096 m_secs = t.m_secs; 00097 m_usecs = t.m_usecs; 00098 00099 m_paused = t.m_paused; 00100 m_pTime = t.m_pTime; 00101 } 00102 00103 uint64_t MercuryTimer::GetTimeMicroseconds() 00104 { 00105 #ifdef WIN32 00106 int64_t t = timeGetTime() * int64_t(1000); 00107 t = FixupTimeIfLooped(t); 00108 t = FixupTimeIfBackwards(t); 00109 return t; 00110 #else 00111 return GetMicrosecondsSinceEpoch(); 00112 #endif 00113 } 00114 00115 00116 int64_t MercuryTimer::FixupTimeIfLooped( int64_t usecs ) 00117 { 00118 static int64_t last = 0; 00119 static int64_t offset_us = 0; 00120 00121 /* The time has wrapped if the last time was very high and the current time is very low. */ 00122 const int64_t i32BitMaxMs = uint64_t(1) << 32; 00123 const int64_t i32BitMaxUs = i32BitMaxMs*1000; 00124 const int64_t one_day = uint64_t(24*60*60)*1000000; 00125 if( last > (i32BitMaxUs-one_day) && usecs < one_day ) 00126 offset_us += i32BitMaxUs; 00127 00128 last = usecs; 00129 00130 return usecs + offset_us; 00131 } 00132 00133 int64_t MercuryTimer::FixupTimeIfBackwards( int64_t usecs ) 00134 { 00135 static int64_t last = 0; 00136 static int64_t offset_us = 0; 00137 00138 if( usecs < last ) 00139 { 00140 /* The time has moved backwards. Increase the offset by the amount we moved. */ 00141 offset_us += last - usecs; 00142 } 00143 00144 last = usecs; 00145 00146 return usecs + offset_us; 00147 } 00148 00149 MercuryTimerBenchmark BENCHMARK; 00150 00151 void MercuryTimerBenchmark::Start( const MString & sName ) 00152 { 00153 m_mTotals[sName].tTimer.Touch(); 00154 } 00155 00156 void MercuryTimerBenchmark::End( const MString & sName ) 00157 { 00158 m_mTotals[sName].fTotalTime += float(m_mTotals[sName].tTimer.Age()); 00159 m_mTotals[sName].iTimesRun++; 00160 } 00161 00162 void MercuryTimerBenchmark::Print( ) 00163 { 00164 std::map< MString, BenchPoint >::iterator c; 00165 00166 LOG.Info( "Name : Times Run : Total Time : Average Time (ms)" ); 00167 for( c = m_mTotals.begin(); c != m_mTotals.end(); c++ ) 00168 { 00169 //if ( (c->second).iTimesRun <= 0 ) 00170 LOG.Info( ssprintf( "%s : %i : %f : %f", (c->first).c_str(), (c->second).iTimesRun, (c->second).fTotalTime, (c->second).fTotalTime/float((c->second).iTimesRun)*1000.0f ) ); 00171 } 00172 } 00173 00174 /* 00175 *Copyright (c) 2001-2003 Chris Danford, Glenn Maynard 00176 * (c) 2005 Joshua Allen 00177 * (c) 2006 Charles Lohr 00178 * All rights reserved. 00179 * 00180 * Permission is hereby granted, free of charge, to any person obtaining a 00181 * copy of this software and associated documentation files (the 00182 * "Software"), to deal in the Software without restriction, including 00183 * without limitation the rights to use, copy, modify, merge, publish, 00184 * distribute, and/or sell copies of the Software, and to permit persons to 00185 * whom the Software is furnished to do so, provided that the above 00186 * copyright notice(s) and this permission notice appear in all copies of 00187 * the Software and that both the above copyright notice(s) and this 00188 * permission notice appear in supporting documentation. 00189 * 00190 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00191 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00192 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF 00193 * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS 00194 * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT 00195 * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 00196 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 00197 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00198 * PERFORMANCE OF THIS SOFTWARE. 00199 */