lltimer.cpp

Go to the documentation of this file.
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 // Locally used constants
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 // Globals and statics
00063 //---------------------------------------------------------------------------
00064 
00065 S32 gUTCOffset = 0; // viewer's offset from server UTC, in seconds
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 // Forward declarations
00076 //
00077 
00078 
00079 //---------------------------------------------------------------------------
00080 // Implementation
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); // Relinquishes time slice to any thread of equal priority, can be woken up by extended IO functions
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 //      sched_yield();
00118 }
00119 #else 
00120 # error "architecture not supported"
00121 #endif
00122 
00123 //
00124 // CPU clock/other clock frequency and count functions
00125 //
00126 
00127 #if LL_WINDOWS
00128 U64 get_clock_count()
00129 {
00130         static bool firstTime = true;
00131         static U64 offset;
00132                 // ensures that callers to this function never have to deal with wrap
00133 
00134         // QueryPerformanceCounter implementation
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 // Both Linux and Mac use gettimeofday for accurate time
00155 F64 calc_clock_frequency(unsigned int uiMeasureMSecs)
00156 {
00157         return 1000000.0; // microseconds, so 1 Mhz.
00158 }
00159 
00160 U64 get_clock_count()
00161 {
00162         // Linux clocks are in microseconds
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 // returns a U64 number that represents the number of 
00181 // microseconds since the unix epoch - Jan 1, 1970
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                 // Synch us up with local time (even though we PROBABLY don't need to, this is how it was implemented)
00192                 // Unix platforms use gettimeofday so they are synced, although this probably isn't a good assumption to
00193                 // make in the future.
00194 
00195                 gTotalTimeClockCount = (U64)(time(NULL) * gClockFrequency);
00196 #endif
00197 
00198                 // Update the last clock count
00199                 gLastTotalTimeClockCount = current_clock_count;
00200         }
00201         else
00202         {
00203                 if (current_clock_count >= gLastTotalTimeClockCount)
00204                 {
00205                         // No wrapping, we're all okay.
00206                         gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount;
00207                 }
00208                 else
00209                 {
00210                         // We've wrapped.  Compensate correctly
00211                         gTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - gLastTotalTimeClockCount) + current_clock_count;
00212                 }
00213 
00214                 // Update the last clock count
00215                 gLastTotalTimeClockCount = current_clock_count;
00216         }
00217 
00218         // Return the total clock tick count in microseconds.
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 // static
00241 U64 LLTimer::getTotalTime()
00242 {
00243         // simply call into the implementation function.
00244         return totalTime();
00245 }       
00246 
00247 // static
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                 // time has gone backward
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");    /*Flawfinder: ignore*/
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);          /* Flawfinder: ignore */
00396                         memcpy(&pci_id[5],&name[13],4);         /* Flawfinder: ignore */
00397 
00398                         for (S32 check = 0; bad_pci_list[check][0]; check++)
00399                         {
00400                                 if (!wcscmp(pci_id, bad_pci_list[check]))
00401                                 {
00402 //                                      llwarns << "unreliable PCI chipset found!! " << pci_id << endl;
00403                                         failed = TRUE;
00404                                         break;
00405                                 }
00406                         }
00407 //                      llinfo << "PCI chipset found: " << pci_id << endl;
00408                         name_len = 1024;
00409                 }
00410         }
00411 #endif
00412         return(failed);
00413 }
00414 
00416 // 
00417 // NON-MEMBER FUNCTIONS
00418 //
00420 
00421 U32 time_corrected()
00422 {
00423         U32 corrected_time = (U32)time(NULL) + gUTCOffset;
00424         return corrected_time;
00425 }
00426 
00427 
00428 // Is the current computer (in its current time zone)
00429 // observing daylight savings time?
00430 BOOL is_daylight_savings()
00431 {
00432         time_t now = time(NULL);
00433 
00434         // Internal buffer to local server time
00435         struct tm* internal_time = localtime(&now);
00436 
00437         // tm_isdst > 0  =>  daylight savings
00438         // tm_isdst = 0  =>  not daylight savings
00439         // tm_isdst < 0  =>  can't tell
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         // We subtract off the PST/PDT offset _before_ getting
00459         // "UTC" time, because this will handle wrapping around
00460         // for 5 AM UTC -> 10 PM PDT of the previous day.
00461         unix_time += pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN;
00462  
00463         // Internal buffer to PST/PDT (see above)
00464         struct tm* internal_time = gmtime(&unix_time);
00465 
00466         /*
00467         // Don't do this, this won't correctly tell you if daylight savings is active in CA or not.
00468         if (pacific_daylight_time)
00469         {
00470                 internal_time->tm_isdst = 1;
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);              /* Flawfinder: ignore */
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 //              LLEventTimer Implementation
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 

Generated on Thu Jul 1 06:09:19 2010 for Second Life Viewer by  doxygen 1.4.7