X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2555c77a816d66498204d68c80d2c1c5eb47bc6e..08670ea85abf4b4946a9ce64971b591d7b1ee30b:/src/common/stopwatch.cpp diff --git a/src/common/stopwatch.cpp b/src/common/stopwatch.cpp index 901693c3e0..f36696dff0 100644 --- a/src/common/stopwatch.cpp +++ b/src/common/stopwatch.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: common/stopwatch.cpp +// Name: src/common/stopwatch.cpp // Purpose: wxStopWatch and other non-GUI stuff from wx/timer.h // Author: // Original version by Julian Smart @@ -10,7 +10,7 @@ // Created: 20.06.2003 (extracted from common/timercmn.cpp) // RCS-ID: $Id$ // Copyright: (c) 1998-2003 wxWidgets Team -// License: wxWindows license +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -28,135 +28,137 @@ #pragma hdrstop #endif +#include "wx/stopwatch.h" + +#if wxUSE_STOPWATCH + #ifndef WX_PRECOMP - #include "wx/intl.h" + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif #include "wx/log.h" + #include "wx/thread.h" #endif //WX_PRECOMP -#include "wx/longlong.h" -#include "wx/stopwatch.h" +// ============================================================================ +// implementation +// ============================================================================ // ---------------------------------------------------------------------------- -// System headers +// wxStopWatch // ---------------------------------------------------------------------------- -#if defined(__WIN32__) - #include "wx/msw/wrapwin.h" -#endif +namespace +{ -#if defined(__WIN32__) && !defined(HAVE_FTIME) && !defined(__MWERKS__) && !defined(__WXWINCE__) - #define HAVE_FTIME -#endif +#ifdef __WXMSW__ -#if defined(__VISAGECPP__) && !defined(HAVE_FTIME) - #define HAVE_FTIME -# if __IBMCPP__ >= 400 - # define ftime(x) _ftime(x) -# endif -#endif +struct PerfCounter +{ + PerfCounter() + { + init = false; + } -#if defined(__MWERKS__) && defined(__WXMSW__) -# undef HAVE_FTIME -# undef HAVE_GETTIMEOFDAY -#endif + bool CanBeUsed() const + { + return freq.QuadPart != 0; + } -#ifndef __WXWINCE__ -#include -#else -#include "wx/msw/private.h" -#include "wx/msw/wince/time.h" -#endif + wxCRIT_SECT_DECLARE_MEMBER(cs); + LARGE_INTEGER freq; + bool init; +} gs_perfCounter; -#if !defined(__WXMAC__) && !defined(__WXWINCE__) - #include // for time_t -#endif +#endif // __WXMSW__ -#if defined(HAVE_GETTIMEOFDAY) - #include - #include -#elif defined(HAVE_FTIME) - #include -#endif +const int MILLISECONDS_PER_SECOND = 1000; +const int MICROSECONDS_PER_MILLISECOND = 1000; +const int MICROSECONDS_PER_SECOND = 1000*1000; -#ifdef __WXMAC__ - #include - #include -#endif +} // anonymous namespace -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- +void wxStopWatch::DoStart() +{ +#ifdef __WXMSW__ + if ( !gs_perfCounter.init ) + { + wxCRIT_SECT_LOCKER(lock, gs_perfCounter.cs); + ::QueryPerformanceFrequency(&gs_perfCounter.freq); -// on some really old systems gettimeofday() doesn't have the second argument, -// define wxGetTimeOfDay() to hide this difference -#ifdef HAVE_GETTIMEOFDAY - #ifdef WX_GETTIMEOFDAY_NO_TZ - struct timezone; - #define wxGetTimeOfDay(tv, tz) gettimeofday(tv) - #else - #define wxGetTimeOfDay(tv, tz) gettimeofday((tv), (tz)) - #endif -#endif // HAVE_GETTIMEOFDAY + // Just a sanity check: it's not supposed to happen but verify that + // ::QueryPerformanceCounter() succeeds so that we can really use it. + LARGE_INTEGER counter; + if ( !::QueryPerformanceCounter(&counter) ) + { + wxLogDebug("QueryPerformanceCounter() unexpected failed (%s), " + "will not use it.", wxSysErrorMsg()); -// ============================================================================ -// implementation -// ============================================================================ + gs_perfCounter.freq.QuadPart = 0; + } -// ---------------------------------------------------------------------------- -// wxStopWatch -// ---------------------------------------------------------------------------- + gs_perfCounter.init = true; + } +#endif // __WXMSW__ -#if wxUSE_STOPWATCH + m_t0 = GetCurrentClockValue(); +} -void wxStopWatch::Start(long t) +wxLongLong wxStopWatch::GetClockFreq() const { -#ifdef 0 -__WXMSW__ - LARGE_INTEGER frequency_li; - ::QueryPerformanceFrequency( &frequency_li ); - m_frequency = frequency_li.QuadPart; - if (m_frequency == 0) - { - m_t0 = wxGetLocalTimeMillis() - t; - } - else - { - LARGE_INTEGER counter_li; - ::QueryPerformanceCounter( &counter_li ); - wxLongLong counter = counter_li.QuadPart; - m_t0 = (counter * 10000 / m_frequency) - t*10; - } -#else - m_t0 = wxGetLocalTimeMillis() - t; -#endif - m_pause = 0; +#ifdef __WXMSW__ + // Under MSW we use the high resolution performance counter timer which has + // its own frequency (usually related to the CPU clock speed). + if ( gs_perfCounter.CanBeUsed() ) + return gs_perfCounter.freq.QuadPart; +#endif // __WXMSW__ + +#ifdef HAVE_GETTIMEOFDAY + // With gettimeofday() we can have nominally microsecond precision and + // while this is not the case in practice, it's still better than + // millisecond. + return MICROSECONDS_PER_SECOND; +#else // !HAVE_GETTIMEOFDAY + // Currently milliseconds are used everywhere else. + return MILLISECONDS_PER_SECOND; +#endif // HAVE_GETTIMEOFDAY/!HAVE_GETTIMEOFDAY +} + +void wxStopWatch::Start(long t0) +{ + // Calling Start() makes the stop watch run however many times it was + // paused before. m_pauseCount = 0; + + DoStart(); + + m_t0 -= (wxLongLong(t0)*GetClockFreq())/MILLISECONDS_PER_SECOND; } -long wxStopWatch::GetElapsedTime() const +wxLongLong wxStopWatch::GetCurrentClockValue() const { -#ifdef 0 -__WXMSW__ - if (m_frequency == 0) - { - return (wxGetLocalTimeMillis() - m_t0).GetLo(); - } - else +#ifdef __WXMSW__ + if ( gs_perfCounter.CanBeUsed() ) { - LARGE_INTEGER counter_li; - ::QueryPerformanceCounter( &counter_li ); - wxLongLong counter = counter_li.QuadPart; - wxLongLong res = (counter * 10000 / m_frequency) - m_t0; - return res.GetLo() / 10; + LARGE_INTEGER counter; + ::QueryPerformanceCounter(&counter); + return counter.QuadPart; } -#else - return (wxGetLocalTimeMillis() - m_t0).GetLo(); -#endif +#endif // __WXMSW__ + +#ifdef HAVE_GETTIMEOFDAY + return wxGetUTCTimeUSec(); +#else // !HAVE_GETTIMEOFDAY + return wxGetUTCTimeMillis(); +#endif // HAVE_GETTIMEOFDAY/!HAVE_GETTIMEOFDAY } -long wxStopWatch::Time() const +wxLongLong wxStopWatch::TimeInMicro() const { - return m_pauseCount ? m_pause : GetElapsedTime(); + const wxLongLong elapsed(m_pauseCount ? m_elapsedBeforePause + : GetCurrentClockValue() - m_t0); + + return (elapsed*MICROSECONDS_PER_SECOND)/GetClockFreq(); } #endif // wxUSE_STOPWATCH @@ -172,14 +174,14 @@ static wxLongLong wxStartTime = 0l; // starts the global timer void wxStartTimer() { - wxStartTime = wxGetLocalTimeMillis(); + wxStartTime = wxGetUTCTimeMillis(); } // Returns elapsed time in milliseconds long wxGetElapsedTime(bool resetTimer) { wxLongLong oldTime = wxStartTime; - wxLongLong newTime = wxGetLocalTimeMillis(); + wxLongLong newTime = wxGetUTCTimeMillis(); if ( resetTimer ) wxStartTime = newTime; @@ -188,160 +190,3 @@ long wxGetElapsedTime(bool resetTimer) } #endif // wxUSE_LONGLONG - -// ---------------------------------------------------------------------------- -// the functions to get the current time and timezone info -// ---------------------------------------------------------------------------- - -// Get local time as seconds since 00:00:00, Jan 1st 1970 -long wxGetLocalTime() -{ - struct tm tm; - time_t t0, t1; - - // This cannot be made static because mktime can overwrite it. - // - memset(&tm, 0, sizeof(tm)); - tm.tm_year = 70; - tm.tm_mon = 0; - tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature' - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; // let mktime guess - - // Note that mktime assumes that the struct tm contains local time. - // - t1 = time(&t1); // now - t0 = mktime(&tm); // origin - - // Return the difference in seconds. - // - if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 )) - return (long)difftime(t1, t0) + (60 * 60 * 24 * 4); - - wxLogSysError(_("Failed to get the local system time")); - return -1; -} - -// Get UTC time as seconds since 00:00:00, Jan 1st 1970 -long wxGetUTCTime() -{ - return (long)time(NULL); -} - -#if wxUSE_LONGLONG - -// Get local time as milliseconds since 00:00:00, Jan 1st 1970 -wxLongLong wxGetLocalTimeMillis() -{ - wxLongLong val = 1000l; - - // If possible, use a function which avoids conversions from - // broken-up time structures to milliseconds - -#if defined(__WXMSW__) && (defined(__WINE__) || defined(__MWERKS__)) - // This should probably be the way all WXMSW compilers should do it - // Go direct to the OS for time - - SYSTEMTIME thenst = { 1970, 1, 4, 1, 0, 0, 0, 0 }; // 00:00:00 Jan 1st 1970 - FILETIME thenft; - SystemTimeToFileTime( &thenst, &thenft ); - wxLongLong then( thenft.dwHighDateTime, thenft.dwLowDateTime ); // time in 100 nanoseconds - - SYSTEMTIME nowst; - GetLocalTime( &nowst ); - FILETIME nowft; - SystemTimeToFileTime( &nowst, &nowft ); - wxLongLong now( nowft.dwHighDateTime, nowft.dwLowDateTime ); // time in 100 nanoseconds - - return ( now - then ) / 10000.0; // time from 00:00:00 Jan 1st 1970 to now in milliseconds - -#elif defined(HAVE_GETTIMEOFDAY) - struct timeval tp; - if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 ) - { - val *= tp.tv_sec; - return (val + (tp.tv_usec / 1000)); - } - else - { - wxLogError(_("wxGetTimeOfDay failed.")); - return 0; - } -#elif defined(HAVE_FTIME) - struct timeb tp; - - // ftime() is void and not int in some mingw32 headers, so don't - // test the return code (well, it shouldn't fail anyhow...) - (void)ftime(&tp); - val *= tp.time; - return (val + tp.millitm); -#elif defined(__WXMAC__) - - static UInt64 gMilliAtStart = 0; - - Nanoseconds upTime = AbsoluteToNanoseconds( UpTime() ); - - if ( gMilliAtStart == 0 ) - { - time_t start = time(NULL); - gMilliAtStart = ((UInt64) start) * 1000000L; - gMilliAtStart -= upTime.lo / 1000 ; - gMilliAtStart -= ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); - } - - UInt64 millival = gMilliAtStart; - millival += upTime.lo / (1000 * 1000); - millival += ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); - val = millival; - - return val; -#else // no gettimeofday() nor ftime() - // We use wxGetLocalTime() to get the seconds since - // 00:00:00 Jan 1st 1970 and then whatever is available - // to get millisecond resolution. - // - // NOTE that this might lead to a problem if the clocks - // use different sources, so this approach should be - // avoided where possible. - - val *= wxGetLocalTime(); - -// GRG: This will go soon as all WIN32 seem to have ftime -// JACS: unfortunately not. WinCE doesn't have it. -#if defined (__WIN32__) - // If your platform/compiler needs to use two different functions - // to get ms resolution, please do NOT just shut off these warnings, - // drop me a line instead at - - // FIXME -#ifndef __WXWINCE__ - #warning "Possible clock skew bug in wxGetLocalTimeMillis()!" -#endif - - SYSTEMTIME st; - ::GetLocalTime(&st); - val += st.wMilliseconds; -#else // !Win32 - // If your platform/compiler does not support ms resolution please - // do NOT just shut off these warnings, drop me a line instead at - // - - #if defined(__VISUALC__) || defined (__WATCOMC__) - #pragma message("wxStopWatch will be up to second resolution!") - #elif defined(__BORLANDC__) - #pragma message "wxStopWatch will be up to second resolution!" - #else - #warning "wxStopWatch will be up to second resolution!" - #endif // compiler -#endif - - return val; - -#endif // time functions -} - -#endif // wxUSE_LONGLONG - -