aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/lltimer.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcommon/lltimer.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcommon/lltimer.cpp')
-rw-r--r--linden/indra/llcommon/lltimer.cpp537
1 files changed, 537 insertions, 0 deletions
diff --git a/linden/indra/llcommon/lltimer.cpp b/linden/indra/llcommon/lltimer.cpp
new file mode 100644
index 0000000..07bd543
--- /dev/null
+++ b/linden/indra/llcommon/lltimer.cpp
@@ -0,0 +1,537 @@
1/**
2 * @file lltimer.cpp
3 * @brief Cross-platform objects for doing timing
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "lltimer.h"
31
32#include "u64.h"
33
34#if LL_WINDOWS
35# define WIN32_LEAN_AND_MEAN
36# include <winsock2.h>
37# include <windows.h>
38# include <time.h>
39#elif LL_LINUX
40# include <time.h>
41# include <sys/time.h>
42# include <sched.h>
43#elif LL_DARWIN
44# include <time.h>
45# include <sys/time.h>
46#else
47# error "architecture not supported"
48#endif
49
50
51//
52// Locally used constants
53//
54const U32 SEC_PER_DAY = 86400;
55const F64 SEC_TO_MICROSEC = 1000000.f;
56const U64 SEC_TO_MICROSEC_U64 = 1000000;
57const F64 USEC_TO_SEC_F64 = 0.000001;
58
59
60//---------------------------------------------------------------------------
61// Globals and statics
62//---------------------------------------------------------------------------
63
64S32 gUTCOffset = 0; // viewer's offset from server UTC, in seconds
65LLTimer* LLTimer::sTimer = NULL;
66
67F64 gClockFrequency = 0.0;
68F64 gClockFrequencyInv = 0.0;
69F64 gClocksToMicroseconds = 0.0;
70U64 gTotalTimeClockCount = 0;
71U64 gLastTotalTimeClockCount = 0;
72
73//
74// Forward declarations
75//
76
77
78//---------------------------------------------------------------------------
79// Implementation
80//---------------------------------------------------------------------------
81
82#if LL_WINDOWS
83void ms_sleep(long ms)
84{
85 Sleep((U32)ms);
86}
87
88void llyield()
89{
90 SleepEx(0, TRUE); // Relinquishes time slice to any thread of equal priority, can be woken up by extended IO functions
91}
92#elif LL_LINUX
93void ms_sleep(long ms)
94{
95 struct timespec t;
96 t.tv_sec = ms / 1000;
97 t.tv_nsec = (ms % 1000) * 1000000l;
98 nanosleep(&t, NULL);
99}
100
101void llyield()
102{
103 sched_yield();
104}
105#elif LL_DARWIN
106void ms_sleep(long ms)
107{
108 struct timespec t;
109 t.tv_sec = ms / 1000;
110 t.tv_nsec = (ms % 1000) * 1000000l;
111 nanosleep(&t, NULL);
112}
113
114void llyield()
115{
116// sched_yield();
117}
118#else
119# error "architecture not supported"
120#endif
121
122//
123// CPU clock/other clock frequency and count functions
124//
125
126#if LL_WINDOWS
127U64 get_clock_count()
128{
129 static bool firstTime = true;
130 static U64 offset;
131 // ensures that callers to this function never have to deal with wrap
132
133 // QueryPerformanceCounter implementation
134 LARGE_INTEGER clock_count;
135 QueryPerformanceCounter(&clock_count);
136 if (firstTime) {
137 offset = clock_count.QuadPart;
138 firstTime = false;
139 }
140 return clock_count.QuadPart - offset;
141}
142
143F64 calc_clock_frequency(U32 uiMeasureMSecs)
144{
145 __int64 freq;
146 QueryPerformanceFrequency((LARGE_INTEGER *) &freq);
147 return (F64)freq;
148}
149#endif // LL_WINDOWS
150
151
152#if LL_LINUX || LL_DARWIN
153// Both Linux and Mac use gettimeofday for accurate time
154F64 calc_clock_frequency(unsigned int uiMeasureMSecs)
155{
156 return 1000000.0; // microseconds, so 1 Mhz.
157}
158
159U64 get_clock_count()
160{
161 // Linux clocks are in microseconds
162 struct timeval tv;
163 gettimeofday(&tv, NULL);
164 return tv.tv_sec*SEC_TO_MICROSEC_U64 + tv.tv_usec;
165}
166#endif
167
168
169void update_clock_frequencies()
170{
171 gClockFrequency = calc_clock_frequency(50);
172 gClockFrequencyInv = 1.0/gClockFrequency;
173 gClocksToMicroseconds = gClockFrequencyInv * SEC_TO_MICROSEC;
174}
175
176
177///////////////////////////////////////////////////////////////////////////////
178
179// returns a U64 number that represents the number of
180// microseconds since the unix epoch - Jan 1, 1970
181U64 totalTime()
182{
183 U64 current_clock_count = get_clock_count();
184 if (!gTotalTimeClockCount)
185 {
186 update_clock_frequencies();
187 gTotalTimeClockCount = current_clock_count;
188
189#if LL_WINDOWS
190 // Synch us up with local time (even though we PROBABLY don't need to, this is how it was implemented)
191 // Unix platforms use gettimeofday so they are synced, although this probably isn't a good assumption to
192 // make in the future.
193
194 gTotalTimeClockCount = (U64)(time(NULL) * gClockFrequency);
195#endif
196
197 // Update the last clock count
198 gLastTotalTimeClockCount = current_clock_count;
199 }
200 else
201 {
202 if (current_clock_count >= gLastTotalTimeClockCount)
203 {
204 // No wrapping, we're all okay.
205 gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount;
206 }
207 else
208 {
209 // We've wrapped. Compensate correctly
210 gTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - gLastTotalTimeClockCount) + current_clock_count;
211 }
212
213 // Update the last clock count
214 gLastTotalTimeClockCount = current_clock_count;
215 }
216
217 // Return the total clock tick count in microseconds.
218 return (U64)(gTotalTimeClockCount*gClocksToMicroseconds);
219}
220
221
222///////////////////////////////////////////////////////////////////////////////
223
224LLTimer::LLTimer()
225{
226 if (!gClockFrequency)
227 {
228 update_clock_frequencies();
229 }
230
231 mStarted = TRUE;
232 reset();
233}
234
235LLTimer::~LLTimer()
236{
237}
238
239// static
240U64 LLTimer::getTotalTime()
241{
242 // simply call into the implementation function.
243 return totalTime();
244}
245
246// static
247F64 LLTimer::getTotalSeconds()
248{
249 return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64;
250}
251
252void LLTimer::reset()
253{
254 mLastClockCount = get_clock_count();
255 mExpirationTicks = 0;
256}
257
258///////////////////////////////////////////////////////////////////////////////
259
260U64 LLTimer::getCurrentClockCount()
261{
262 return get_clock_count();
263}
264
265///////////////////////////////////////////////////////////////////////////////
266
267void LLTimer::setLastClockCount(U64 current_count)
268{
269 mLastClockCount = current_count;
270}
271
272///////////////////////////////////////////////////////////////////////////////
273
274static
275U64 getElapsedTimeAndUpdate(U64& lastClockCount)
276{
277 U64 current_clock_count = get_clock_count();
278 U64 result;
279
280 if (current_clock_count >= lastClockCount)
281 {
282 result = current_clock_count - lastClockCount;
283 }
284 else
285 {
286 // time has gone backward
287 result = 0;
288 }
289
290 lastClockCount = current_clock_count;
291
292 return result;
293}
294
295
296F64 LLTimer::getElapsedTimeF64() const
297{
298 U64 last = mLastClockCount;
299 return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv;
300}
301
302F32 LLTimer::getElapsedTimeF32() const
303{
304 return (F32)getElapsedTimeF64();
305}
306
307F64 LLTimer::getElapsedTimeAndResetF64()
308{
309 return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv;
310}
311
312F32 LLTimer::getElapsedTimeAndResetF32()
313{
314 return (F32)getElapsedTimeAndResetF64();
315}
316
317///////////////////////////////////////////////////////////////////////////////
318
319void LLTimer::setTimerExpirySec(F32 expiration)
320{
321 mExpirationTicks = get_clock_count()
322 + (U64)((F32)(expiration * gClockFrequency));
323}
324
325F32 LLTimer::getRemainingTimeF32()
326{
327 U64 cur_ticks = get_clock_count();
328 if (cur_ticks > mExpirationTicks)
329 {
330 return 0.0f;
331 }
332 return F32((mExpirationTicks - cur_ticks) * gClockFrequencyInv);
333}
334
335
336BOOL LLTimer::checkExpirationAndReset(F32 expiration)
337{
338 U64 cur_ticks = get_clock_count();
339 if (cur_ticks < mExpirationTicks)
340 {
341 return FALSE;
342 }
343
344 mExpirationTicks = cur_ticks
345 + (U64)((F32)(expiration * gClockFrequency));
346 return TRUE;
347}
348
349
350BOOL LLTimer::hasExpired()
351{
352 return (get_clock_count() >= mExpirationTicks)
353 ? TRUE : FALSE;
354}
355
356///////////////////////////////////////////////////////////////////////////////
357
358BOOL LLTimer::knownBadTimer()
359{
360 BOOL failed = FALSE;
361
362#if LL_WINDOWS
363 WCHAR bad_pci_list[][10] = {L"1039:0530",
364 L"1039:0620",
365 L"10B9:0533",
366 L"10B9:1533",
367 L"1106:0596",
368 L"1106:0686",
369 L"1166:004F",
370 L"1166:0050",
371 L"8086:7110",
372 L"\0"
373 };
374
375 HKEY hKey = NULL;
376 LONG nResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Enum\\PCI", 0,
377 KEY_EXECUTE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey);
378
379 WCHAR name[1024];
380 DWORD name_len = 1024;
381 FILETIME scrap;
382
383 S32 key_num = 0;
384 WCHAR pci_id[10];
385
386 wcscpy(pci_id, L"0000:0000"); /*Flawfinder: ignore*/
387
388 while (nResult == ERROR_SUCCESS)
389 {
390 nResult = ::RegEnumKeyEx(hKey, key_num++, name, &name_len, NULL, NULL, NULL, &scrap);
391
392 if (nResult == ERROR_SUCCESS)
393 {
394 memcpy(&pci_id[0],&name[4],4); /* Flawfinder: ignore */
395 memcpy(&pci_id[5],&name[13],4); /* Flawfinder: ignore */
396
397 for (S32 check = 0; bad_pci_list[check][0]; check++)
398 {
399 if (!wcscmp(pci_id, bad_pci_list[check]))
400 {
401// llwarns << "unreliable PCI chipset found!! " << pci_id << endl;
402 failed = TRUE;
403 break;
404 }
405 }
406// llinfo << "PCI chipset found: " << pci_id << endl;
407 name_len = 1024;
408 }
409 }
410#endif
411 return(failed);
412}
413
414///////////////////////////////////////////////////////////////////////////////
415//
416// NON-MEMBER FUNCTIONS
417//
418///////////////////////////////////////////////////////////////////////////////
419
420U32 time_corrected()
421{
422 U32 corrected_time = (U32)time(NULL) + gUTCOffset;
423 return corrected_time;
424}
425
426
427// Is the current computer (in its current time zone)
428// observing daylight savings time?
429BOOL is_daylight_savings()
430{
431 time_t now = time(NULL);
432
433 // Internal buffer to local server time
434 struct tm* internal_time = localtime(&now);
435
436 // tm_isdst > 0 => daylight savings
437 // tm_isdst = 0 => not daylight savings
438 // tm_isdst < 0 => can't tell
439 return (internal_time->tm_isdst > 0);
440}
441
442
443struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time)
444{
445 time_t unix_time = (time_t)utc_time;
446
447 S32 pacific_offset_hours;
448 if (pacific_daylight_time)
449 {
450 pacific_offset_hours = -7;
451 }
452 else
453 {
454 pacific_offset_hours = -8;
455 }
456
457 // We subtract off the PST/PDT offset _before_ getting
458 // "UTC" time, because this will handle wrapping around
459 // for 5 AM UTC -> 10 PM PDT of the previous day.
460 unix_time += pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN;
461
462 // Internal buffer to PST/PDT (see above)
463 struct tm* internal_time = gmtime(&unix_time);
464
465 /*
466 // Don't do this, this won't correctly tell you if daylight savings is active in CA or not.
467 if (pacific_daylight_time)
468 {
469 internal_time->tm_isdst = 1;
470 }
471 */
472
473 return internal_time;
474}
475
476
477void microsecondsToTimecodeString(U64 current_time, char *tcstring)
478{
479 U64 hours;
480 U64 minutes;
481 U64 seconds;
482 U64 frames;
483 U64 subframes;
484
485 hours = current_time / (U64)3600000000ul;
486 minutes = current_time / (U64)60000000;
487 minutes %= 60;
488 seconds = current_time / (U64)1000000;
489 seconds %= 60;
490 frames = current_time / (U64)41667;
491 frames %= 24;
492 subframes = current_time / (U64)42;
493 subframes %= 100;
494
495 sprintf(tcstring,"%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes); /* Flawfinder: ignore */
496}
497
498
499void secondsToTimecodeString(F32 current_time, char *tcstring)
500{
501 microsecondsToTimecodeString((U64)((F64)(SEC_TO_MICROSEC*current_time)), tcstring);
502}
503
504
505//////////////////////////////////////////////////////////////////////////////
506//
507// LLEventTimer Implementation
508//
509//////////////////////////////////////////////////////////////////////////////
510
511std::list<LLEventTimer*> LLEventTimer::sActiveList;
512
513LLEventTimer::LLEventTimer(F32 period)
514: mTimer()
515{
516 mPeriod = period;
517 sActiveList.push_back(this);
518}
519
520LLEventTimer::~LLEventTimer()
521{
522 sActiveList.remove(this);
523}
524
525void LLEventTimer::updateClass()
526{
527 for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
528 {
529 LLEventTimer* timer = *iter++;
530 F32 et = timer->mTimer.getElapsedTimeF32();
531 if (et > timer->mPeriod) {
532 timer->mTimer.reset();
533 timer->tick();
534 }
535 }
536}
537