From c91d1738709b038fee84d569180cba2bbcbfe5d7 Mon Sep 17 00:00:00 2001 From: thaloun Date: Mon, 16 Nov 2015 16:28:49 -0800 Subject: [PATCH] Revert of Several Tick counter improvements. (patchset #8 id:140001 of https://codereview.webrtc.org/1415923010/ ) Reason for revert: Potentially breaks a threading test under DrMemory. Rolling back while I investigate. Original issue's description: > Several Tick counter improvements. > > Move logic into cc file > Simplify interval calculation > Remove unused QUERY_PERFORMANCE_COUNTER windows implementation > Remove double divide on each ::Now() invocation on mac > > Move TickTime and TickInterval funcitons to cc file in prep for refactoring. > > BUG= > R=mflodman@webrtc.org, pbos@webrtc.org > > Committed: https://crrev.com/4c27e4b62da2047063d88eedfeec3e939fea7843 > Cr-Commit-Position: refs/heads/master@{#10661} TBR=pbos@webrtc.org,mflodman@webrtc.org,noahric@chromium.org,thaloun@google.com NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG= Review URL: https://codereview.webrtc.org/1450203002 Cr-Commit-Position: refs/heads/master@{#10663} --- .../source/process_thread_impl_unittest.cc | 7 +- webrtc/system_wrappers/include/tick_util.h | 114 +++++++++++++++-- webrtc/system_wrappers/source/tick_util.cc | 120 +++++------------- 3 files changed, 143 insertions(+), 98 deletions(-) diff --git a/webrtc/modules/utility/source/process_thread_impl_unittest.cc b/webrtc/modules/utility/source/process_thread_impl_unittest.cc index 92cd561e45..34ed5c5a38 100644 --- a/webrtc/modules/utility/source/process_thread_impl_unittest.cc +++ b/webrtc/modules/utility/source/process_thread_impl_unittest.cc @@ -251,9 +251,8 @@ TEST(ProcessThreadImpl, WakeUp) { rtc::scoped_ptr called(EventWrapper::Create()); MockModule module; - int64_t start_time; - int64_t called_time; - + int64_t start_time = 0; + int64_t called_time = 0; // Ask for a callback after 1000ms. // TimeUntilNextProcess will be called twice. // The first time we use it to get the thread into a waiting state. @@ -282,6 +281,8 @@ TEST(ProcessThreadImpl, WakeUp) { EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1); thread.Stop(); + ASSERT_GT(start_time, 0); + ASSERT_GT(called_time, 0); EXPECT_GE(called_time, start_time); uint32_t diff = called_time - start_time; // We should have been called back much quicker than 1sec. diff --git a/webrtc/system_wrappers/include/tick_util.h b/webrtc/system_wrappers/include/tick_util.h index 6e3b05edb2..f839ff646c 100644 --- a/webrtc/system_wrappers/include/tick_util.h +++ b/webrtc/system_wrappers/include/tick_util.h @@ -56,8 +56,6 @@ class TickTime { static int64_t TicksToMilliseconds(const int64_t ticks); - static int64_t TicksToMicroseconds(const int64_t ticks); - // Returns a TickTime that is ticks later than the passed TickTime. friend TickTime operator+(const TickTime lhs, const int64_t ticks); TickTime& operator+=(const int64_t& ticks); @@ -114,14 +112,6 @@ class TickInterval { int64_t interval_; }; -inline int64_t TickInterval::Milliseconds() const { - return TickTime::TicksToMilliseconds(interval_); -} - -inline int64_t TickInterval::Microseconds() const { - return TickTime::TicksToMicroseconds(interval_); -} - inline TickInterval operator+(const TickInterval& lhs, const TickInterval& rhs) { return TickInterval(lhs.interval_ + rhs.interval_); @@ -173,10 +163,76 @@ inline TickTime TickTime::Now() { return TickTime(QueryOsForTicks()); } +inline int64_t TickTime::MillisecondTimestamp() { + int64_t ticks = TickTime::Now().Ticks(); +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (ticks * 1000) / qpfreq.QuadPart; +#else + return ticks; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + return ticks / 1000000LL; +#else + return ticks / 1000LL; +#endif +} + +inline int64_t TickTime::MicrosecondTimestamp() { + int64_t ticks = TickTime::Now().Ticks(); +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (ticks * 1000) / (qpfreq.QuadPart / 1000); +#else + return ticks * 1000LL; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + return ticks / 1000LL; +#else + return ticks; +#endif +} + inline int64_t TickTime::Ticks() const { return ticks_; } +inline int64_t TickTime::MillisecondsToTicks(const int64_t ms) { +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (qpfreq.QuadPart * ms) / 1000; +#else + return ms; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + return ms * 1000000LL; +#else + return ms * 1000LL; +#endif +} + +inline int64_t TickTime::TicksToMilliseconds(const int64_t ticks) { +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (ticks * 1000) / qpfreq.QuadPart; +#else + return ticks; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + return ticks / 1000000LL; +#else + return ticks / 1000LL; +#endif +} + inline TickTime& TickTime::operator+=(const int64_t& ticks) { ticks_ += ticks; return *this; @@ -189,6 +245,44 @@ inline TickInterval::TickInterval(const int64_t interval) : interval_(interval) { } +inline int64_t TickInterval::Milliseconds() const { +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (interval_ * 1000) / qpfreq.QuadPart; +#else + // interval_ is in ms + return interval_; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + // interval_ is in ns + return interval_ / 1000000; +#else + // interval_ is usecs + return interval_ / 1000; +#endif +} + +inline int64_t TickInterval::Microseconds() const { +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (interval_ * 1000000) / qpfreq.QuadPart; +#else + // interval_ is in ms + return interval_ * 1000LL; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + // interval_ is in ns + return interval_ / 1000; +#else + // interval_ is usecs + return interval_; +#endif +} + inline TickInterval& TickInterval::operator+=(const TickInterval& rhs) { interval_ += rhs.interval_; return *this; diff --git a/webrtc/system_wrappers/source/tick_util.cc b/webrtc/system_wrappers/source/tick_util.cc index cae817dc55..bc8fcfe91b 100644 --- a/webrtc/system_wrappers/source/tick_util.cc +++ b/webrtc/system_wrappers/source/tick_util.cc @@ -17,71 +17,6 @@ namespace webrtc { bool TickTime::use_fake_clock_ = false; int64_t TickTime::fake_ticks_ = 0; -int64_t TickTime::MillisecondTimestamp() { - return TicksToMilliseconds(TickTime::Now().Ticks()); -} - -int64_t TickTime::MicrosecondTimestamp() { - return TicksToMicroseconds(TickTime::Now().Ticks()); -} - -int64_t TickTime::MillisecondsToTicks(const int64_t ms) { -#if _WIN32 - return ms; -#elif defined(WEBRTC_LINUX) - return ms * 1000000LL; -#elif defined(WEBRTC_MAC) - // TODO(pbos): Fix unsafe use of static locals. - static double timebase_from_millisecond_fract = 0.0; - if (timebase_from_millisecond_fract == 0.0) { - mach_timebase_info_data_t timebase; - (void)mach_timebase_info(&timebase); - timebase_from_millisecond_fract = (timebase.denom * 1e6) / timebase.numer; - } - return ms * timebase_from_millisecond_fract; -#else - return ms * 1000LL; -#endif -} - -int64_t TickTime::TicksToMilliseconds(const int64_t ticks) { -#if _WIN32 - return ticks; -#elif defined(WEBRTC_LINUX) - return ticks / 1000000LL; -#elif defined(WEBRTC_MAC) - // TODO(pbos): Fix unsafe use of static locals. - static double timebase_microsecond_fract = 0.0; - if (timebase_microsecond_fract == 0.0) { - mach_timebase_info_data_t timebase; - (void)mach_timebase_info(&timebase); - timebase_microsecond_fract = timebase.numer / (timebase.denom * 1e6); - } - return ticks * timebase_microsecond_fract; -#else - return ticks; -#endif -} - -int64_t TickTime::TicksToMicroseconds(const int64_t ticks) { -#if _WIN32 - return ticks * 1000LL; -#elif defined(WEBRTC_LINUX) - return ticks / 1000LL; -#elif defined(WEBRTC_MAC) - // TODO(pbos): Fix unsafe use of static locals. - static double timebase_microsecond_fract = 0.0; - if (timebase_microsecond_fract == 0.0) { - mach_timebase_info_data_t timebase; - (void)mach_timebase_info(&timebase); - timebase_microsecond_fract = timebase.numer / (timebase.denom * 1e3); - } - return ticks * timebase_microsecond_fract; -#else - return ticks; -#endif -} - void TickTime::UseFakeClock(int64_t start_millisecond) { use_fake_clock_ = true; fake_ticks_ = MillisecondsToTicks(start_millisecond); @@ -92,14 +27,20 @@ void TickTime::AdvanceFakeClock(int64_t milliseconds) { fake_ticks_ += MillisecondsToTicks(milliseconds); } -// Gets the native system tick count. The actual unit, resolution, and epoch -// varies by platform: -// Windows: Milliseconds of uptime with rollover count in the upper 32-bits. -// Linux/Android: Nanoseconds since the Unix epoch. -// Mach (Mac/iOS): "absolute" time since first call. -// Unknown POSIX: Microseconds since the Unix epoch. int64_t TickTime::QueryOsForTicks() { + TickTime result; #if _WIN32 + // TODO(wu): Remove QueryPerformanceCounter implementation. +#ifdef USE_QUERY_PERFORMANCE_COUNTER + // QueryPerformanceCounter returns the value from the TSC which is + // incremented at the CPU frequency. The algorithm used requires + // the CPU frequency to be constant. Technology like speed stepping + // which has variable CPU frequency will therefore yield unpredictable, + // incorrect time estimations. + LARGE_INTEGER qpcnt; + QueryPerformanceCounter(&qpcnt); + result.ticks_ = qpcnt.QuadPart; +#else static volatile LONG last_time_get_time = 0; static volatile int64_t num_wrap_time_get_time = 0; volatile LONG* last_time_get_time_ptr = &last_time_get_time; @@ -112,11 +53,11 @@ int64_t TickTime::QueryOsForTicks() { // 0x0fffffff ~3.1 days, the code will not take that long to execute // so it must have been a wrap around. if (old > 0xf0000000 && now < 0x0fffffff) { - // TODO(pbos): Fix unsafe use of static locals. num_wrap_time_get_time++; } } - return now + (num_wrap_time_get_time << 32); + result.ticks_ = now + (num_wrap_time_get_time << 32); +#endif #elif defined(WEBRTC_LINUX) struct timespec ts; // TODO(wu): Remove CLOCK_REALTIME implementation. @@ -125,24 +66,33 @@ int64_t TickTime::QueryOsForTicks() { #else clock_gettime(CLOCK_MONOTONIC, &ts); #endif - return 1000000000LL * ts.tv_sec + ts.tv_nsec; + result.ticks_ = 1000000000LL * static_cast(ts.tv_sec) + + static_cast(ts.tv_nsec); #elif defined(WEBRTC_MAC) - // Return absolute time as an offset from the first call to this function, so - // that we can do floating-point (double) operations on it without losing - // precision. This holds true until the elapsed time is ~11 days, - // at which point we'll start to lose some precision, though not enough to - // matter for millisecond accuracy for another couple years after that. - // TODO(pbos): Fix unsafe use of static locals. - static uint64_t timebase_start = 0; - if (timebase_start == 0) { - timebase_start = mach_absolute_time(); + static mach_timebase_info_data_t timebase; + if (timebase.denom == 0) { + // Get the timebase if this is the first time we run. + // Recommended by Apple's QA1398. + kern_return_t retval = mach_timebase_info(&timebase); + if (retval != KERN_SUCCESS) { + // TODO(wu): Implement RTC_CHECK for all the platforms. Then replace this + // with a RTC_CHECK_EQ(retval, KERN_SUCCESS); +#ifndef WEBRTC_IOS + asm("int3"); +#else + __builtin_trap(); +#endif // WEBRTC_IOS + } } - return mach_absolute_time() - timebase_start; + // Use timebase to convert absolute time tick units into nanoseconds. + result.ticks_ = mach_absolute_time() * timebase.numer / timebase.denom; #else struct timeval tv; gettimeofday(&tv, NULL); - return 1000000LL * tv.tv_sec + tv.tv_usec; + result.ticks_ = 1000000LL * static_cast(tv.tv_sec) + + static_cast(tv.tv_usec); #endif + return result.ticks_; } } // namespace webrtc