lltimer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /**
  2. * @file lltimer.cpp
  3. * @brief Cross-platform objects for doing timing
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewergpl$
  6. *
  7. * Copyright (c) 2000-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #if !LL_WINDOWS
  34. # include <errno.h>
  35. # include <time.h>
  36. # include <unistd.h>
  37. # if LL_DARWIN
  38. # include <sys/time.h>
  39. # endif
  40. #endif
  41. #include "lltimer.h"
  42. //---------------------------------------------------------------------------
  43. // Globals and static variables
  44. //---------------------------------------------------------------------------
  45. // Viewer's offset from server UTC, in seconds
  46. S32 gUTCOffset = 0;
  47. static F64 sClockFrequency = 0.0;
  48. static F64 sClockFrequencyInv = 0.0;
  49. static F64 sClocksToMicroseconds = 0.0;
  50. static U64 sTotalTimeClockCount = 0;
  51. static U64 sLastTotalTimeClockCount = 0;
  52. static U64 sLastClockDelta = 0;
  53. LLTimer* LLTimer::sTimer = NULL;
  54. // This is the amount of time (one bisextile year in micro seconds) we allow
  55. // for the system clock to be set backwards while the viewer is ruunning.
  56. constexpr U64 ONE_YEAR_MSEC = U64(366 * 24 * 3600) * SEC_TO_MICROSEC_U64;
  57. // Helper function
  58. void update_clock_frequencies()
  59. {
  60. #if LL_WINDOWS
  61. __int64 freq;
  62. QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
  63. sClockFrequency = (F64)freq;
  64. #else
  65. // Both Linux and Mac use gettimeofday() for accurate time
  66. sClockFrequency = 1000000.0; // microseconds, so 1 MHz.
  67. #endif
  68. sClockFrequencyInv = 1.0 / sClockFrequency;
  69. sClocksToMicroseconds = sClockFrequencyInv * SEC_TO_MICROSEC;
  70. }
  71. //---------------------------------------------------------------------------
  72. // LLTimer implementation
  73. //---------------------------------------------------------------------------
  74. //static
  75. void LLTimer::initClass()
  76. {
  77. if (!sTimer)
  78. {
  79. sTimer = new LLTimer;
  80. }
  81. }
  82. //static
  83. void LLTimer::cleanupClass()
  84. {
  85. if (sTimer)
  86. {
  87. delete sTimer;
  88. sTimer = NULL;
  89. }
  90. }
  91. LLTimer::LLTimer()
  92. {
  93. if (!sClockFrequency)
  94. {
  95. update_clock_frequencies();
  96. }
  97. mStarted = true;
  98. reset();
  99. }
  100. // Returns a seconds count since UNIX epoch, with a milli-second resolution.
  101. // This method is slower (under Linux or Windows, at least) than the other
  102. // methods below (such as getCurrentClockCount()), but the latter may return
  103. // (under Linux or Windows) a "random" time, which is usually the time ellapsed
  104. // since the computer booted up.
  105. // This method is used by LLDate::now() and the environment "time of day"
  106. // implementations. It is NOT suitable for high accurracy or high resolution
  107. // applications.
  108. //static
  109. F64 LLTimer::getEpochSeconds()
  110. {
  111. #if LL_WINDOWS
  112. static F64 offset = 0.0;
  113. static F64 last_update = 0.0;
  114. LARGE_INTEGER clock;
  115. if (last_update == 0.0)
  116. {
  117. // We need to update the offset from Epoch for performance counter...
  118. update_clock_frequencies(); // Make sure sClockFrequencyInv is set
  119. // Get the number of *100ns* ticks since January 1st, *1601* UTC.
  120. // Using GetSystemTimeAsFileTime() is more complex but way more
  121. // accurate than using time() (which is a 1 second resolution timer).
  122. FILETIME ft;
  123. GetSystemTimeAsFileTime(&ft);
  124. // Get the current performance counter value
  125. QueryPerformanceCounter(&clock);
  126. // Compute the current time in seconds since Epoch
  127. ULARGE_INTEGER ft_value;
  128. ft_value.LowPart = ft.dwLowDateTime;
  129. ft_value.HighPart = ft.dwHighDateTime;
  130. constexpr F64 SEC_PER_100NS = 1.0 / 10000000.0;
  131. constexpr U64 EPOCH_DELTA = 116444736000000000UL;
  132. last_update = F64(ft_value.QuadPart - EPOCH_DELTA) * SEC_PER_100NS;
  133. // And here is our offset...
  134. offset = last_update - F64(clock.QuadPart) * sClockFrequencyInv;
  135. }
  136. else
  137. {
  138. // Get the current performance counter value
  139. QueryPerformanceCounter(&clock);
  140. }
  141. // Compute time from performance counter value and Epoch offset, in seconds
  142. F64 now = F64(clock.QuadPart) * sClockFrequencyInv + offset;
  143. // Resync every 3 minutes or so, in case the computer clock would be
  144. // changed (manually or automatically, e.g. via NTP).
  145. if (now - last_update > 360.0)
  146. {
  147. last_update = 0.0;
  148. }
  149. return now;
  150. #else // LL_LINUX || LL_DARWIN
  151. // UNIX/BSD clocks are in microseconds
  152. struct timeval tv;
  153. gettimeofday(&tv, NULL);
  154. return F64(tv.tv_sec) + F64(tv.tv_usec) * SEC_PER_USEC;
  155. #endif
  156. }
  157. //static
  158. U64 LLTimer::getCurrentClockCount()
  159. {
  160. #if LL_LINUX
  161. struct timespec tv;
  162. # ifdef CLOCK_MONOTONIC_RAW // if MONOTONIC_RAW supported at build-time
  163. // Try and use a clock that is unaffected by ntp and user-triggered system
  164. // time changes... If MONOTONIC_RAW is supported at runtime (i.e. when
  165. // running on a kernel from Linux 2.6.28 onwards).
  166. if (clock_gettime(CLOCK_MONOTONIC_RAW, &tv) == -1)
  167. # endif
  168. {
  169. // If MONOTONIC_RAW is not supported, then use REALTIME
  170. clock_gettime(CLOCK_REALTIME, &tv);
  171. }
  172. return tv.tv_sec * SEC_TO_MICROSEC_U64 + tv.tv_nsec / 1000;
  173. #elif LL_WINDOWS
  174. // Ensure that callers to this method never have to deal with wrap !
  175. static bool first_time = true;
  176. static U64 offset;
  177. // QueryPerformanceCounter implementation
  178. LARGE_INTEGER clock_count;
  179. QueryPerformanceCounter(&clock_count);
  180. if (first_time)
  181. {
  182. offset = clock_count.QuadPart;
  183. first_time = false;
  184. }
  185. return clock_count.QuadPart - offset;
  186. #else // LL_DARWIN or any other UNIX/BSD-like OS
  187. struct timeval tv;
  188. gettimeofday(&tv, NULL);
  189. return tv.tv_sec * SEC_TO_MICROSEC_U64 + tv.tv_usec;
  190. #endif
  191. }
  192. // Returns a high precision usec since computer boot up time
  193. //static
  194. U64 LLTimer::totalTime()
  195. {
  196. U64 cur_clock_count = getCurrentClockCount();
  197. if (!sTotalTimeClockCount) // First call ?
  198. {
  199. update_clock_frequencies();
  200. sLastClockDelta = cur_clock_count;
  201. }
  202. // Time not going backward or counter wrapping, we are all okay.
  203. else if (cur_clock_count >= sLastTotalTimeClockCount)
  204. {
  205. sLastClockDelta = cur_clock_count - sLastTotalTimeClockCount;
  206. }
  207. // Allow setting the system time backwards by one year; an actual wrapping
  208. // would yield a much larger delta anyway...
  209. else if (cur_clock_count + ONE_YEAR_MSEC > sLastTotalTimeClockCount)
  210. {
  211. // It is a pretty common occurrence that we get 1 or 2 ticks backwards
  212. // on some systems, so do not spam the log with this.
  213. LL_DEBUGS("Timer") << "Clock count went backwards. Last clock count = "
  214. << sLastTotalTimeClockCount
  215. << " - New clock count = " << cur_clock_count
  216. << " - Using last clock delta as an estimation of ellapsed time: "
  217. << sLastClockDelta << LL_ENDL;
  218. // Use previous clock delta as an estimation...
  219. }
  220. // We must have wrapped. Compensate accordingly.
  221. else
  222. {
  223. llwarns << "Clock count wrapping detected. Last clock count = "
  224. << sLastTotalTimeClockCount << " - New clock count = "
  225. << cur_clock_count << llendl;
  226. sLastClockDelta = (0xFFFFFFFFFFFFFFFFULL - sLastTotalTimeClockCount) +
  227. cur_clock_count;;
  228. }
  229. sTotalTimeClockCount += sLastClockDelta;
  230. // Update the last clock count
  231. sLastTotalTimeClockCount = cur_clock_count;
  232. // Return the total clock tick count in microseconds.
  233. return (U64)(sTotalTimeClockCount * sClocksToMicroseconds);
  234. }
  235. F64 LLTimer::getElapsedTimeF64() const
  236. {
  237. U64 last = mLastClockCount;
  238. return (F64)getElapsedTimeAndUpdate(last) * sClockFrequencyInv;
  239. }
  240. //static
  241. U64 LLTimer::getElapsedTimeAndUpdate(U64& last_clock_count)
  242. {
  243. U64 cur_clock_count = getCurrentClockCount();
  244. U64 result;
  245. if (cur_clock_count >= last_clock_count)
  246. {
  247. result = cur_clock_count - last_clock_count;
  248. }
  249. else
  250. {
  251. // Time has gone backward
  252. result = 0;
  253. }
  254. last_clock_count = cur_clock_count;
  255. return result;
  256. }
  257. F64 LLTimer::getElapsedTimeAndResetF64()
  258. {
  259. return (F64)getElapsedTimeAndUpdate(mLastClockCount) * sClockFrequencyInv;
  260. }
  261. void LLTimer::setTimerExpirySec(F32 expiration)
  262. {
  263. mExpirationTicks = getCurrentClockCount() +
  264. (U64)((F32)(expiration * sClockFrequency));
  265. }
  266. F64 LLTimer::getRemainingTimeF64() const
  267. {
  268. U64 cur_ticks = getCurrentClockCount();
  269. if (cur_ticks > mExpirationTicks)
  270. {
  271. return 0.0;
  272. }
  273. return F64(mExpirationTicks - cur_ticks) * sClockFrequencyInv;
  274. }
  275. bool LLTimer::checkExpirationAndReset(F32 expiration)
  276. {
  277. U64 cur_ticks = getCurrentClockCount();
  278. if (cur_ticks < mExpirationTicks)
  279. {
  280. return false;
  281. }
  282. mExpirationTicks = cur_ticks + (U64)((F32)(expiration * sClockFrequency));
  283. return true;
  284. }
  285. ///////////////////////////////////////////////////////////////////////////////
  286. // NON-MEMBER FUNCTIONS
  287. ///////////////////////////////////////////////////////////////////////////////
  288. void ms_sleep(U32 ms)
  289. {
  290. #if LL_WINDOWS
  291. // The Sleep() function is way too inaccurate, and already sleeps for
  292. // longer than a ms... So let's not make things worst and just "relinquish
  293. // the remainder of our time slice" (as documented by Microsoft) when
  294. // requesting less than a 3ms sleep time. HB
  295. if (ms < 3)
  296. {
  297. ms = 0;
  298. }
  299. Sleep(ms);
  300. #else
  301. usleep(1000 * ms);
  302. #endif
  303. }
  304. time_t time_corrected()
  305. {
  306. return time(NULL) + gUTCOffset;
  307. }
  308. time_t computer_time()
  309. {
  310. return time(NULL);
  311. }
  312. struct tm* utc_time_to_tm(time_t utc_time)
  313. {
  314. struct tm* internal_time = gmtime(&utc_time);
  315. return internal_time;
  316. }
  317. struct tm* local_time_to_tm(time_t local_time)
  318. {
  319. struct tm* internal_time = localtime(&local_time);
  320. return internal_time;
  321. }
  322. struct tm* utc_to_pacific_time(time_t utc_time, bool pacific_daylight_time)
  323. {
  324. S32 pacific_offset_hours;
  325. if (pacific_daylight_time)
  326. {
  327. pacific_offset_hours = 7;
  328. }
  329. else
  330. {
  331. pacific_offset_hours = 8;
  332. }
  333. // We subtract off the PST/PDT offset _before_ getting "UTC" time, because
  334. // this will handle wrapping around for 5 AM UTC -> 10 PM PDT of the
  335. // previous day.
  336. utc_time -= pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN;
  337. // Internal buffer to PST/PDT (see above)
  338. struct tm* internal_time = gmtime(&utc_time);
  339. #if 0 // Do not do this, this would not correctly tell you if daylight
  340. // savings is active in CA or not.
  341. if (pacific_daylight_time)
  342. {
  343. internal_time->tm_isdst = 1;
  344. }
  345. #endif
  346. return internal_time;
  347. }
  348. void microsecondsToTimecodeString(U64 current_time, std::string& tcstring)
  349. {
  350. U64 hours = current_time / (U64)3600000000ul;
  351. U64 minutes = current_time / (U64)60000000;
  352. minutes %= 60;
  353. U64 seconds = current_time / (U64)1000000;
  354. seconds %= 60;
  355. U64 frames = current_time / (U64)41667;
  356. frames %= 24;
  357. U64 subframes = current_time / (U64)42;
  358. subframes %= 100;
  359. tcstring = llformat("%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",
  360. (int)hours, (int)minutes, (int)seconds,
  361. (int)frames, (int)subframes);
  362. }
  363. void secondsToTimecodeString(F32 current_time, std::string& tcstring)
  364. {
  365. microsecondsToTimecodeString((U64)((F64)(SEC_TO_MICROSEC * current_time)),
  366. tcstring);
  367. }
  368. void timeToFormattedString(time_t time, const char* format,
  369. std::string& timestr)
  370. {
  371. char buffer[256];
  372. struct tm* t = localtime(&time);
  373. strftime(buffer, 255, format, t);
  374. timestr = (const char*)buffer;
  375. }
  376. void timeStructToFormattedString(struct tm* time, const std::string& format,
  377. std::string& timestr)
  378. {
  379. char buffer[256];
  380. strftime(buffer, 255, format.c_str(), time);
  381. timestr = (const char*)buffer;
  382. }