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