00001
00032 #include "linden_common.h"
00033
00034 #include "lltimer.h"
00035
00036 #include "u64.h"
00037
00038 #if LL_WINDOWS
00039 # define WIN32_LEAN_AND_MEAN
00040 # include <winsock2.h>
00041 # include <windows.h>
00042 #elif LL_LINUX || LL_SOLARIS
00043 # include <sys/time.h>
00044 # include <sched.h>
00045 #elif LL_DARWIN
00046 # include <sys/time.h>
00047 #else
00048 # error "architecture not supported"
00049 #endif
00050
00051
00052
00053
00054
00055 const U32 SEC_PER_DAY = 86400;
00056 const F64 SEC_TO_MICROSEC = 1000000.f;
00057 const U64 SEC_TO_MICROSEC_U64 = 1000000;
00058 const F64 USEC_TO_SEC_F64 = 0.000001;
00059
00060
00061
00062
00063
00064
00065 S32 gUTCOffset = 0;
00066 LLTimer* LLTimer::sTimer = NULL;
00067
00068 F64 gClockFrequency = 0.0;
00069 F64 gClockFrequencyInv = 0.0;
00070 F64 gClocksToMicroseconds = 0.0;
00071 U64 gTotalTimeClockCount = 0;
00072 U64 gLastTotalTimeClockCount = 0;
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 #if LL_WINDOWS
00084 void ms_sleep(long ms)
00085 {
00086 Sleep((U32)ms);
00087 }
00088
00089 void llyield()
00090 {
00091 SleepEx(0, TRUE);
00092 }
00093 #elif LL_LINUX || LL_SOLARIS
00094 void ms_sleep(long ms)
00095 {
00096 struct timespec t;
00097 t.tv_sec = ms / 1000;
00098 t.tv_nsec = (ms % 1000) * 1000000l;
00099 nanosleep(&t, NULL);
00100 }
00101
00102 void llyield()
00103 {
00104 sched_yield();
00105 }
00106 #elif LL_DARWIN
00107 void ms_sleep(long ms)
00108 {
00109 struct timespec t;
00110 t.tv_sec = ms / 1000;
00111 t.tv_nsec = (ms % 1000) * 1000000l;
00112 nanosleep(&t, NULL);
00113 }
00114
00115 void llyield()
00116 {
00117
00118 }
00119 #else
00120 # error "architecture not supported"
00121 #endif
00122
00123
00124
00125
00126
00127 #if LL_WINDOWS
00128 U64 get_clock_count()
00129 {
00130 static bool firstTime = true;
00131 static U64 offset;
00132
00133
00134
00135 LARGE_INTEGER clock_count;
00136 QueryPerformanceCounter(&clock_count);
00137 if (firstTime) {
00138 offset = clock_count.QuadPart;
00139 firstTime = false;
00140 }
00141 return clock_count.QuadPart - offset;
00142 }
00143
00144 F64 calc_clock_frequency(U32 uiMeasureMSecs)
00145 {
00146 __int64 freq;
00147 QueryPerformanceFrequency((LARGE_INTEGER *) &freq);
00148 return (F64)freq;
00149 }
00150 #endif // LL_WINDOWS
00151
00152
00153 #if LL_LINUX || LL_DARWIN || LL_SOLARIS
00154
00155 F64 calc_clock_frequency(unsigned int uiMeasureMSecs)
00156 {
00157 return 1000000.0;
00158 }
00159
00160 U64 get_clock_count()
00161 {
00162
00163 struct timeval tv;
00164 gettimeofday(&tv, NULL);
00165 return tv.tv_sec*SEC_TO_MICROSEC_U64 + tv.tv_usec;
00166 }
00167 #endif
00168
00169
00170 void update_clock_frequencies()
00171 {
00172 gClockFrequency = calc_clock_frequency(50U);
00173 gClockFrequencyInv = 1.0/gClockFrequency;
00174 gClocksToMicroseconds = gClockFrequencyInv * SEC_TO_MICROSEC;
00175 }
00176
00177
00179
00180
00181
00182 U64 totalTime()
00183 {
00184 U64 current_clock_count = get_clock_count();
00185 if (!gTotalTimeClockCount)
00186 {
00187 update_clock_frequencies();
00188 gTotalTimeClockCount = current_clock_count;
00189
00190 #if LL_WINDOWS
00191
00192
00193
00194
00195 gTotalTimeClockCount = (U64)(time(NULL) * gClockFrequency);
00196 #endif
00197
00198
00199 gLastTotalTimeClockCount = current_clock_count;
00200 }
00201 else
00202 {
00203 if (current_clock_count >= gLastTotalTimeClockCount)
00204 {
00205
00206 gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount;
00207 }
00208 else
00209 {
00210
00211 gTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - gLastTotalTimeClockCount) + current_clock_count;
00212 }
00213
00214
00215 gLastTotalTimeClockCount = current_clock_count;
00216 }
00217
00218
00219 return (U64)(gTotalTimeClockCount*gClocksToMicroseconds);
00220 }
00221
00222
00224
00225 LLTimer::LLTimer()
00226 {
00227 if (!gClockFrequency)
00228 {
00229 update_clock_frequencies();
00230 }
00231
00232 mStarted = TRUE;
00233 reset();
00234 }
00235
00236 LLTimer::~LLTimer()
00237 {
00238 }
00239
00240
00241 U64 LLTimer::getTotalTime()
00242 {
00243
00244 return totalTime();
00245 }
00246
00247
00248 F64 LLTimer::getTotalSeconds()
00249 {
00250 return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64;
00251 }
00252
00253 void LLTimer::reset()
00254 {
00255 mLastClockCount = get_clock_count();
00256 mExpirationTicks = 0;
00257 }
00258
00260
00261 U64 LLTimer::getCurrentClockCount()
00262 {
00263 return get_clock_count();
00264 }
00265
00267
00268 void LLTimer::setLastClockCount(U64 current_count)
00269 {
00270 mLastClockCount = current_count;
00271 }
00272
00274
00275 static
00276 U64 getElapsedTimeAndUpdate(U64& lastClockCount)
00277 {
00278 U64 current_clock_count = get_clock_count();
00279 U64 result;
00280
00281 if (current_clock_count >= lastClockCount)
00282 {
00283 result = current_clock_count - lastClockCount;
00284 }
00285 else
00286 {
00287
00288 result = 0;
00289 }
00290
00291 lastClockCount = current_clock_count;
00292
00293 return result;
00294 }
00295
00296
00297 F64 LLTimer::getElapsedTimeF64() const
00298 {
00299 U64 last = mLastClockCount;
00300 return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv;
00301 }
00302
00303 F32 LLTimer::getElapsedTimeF32() const
00304 {
00305 return (F32)getElapsedTimeF64();
00306 }
00307
00308 F64 LLTimer::getElapsedTimeAndResetF64()
00309 {
00310 return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv;
00311 }
00312
00313 F32 LLTimer::getElapsedTimeAndResetF32()
00314 {
00315 return (F32)getElapsedTimeAndResetF64();
00316 }
00317
00319
00320 void LLTimer::setTimerExpirySec(F32 expiration)
00321 {
00322 mExpirationTicks = get_clock_count()
00323 + (U64)((F32)(expiration * gClockFrequency));
00324 }
00325
00326 F32 LLTimer::getRemainingTimeF32()
00327 {
00328 U64 cur_ticks = get_clock_count();
00329 if (cur_ticks > mExpirationTicks)
00330 {
00331 return 0.0f;
00332 }
00333 return F32((mExpirationTicks - cur_ticks) * gClockFrequencyInv);
00334 }
00335
00336
00337 BOOL LLTimer::checkExpirationAndReset(F32 expiration)
00338 {
00339 U64 cur_ticks = get_clock_count();
00340 if (cur_ticks < mExpirationTicks)
00341 {
00342 return FALSE;
00343 }
00344
00345 mExpirationTicks = cur_ticks
00346 + (U64)((F32)(expiration * gClockFrequency));
00347 return TRUE;
00348 }
00349
00350
00351 BOOL LLTimer::hasExpired()
00352 {
00353 return (get_clock_count() >= mExpirationTicks)
00354 ? TRUE : FALSE;
00355 }
00356
00358
00359 BOOL LLTimer::knownBadTimer()
00360 {
00361 BOOL failed = FALSE;
00362
00363 #if LL_WINDOWS
00364 WCHAR bad_pci_list[][10] = {L"1039:0530",
00365 L"1039:0620",
00366 L"10B9:0533",
00367 L"10B9:1533",
00368 L"1106:0596",
00369 L"1106:0686",
00370 L"1166:004F",
00371 L"1166:0050",
00372 L"8086:7110",
00373 L"\0"
00374 };
00375
00376 HKEY hKey = NULL;
00377 LONG nResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Enum\\PCI", 0,
00378 KEY_EXECUTE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey);
00379
00380 WCHAR name[1024];
00381 DWORD name_len = 1024;
00382 FILETIME scrap;
00383
00384 S32 key_num = 0;
00385 WCHAR pci_id[10];
00386
00387 wcscpy(pci_id, L"0000:0000");
00388
00389 while (nResult == ERROR_SUCCESS)
00390 {
00391 nResult = ::RegEnumKeyEx(hKey, key_num++, name, &name_len, NULL, NULL, NULL, &scrap);
00392
00393 if (nResult == ERROR_SUCCESS)
00394 {
00395 memcpy(&pci_id[0],&name[4],4);
00396 memcpy(&pci_id[5],&name[13],4);
00397
00398 for (S32 check = 0; bad_pci_list[check][0]; check++)
00399 {
00400 if (!wcscmp(pci_id, bad_pci_list[check]))
00401 {
00402
00403 failed = TRUE;
00404 break;
00405 }
00406 }
00407
00408 name_len = 1024;
00409 }
00410 }
00411 #endif
00412 return(failed);
00413 }
00414
00416
00417
00418
00420
00421 U32 time_corrected()
00422 {
00423 U32 corrected_time = (U32)time(NULL) + gUTCOffset;
00424 return corrected_time;
00425 }
00426
00427
00428
00429
00430 BOOL is_daylight_savings()
00431 {
00432 time_t now = time(NULL);
00433
00434
00435 struct tm* internal_time = localtime(&now);
00436
00437
00438
00439
00440 return (internal_time->tm_isdst > 0);
00441 }
00442
00443
00444 struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time)
00445 {
00446 time_t unix_time = (time_t)utc_time;
00447
00448 S32 pacific_offset_hours;
00449 if (pacific_daylight_time)
00450 {
00451 pacific_offset_hours = -7;
00452 }
00453 else
00454 {
00455 pacific_offset_hours = -8;
00456 }
00457
00458
00459
00460
00461 unix_time += pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN;
00462
00463
00464 struct tm* internal_time = gmtime(&unix_time);
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 return internal_time;
00475 }
00476
00477
00478 void microsecondsToTimecodeString(U64 current_time, char *tcstring)
00479 {
00480 U64 hours;
00481 U64 minutes;
00482 U64 seconds;
00483 U64 frames;
00484 U64 subframes;
00485
00486 hours = current_time / (U64)3600000000ul;
00487 minutes = current_time / (U64)60000000;
00488 minutes %= 60;
00489 seconds = current_time / (U64)1000000;
00490 seconds %= 60;
00491 frames = current_time / (U64)41667;
00492 frames %= 24;
00493 subframes = current_time / (U64)42;
00494 subframes %= 100;
00495
00496 sprintf(tcstring,"%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes);
00497 }
00498
00499
00500 void secondsToTimecodeString(F32 current_time, char *tcstring)
00501 {
00502 microsecondsToTimecodeString((U64)((F64)(SEC_TO_MICROSEC*current_time)), tcstring);
00503 }
00504
00505
00507
00508
00509
00511
00512 std::list<LLEventTimer*> LLEventTimer::sActiveList;
00513
00514 LLEventTimer::LLEventTimer(F32 period)
00515 : mEventTimer()
00516 {
00517 mPeriod = period;
00518 sActiveList.push_back(this);
00519 }
00520
00521 LLEventTimer::~LLEventTimer()
00522 {
00523 sActiveList.remove(this);
00524 }
00525
00526 void LLEventTimer::updateClass()
00527 {
00528 std::list<LLEventTimer*> completed_timers;
00529 for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
00530 {
00531 LLEventTimer* timer = *iter++;
00532 F32 et = timer->mEventTimer.getElapsedTimeF32();
00533 if (et > timer->mPeriod) {
00534 timer->mEventTimer.reset();
00535 if ( timer->tick() )
00536 {
00537 completed_timers.push_back( timer );
00538 }
00539 }
00540 }
00541
00542 if ( completed_timers.size() > 0 )
00543 {
00544 for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
00545 completed_iter != completed_timers.end();
00546 completed_iter++ )
00547 {
00548 delete *completed_iter;
00549 }
00550 }
00551 }
00552